Commit 2f6f011a authored by qinsoon's avatar qinsoon Committed by Isaac Oscar Gariano

changed tree generation heuristics

parent fd1833ef
......@@ -441,6 +441,15 @@ impl MuType {
}
}
/// gets the function signature for FuncRef or UFuncPtr, return None if the type is not
/// those two types
pub fn get_func_sig(&self) -> Option<P<MuFuncSig>> {
match self.v {
MuType_::FuncRef(ref sig) | MuType_::UFuncPtr(ref sig) => Some(sig.clone()),
_ => None
}
}
/// gets the length (in bit) of a integer/pointer type (assume pointer types are always 64 bits)
// FIXME: should deprecate this function, and get the length from BackendType
pub fn get_int_length(&self) -> Option<usize> {
......
......@@ -1832,10 +1832,7 @@ impl ASMCodeGen {
/// emits an instruction (use 1 reg 1 mem, define the reg)
fn internal_binop_def_r_mem(&mut self, inst: &str, dest: &P<Value>, src: &P<Value>) {
let len = match dest.ty.get_int_length() {
Some(n) if n == 64 | 32 | 16 | 8 => n,
_ => panic!("unimplemented int types: {}", dest.ty)
};
let len = check_op_len(dest);
let inst = inst.to_string() + &op_postfix(len);
trace!("emit: {} {}, {} -> {}", inst, src, dest, dest);
......@@ -2256,10 +2253,26 @@ impl ASMCodeGen {
)
}
/// emits an instruction (use 2 fpregs, define 1st fpreg)
fn internal_fp_binop_def_r_mem(&mut self, inst: &str, dest: Reg, src: Reg) {
/// emits an instruction (use 1 fpreg 1 memory operand, define the fpreg)
fn internal_fp_binop_def_r_mem(&mut self, inst: &str, dest: Reg, src: Mem) {
trace!("emit: {} {}, {} -> {}", inst, src, dest, dest);
unimplemented!()
let (mem, mut uses) = self.prepare_mem(src, inst.len() + 1);
let (reg, id, loc) = self.prepare_fpreg(dest, inst.len() + 1 + mem.len() + 1);
// uses are GPRs, it won't include FPRs - we can simply insert into the map
uses.insert(id, vec![loc.clone()]);
let asm = format!("{} {},{}", inst, mem, reg);
self.add_asm_inst(
asm,
linked_hashmap!{
id => vec![loc]
},
uses,
true
)
}
/// emits a move instruction (reg -> fpreg)
......
......@@ -931,7 +931,7 @@ impl<'a> InstructionSelection {
let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
} else if self.match_mem(op) {
let mem_op = self.emit_mem(op, f_context, vm);
let mem_op = self.emit_mem(op, f_content, f_context, vm);
self.backend.emit_lea_r64(&tmp_res, &mem_op);
} else {
panic!("unexpected op (expect ireg): {}", op)
......@@ -2475,7 +2475,7 @@ impl<'a> InstructionSelection {
trace!("emit add-ireg-mem");
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let reg_op2 = self.emit_mem(op2, f_context, vm);
let reg_op2 = self.emit_mem(op2, f_content, f_context, vm);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
......@@ -2537,7 +2537,7 @@ impl<'a> InstructionSelection {
trace!("emit sub-ireg-mem");
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
......@@ -2599,7 +2599,7 @@ impl<'a> InstructionSelection {
trace!("emit and-ireg-mem");
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
......@@ -2662,7 +2662,7 @@ impl<'a> InstructionSelection {
trace!("emit or-ireg-mem");
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
......@@ -2718,7 +2718,7 @@ impl<'a> InstructionSelection {
trace!("emit xor-ireg-mem");
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
......@@ -3256,7 +3256,7 @@ impl<'a> InstructionSelection {
trace!("emit add-fpreg-mem");
let reg_op1 = self.emit_fpreg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
match reg_op1.ty.v {
MuType_::Double => {
......@@ -3308,7 +3308,7 @@ impl<'a> InstructionSelection {
trace!("emit sub-fpreg-mem");
let reg_op1 = self.emit_fpreg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
match reg_op1.ty.v {
MuType_::Double => {
......@@ -3359,7 +3359,7 @@ impl<'a> InstructionSelection {
trace!("emit mul-fpreg-mem");
let reg_op1 = self.emit_fpreg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
match reg_op1.ty.v {
MuType_::Double => {
......@@ -3407,7 +3407,7 @@ impl<'a> InstructionSelection {
trace!("emit div-fpreg-mem");
let reg_op1 = self.emit_fpreg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
match reg_op1.ty.v {
MuType_::Double => {
......@@ -3837,7 +3837,7 @@ impl<'a> InstructionSelection {
// div op2
if self.match_mem(op2) {
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
self.backend.emit_div_mem(&mem_op2);
} else if self.match_iimm(op2) {
let imm = self.node_iimm_to_i32(op2);
......@@ -3903,7 +3903,7 @@ impl<'a> InstructionSelection {
// idiv op2
if self.match_mem(op2) {
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
self.backend.emit_idiv_mem(&mem_op2);
} else if self.match_iimm(op2) {
let imm = self.node_iimm_to_i32(op2);
......@@ -4441,16 +4441,10 @@ impl<'a> InstructionSelection {
let ref ops = inst.ops;
let ref func = ops[calldata.func];
let ref func_sig = match func.v {
TreeNode_::Value(ref pv) => {
let ty: &MuType = &pv.ty;
match ty.v {
MuType_::FuncRef(ref sig) | MuType_::UFuncPtr(ref sig) => sig,
_ => panic!("expected funcref/ptr type")
}
}
_ => {
// emit a funcref from an instruction
unimplemented!()
TreeNode_::Value(ref pv) => pv.ty.get_func_sig().unwrap(),
TreeNode_::Instruction(ref inst) => {
let ref funcref_val = inst.value.as_ref().unwrap()[0];
funcref_val.ty.get_func_sig().unwrap()
}
};
......@@ -4516,7 +4510,7 @@ impl<'a> InstructionSelection {
x86_64::ALL_CALLER_SAVED_REGS.to_vec()
)
} else if self.match_mem(func) {
let target = self.emit_mem(func, f_context, vm);
let target = self.emit_mem(func, f_content, f_context, vm);
let callsite = self.new_callsite_label(Some(node));
self.backend.emit_call_near_mem64(
......@@ -5108,13 +5102,13 @@ impl<'a> InstructionSelection {
return op;
} else if self.match_ireg(op1) && self.match_mem(op2) {
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_context, vm);
let mem_op2 = self.emit_mem(op2, f_content, f_context, vm);
self.backend.emit_cmp_mem_r(&mem_op2, &reg_op1);
return op;
} else if self.match_mem(op1) && self.match_ireg(op2) {
let mem_op1 = self.emit_mem(op1, f_context, vm);
let mem_op1 = self.emit_mem(op1, f_content, f_context, vm);
let reg_op2 = self.emit_ireg(op2, f_content, f_context, vm);
self.backend.emit_cmp_r_mem(&mem_op1, &reg_op2);
......@@ -6133,19 +6127,16 @@ impl<'a> InstructionSelection {
}
}
_ => {
let tmp_loc = self.emit_ireg(op, f_content, f_context, vm);
let ret = MemoryLocation::Address {
base: tmp_loc,
offset: None,
index: None,
scale: None
};
trace!("MEM from general ireg inst: {}", op);
ret
Instruction_::Load { mem_loc, .. } => {
trace!("MEM from LOAD");
self.emit_inst_addr_to_value_inner(
&inst.ops[mem_loc],
f_content,
f_context,
vm
)
}
_ => panic!("MEM from general ireg inst: {}", op)
}
}
_ => {
......@@ -6269,7 +6260,13 @@ impl<'a> InstructionSelection {
/// emits code for a memory location pattern
#[allow(unused_variables)]
fn emit_mem(&mut self, op: &TreeNode, f_context: &mut FunctionContext, vm: &VM) -> P<Value> {
fn emit_mem(
&mut self,
op: &TreeNode,
f_content: &FunctionContent,
f_context: &mut FunctionContext,
vm: &VM
) -> P<Value> {
match op.v {
TreeNode_::Value(ref pv) => {
match pv.v {
......@@ -6280,7 +6277,7 @@ impl<'a> InstructionSelection {
_ => unimplemented!()
}
}
TreeNode_::Instruction(_) => unimplemented!()
TreeNode_::Instruction(_) => self.emit_node_addr_to_value(op, f_content, f_context, vm)
}
}
......
......@@ -33,9 +33,78 @@ impl TreeGen {
}
fn is_movable(inst: &Instruction) -> bool {
!inst.has_side_effect()
is_suitable_child(inst)
}
/// is this instruction suitable to be tree child (we may find pattern for it)?
fn is_suitable_child(inst: &Instruction) -> bool {
use ast::inst::Instruction_::*;
match inst.v {
Return(_) |
ThreadExit |
Throw(_) |
TailCall(_) |
Branch1(_) |
Branch2 { .. } |
Watchpoint { .. } |
WPBranch { .. } |
Call { .. } |
CCall { .. } |
SwapStackExc { .. } |
SwapStackKill { .. } |
Switch { .. } |
ExnInstruction { .. } |
PrintHex(_) |
SetRetval(_) |
KillStack(_) |
CurrentStack |
SwapStackExpr { .. } |
CommonInst_Tr64IsFp(_) |
CommonInst_Tr64IsInt(_) |
CommonInst_Tr64IsRef(_) |
CommonInst_Tr64FromFp(_) |
CommonInst_Tr64FromInt(_) |
CommonInst_Tr64FromRef(_, _) |
CommonInst_Tr64ToFp(_) |
CommonInst_Tr64ToInt(_) |
CommonInst_Tr64ToRef(_) |
CommonInst_Tr64ToTag(_) |
ExprCall { .. } |
ExprCCall { .. } |
New(_) |
AllocA(_) |
NewHybrid(_, _) |
AllocAHybrid(_, _) |
NewStack(_) |
NewThread { .. } |
NewFrameCursor(_) |
Select { .. } |
Fence(_) |
CommonInst_SetThreadLocal(_) |
CommonInst_Pin(_) |
CommonInst_Unpin(_) |
CommonInst_GetAddr(_) |
CmpXchg { .. } |
AtomicRMW { .. } |
Store { .. } => false,
BinOp(_, _, _) |
BinOpWithStatus(_, _, _, _) |
CmpOp(_, _, _) |
ConvOp { .. } |
Load { .. } |
GetIRef(_) |
GetFieldIRef { .. } |
GetElementIRef { .. } |
ShiftIRef { .. } |
GetVarPartIRef { .. } |
CommonInst_GetThreadLocal |
Move(_) => true
}
}
impl CompilerPass for TreeGen {
fn name(&self) -> &'static str {
self.name
......@@ -51,8 +120,8 @@ impl CompilerPass for TreeGen {
// then we replace the use of the SSA with the actual variable
// we are doing it in two steps
// 1. if we see an expression that generates an SSA which is used only once, we take out
// the expression node
// 1. if we see an expression that generates an SSA which is used only once and used
// in its next instruction, we take out the expression node
// 2. if we see an SSA that is used only once (and it is this place for sure), we replace it
// with the expression node
// because of SSA form, it is guaranteed to see 1 before 2 for SSA variables.
......@@ -71,7 +140,8 @@ impl CompilerPass for TreeGen {
trace!("check block {}", label);
trace!("");
for mut node in body.into_iter() {
for i in 0..body.len() {
let mut node = body[i].clone();
trace!("check inst: {}", node);
match &mut node.v {
&mut TreeNode_::Instruction(ref mut inst) => {
......@@ -105,6 +175,7 @@ impl CompilerPass for TreeGen {
// * it generates only one value
// * the value is used only once
// * the instruction is movable
// * the value is used in the next instruction
trace!("check if we should fold the inst");
if inst.value.is_some() {
let left = inst.value.as_ref().unwrap();
......@@ -112,11 +183,23 @@ impl CompilerPass for TreeGen {
// if left is _one_ variable that is used once
// we can put the expression as a child node to its use
if left.len() == 1 {
let ref val_lhs = left[0];
let lhs = context
.get_value_mut(left[0].extract_ssa_id().unwrap())
.unwrap();
if lhs.use_count() == 1 {
if is_movable(&inst) {
let next_inst_uses_lhs = {
if i != body.len() - 1 {
let ref next_inst = body[i + 1].as_inst_ref();
next_inst
.ops
.iter()
.any(|x| x.as_value() == val_lhs)
} else {
false
}
};
if is_movable(&inst) && next_inst_uses_lhs {
// FIXME: should be able to move the inst here
lhs.assign_expr(inst.clone());
......@@ -124,7 +207,7 @@ impl CompilerPass for TreeGen {
trace!("");
continue;
} else {
trace!("no, not movable");
trace!("no, not movable or not used by next inst");
}
} else {
trace!("no, use count more than 1");
......
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