GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

Commit 649effb9 authored by qinsoon's avatar qinsoon

changed tree generation heuristics

parent 69f7c5de
Pipeline #1231 failed with stages
in 22 minutes and 53 seconds
......@@ -433,6 +433,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(
......@@ -5110,13 +5104,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);
......@@ -6135,19 +6129,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)
}
}
_ => {
......@@ -6271,7 +6262,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 {
......@@ -6282,7 +6279,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