Commit 5bfc39a4 authored by qinsoon's avatar qinsoon

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