WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.2% of users enabled 2FA.

Commit 5bfc39a4 authored by qinsoon's avatar qinsoon
Browse files

match patterns for mul/div by a constant that is a power of 2

emit shift instead of mul/div
parent 45372bf4
......@@ -71,6 +71,12 @@ testmuc:test_cmp:
- *build_muc
- LD_LIBRARY_PATH=mu-tool-compiler/lib/ MUC=mu-tool-compiler/muc python2 -m pytest test_cmp.py -v
testmuc:test_binop:
stage: test
script:
- *build_muc
- LD_LIBRARY_PATH=mu-tool-compiler/lib/ MUC=mu-tool-compiler/muc python2 -m pytest test_binop.py -v
testjit:milestones:
stage: test
script:
......
......@@ -2765,6 +2765,13 @@ impl<'a> InstructionSelection {
// MUL with one is the original value
trace!("emit mul-ireg-1");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg(op1) && self.match_iconst_p2(op2) {
// MUL with a constant that is a power of 2 can be done with shl
trace!("emit mul-ireg-p2");
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let shift = self.node_iconst_to_p2(op2);
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
self.backend.emit_shl_r_imm8(&res_tmp, shift as i8);
} else if self.match_ireg_ex(op1) && self.match_iconst_zero(op2) {
// MUL with zero is zero
trace!("emit mul-iregex-0");
......@@ -2875,16 +2882,25 @@ impl<'a> InstructionSelection {
match op_size {
1 | 2 | 4 | 8 => {
self.emit_udiv(op1, op2, f_content, f_context, vm);
if self.match_iconst_p2(op2) {
// we can simply logic shift right
let shift = self.node_iconst_to_p2(op2);
// mov rax -> result
let res_size = vm.get_backend_type_size(res_tmp.ty.id());
match res_size {
8 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::RAX),
4 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::EAX),
2 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::AX),
1 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::AL),
_ => panic!("unexpected res for node {:?}", node)
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
self.backend.emit_shr_r_imm8(&res_tmp, shift as i8);
} else {
self.emit_udiv(op1, op2, f_content, f_context, vm);
// mov rax -> result
let res_size = vm.get_backend_type_size(res_tmp.ty.id());
match res_size {
8 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::RAX),
4 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::EAX),
2 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::AX),
1 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::AL),
_ => panic!("unexpected res for node {:?}", node)
}
}
}
16 => {
......@@ -2913,16 +2929,25 @@ impl<'a> InstructionSelection {
match op_size {
1 | 2 | 4 | 8 => {
self.emit_idiv(op1, op2, f_content, f_context, vm);
if self.match_iconst_p2(op2) {
// we can simply arithmetic shift right
let shift = self.node_iconst_to_p2(op2);
// mov rax -> result
let res_size = vm.get_backend_type_size(res_tmp.ty.id());
match res_size {
8 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::RAX),
4 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::EAX),
2 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::AX),
1 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::AL),
_ => panic!("unexpected res for node {:?}", node)
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
self.backend.emit_sar_r_imm8(&res_tmp, shift as i8);
} else {
self.emit_idiv(op1, op2, f_content, f_context, vm);
// mov rax -> result
let res_size = vm.get_backend_type_size(res_tmp.ty.id());
match res_size {
8 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::RAX),
4 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::EAX),
2 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::AX),
1 => self.backend.emit_mov_r_r(&res_tmp, &x86_64::AL),
_ => panic!("unexpected res for node {:?}", node)
}
}
}
16 => {
......@@ -5569,6 +5594,33 @@ impl<'a> InstructionSelection {
}
}
/// matches an integer that is power of 2
fn match_iconst_p2(&mut self, op: &TreeNode) -> bool {
match op.v {
TreeNode_::Value(ref pv) if pv.is_const() => {
if pv.is_int_const() {
math::is_power_of_two(pv.extract_int_const().unwrap() as usize).is_some()
} else {
false
}
}
_ => false
}
}
fn node_iconst_to_p2(&mut self, op: &TreeNode) -> u8 {
match op.v {
TreeNode_::Value(ref pv) if pv.is_const() => {
if pv.is_int_const() {
math::is_power_of_two(pv.extract_int_const().unwrap() as usize).unwrap()
} else {
unreachable!()
}
}
_ => unreachable!()
}
}
/// matches a floatingpoint zero
fn match_fconst_zero(&mut self, op: &TreeNode) -> bool {
match op.v {
......
......@@ -21,7 +21,7 @@ use utils::math::align_up;
use utils::bit_utils::bits_ones;
use std;
pub static mut VALIDATE_IR: bool = false;
pub static mut VALIDATE_IR: bool = true;
macro_rules! assert_ir {
($ cond : expr ) => [{if unsafe{VALIDATE_IR} {assert!($cond)} }];
......
# Copyright 2017 The Australian National University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from util import execute, compile_bundle, load_bundle, get_function;
import pytest;
import ctypes;
def test_div():
lib = load_bundle(
"""
.funcdef div<(int<64> int<64>) -> (int<64>)>
{
entry(<int<64>> x <int<64>> y):
res = UDIV <int<64>> x y
RET res
}
""", "div"
)
div = get_function(lib.div, [ctypes.c_uint64], ctypes.c_uint64)
assert(div(6, 2) == 3)
def test_div2():
lib = load_bundle(
"""
.funcdef div2<(int<64>) -> (int<64>)>
{
entry(<int<64>> x):
res = UDIV <int<64>> x <int<64>> 2
RET res
}
""", "div2"
)
div2 = get_function(lib.div2, [ctypes.c_uint64], ctypes.c_uint64)
assert(div2(6) == 3)
def test_sdiv():
lib = load_bundle(
"""
.funcdef sdiv<(int<64> int<64>) -> (int<64>)>
{
entry(<int<64>> x <int<64>> y):
res = SDIV <int<64>> x y
RET res
}
""", "sdiv"
)
sdiv = get_function(lib.sdiv, [ctypes.c_int64], ctypes.c_int64)
assert(sdiv(ctypes.c_int64(6), ctypes.c_int64(2)) == 3)
assert(sdiv(ctypes.c_int64(-6), ctypes.c_int64(2)) == -3)
assert(sdiv(ctypes.c_int64(6), ctypes.c_int64(-2)) == -3)
assert(sdiv(ctypes.c_int64(-6), ctypes.c_int64(-2)) == 3)
def test_sdiv2():
lib = load_bundle(
"""
.funcdef sdiv2<(int<64>) -> (int<64>)>
{
entry(<int<64>> x):
res = SDIV <int<64>> x <int<64>> 2
RET res
}
""", "sdiv2"
)
sdiv2 = get_function(lib.sdiv2, [ctypes.c_int64], ctypes.c_int64)
assert(sdiv2(ctypes.c_int64(6)) == 3)
assert(sdiv2(ctypes.c_int64(-6)) == -3)
def test_mul():
lib = load_bundle(
"""
.funcdef mul<(int<64> int<64>) -> (int<64>)>
{
entry(<int<64>> x <int<64>> y):
res = MUL <int<64>> x y
RET res
}
""", "mul"
)
mul = get_function(lib.mul, [ctypes.c_int64, ctypes.c_int64], ctypes.c_int64)
assert(mul(3, 2) == 6)
assert(mul(-3, 2) == -6)
assert(mul(-3, -2) == 6)
def test_mul2():
lib = load_bundle(
"""
.funcdef mul2<(int<64>) -> (int<64>)>
{
entry(<int<64>> x):
res = MUL <int<64>> x <int<64>> 2
RET res
}
""", "mul2"
)
mul2 = get_function(lib.mul2, [ctypes.c_int64], ctypes.c_int64)
assert(mul2(3) == 6)
assert(mul2(-3) == -6)
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment