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

Commit 9d2cc163 authored by qinsoon's avatar qinsoon
Browse files

[wip] working on instruction selection on factorial func

parent 66a09287
use ast::ptr::P;
use ast::types::*;
use ast::inst::*;
use ast::op::*;
use common::vector_as_str;
use std::collections::HashMap;
......@@ -38,6 +39,7 @@ impl MuFunction {
self.context.values.insert(id, ValueEntry{id: id, tag: tag, ty: ty.clone(), use_count: Cell::new(0), expr: None});
P(TreeNode {
op: pick_op_code_for_ssa(&ty),
v: TreeNode_::Value(P(Value{
tag: tag,
ty: ty,
......@@ -46,18 +48,9 @@ impl MuFunction {
})
}
pub fn new_constant(&mut self, tag: MuTag, ty: P<MuType>, v: Constant) -> P<TreeNode> {
P(TreeNode{
v: TreeNode_::Value(P(Value{
tag: tag,
ty: ty,
v: Value_::Constant(v)
}))
})
}
pub fn new_value(&mut self, v: P<Value>) -> P<TreeNode> {
pub fn new_constant(&mut self, v: P<Value>) -> P<TreeNode> {
P(TreeNode{
op: pick_op_code_for_const(&v.ty),
v: TreeNode_::Value(v)
})
}
......@@ -197,13 +190,13 @@ pub struct BlockContent {
#[derive(Debug, Clone)]
/// always use with P<TreeNode>
pub struct TreeNode {
// pub op: OpCode,
pub v: TreeNode_
pub op: OpCode,
pub v: TreeNode_,
}
impl TreeNode {
pub fn new_inst(v: Instruction) -> P<TreeNode> {
P(TreeNode{v: TreeNode_::Instruction(v)})
P(TreeNode{op: pick_op_code_for_inst(&v), v: TreeNode_::Instruction(v)})
}
pub fn extract_ssa_id(&self) -> Option<MuID> {
......
use ast::ptr::P;
use ast::types::*;
use ast::inst::*;
#[derive(Copy, Clone, Debug)]
pub enum OpCode {
// SSA
......@@ -27,13 +31,14 @@ pub enum OpCode {
ExnInstruction,
// expression
BinOp,
CmpOp,
Binary(BinOp),
Comparison(CmpOp),
AtomicRMW(AtomicRMWOp),
ExprCall,
Load,
Store,
CmpXchg,
AtomicRMWOp,
New,
AllocA,
NewHybrid,
......@@ -49,6 +54,64 @@ pub enum OpCode {
GetVarPartIRef
}
pub fn pick_op_code_for_ssa(ty: &P<MuType>) -> OpCode {
use ast::types::MuType_::*;
let a : &MuType_ = ty;
match a {
// currently use i64 for all ints
&Int(_) => OpCode::RegI64,
// currently do not differentiate float and double
&Float
| &Double => OpCode::RegFP,
// ref and pointer types use RegI64
&Ref(_)
| &IRef(_)
| &WeakRef(_)
| &UPtr(_)
| &ThreadRef
| &StackRef
| &Tagref64
| &FuncRef(_)
| &UFuncPtr(_) => OpCode::RegI64,
// we are not supposed to have these as SSA
&Struct(_)
| &Array(_, _)
| &Hybrid(_, _)
| &Void => panic!("Not expecting {} as SSA", ty),
// unimplemented
&Vector(_, _) => unimplemented!()
}
}
pub fn pick_op_code_for_const(ty: &P<MuType>) -> OpCode {
use ast::types::MuType_::*;
let a : &MuType_ = ty;
match a {
// currently use i64 for all ints
&Int(_) => OpCode::IntImmI64,
// currently do not differentiate float and double
&Float
| &Double => OpCode::FPImm,
// ref and pointer types use RegI64
&Ref(_)
| &IRef(_)
| &WeakRef(_)
| &UPtr(_)
| &ThreadRef
| &StackRef
| &Tagref64
| &FuncRef(_)
| &UFuncPtr(_) => OpCode::IntImmI64,
// we are not supposed to have these as SSA
&Struct(_)
| &Array(_, _)
| &Hybrid(_, _)
| &Void => unimplemented!(),
// unimplemented
&Vector(_, _) => unimplemented!()
}
}
#[derive(Copy, Clone, Debug)]
pub enum BinOp {
// Int(n) BinOp Int(n) -> Int(n)
......@@ -65,10 +128,10 @@ pub enum BinOp {
// Int(n) BinOp Int(m) -> Int(n)
Shl,
Lshr,
AsHR,
Ashr,
// FP BinOp FP -> FP
Fadd,
FAdd,
FSub,
FMul,
FDiv,
......@@ -122,3 +185,41 @@ pub enum AtomicRMWOp {
UMAX,
UMIN
}
pub fn pick_op_code_for_inst(inst: &Instruction) -> OpCode {
match inst.v {
Instruction_::BinOp(op, _, _) => OpCode::Binary(op),
Instruction_::CmpOp(op, _, _) => OpCode::Comparison(op),
Instruction_::AtomicRMW{op, ..} => OpCode::AtomicRMW(op),
Instruction_::ExprCall{..} => OpCode::ExprCall,
Instruction_::Load{..} => OpCode::Load,
Instruction_::Store{..} => OpCode::Store,
Instruction_::CmpXchg{..} => OpCode::CmpXchg,
Instruction_::New(_) => OpCode::New,
Instruction_::AllocA(_) => OpCode::AllocA,
Instruction_::NewHybrid(_, _) => OpCode::NewHybrid,
Instruction_::AllocAHybrid(_, _) => OpCode::AllocAHybrid,
Instruction_::NewStack(_) => OpCode::NewStack,
Instruction_::NewThread(_, _) => OpCode::NewThread,
Instruction_::NewThreadExn(_, _) => OpCode::NewThreadExn,
Instruction_::NewFrameCursor(_) => OpCode::NewFrameCursor,
Instruction_::GetIRef(_) => OpCode::GetIRef,
Instruction_::GetFieldIRef{..} => OpCode::GetFieldIRef,
Instruction_::GetElementIRef{..} => OpCode::GetElementIRef,
Instruction_::ShiftIRef{..} => OpCode::ShiftIRef,
Instruction_::GetVarPartIRef{..} => OpCode::GetVarPartIRef,
Instruction_::Fence(_) => OpCode::Fence,
Instruction_::Return(_) => OpCode::Return,
Instruction_::ThreadExit => OpCode::ThreadExit,
Instruction_::Throw(_) => OpCode::Throw,
Instruction_::TailCall(_) => OpCode::TailCall,
Instruction_::Branch1(_) => OpCode::Branch1,
Instruction_::Branch2{..} => OpCode::Branch2,
Instruction_::Watchpoint{..} => OpCode::Watchpoint,
Instruction_::WPBranch{..} => OpCode::WPBranch,
Instruction_::Call{..} => OpCode::Call,
Instruction_::SwapStack{..} => OpCode::SwapStack,
Instruction_::Switch{..} => OpCode::Switch,
Instruction_::ExnInstruction{..} => OpCode::ExnInstruction
}
}
use ast::ir::*;
use ast::ptr::*;
use ast::inst::Destination;
use ast::inst::DestArg;
use ast::inst::Instruction_::*;
use ast::op;
use ast::op::OpCode;
use vm::context::VMContext;
use compiler::CompilerPass;
......@@ -25,6 +29,7 @@ impl CompilerPass for InstructionSelection {
debug!("{}", self.name());
}
#[allow(unused_variables)]
fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
for block_label in func.block_trace.as_ref().unwrap() {
let block = func.content.as_mut().unwrap().get_block_mut(block_label);
......@@ -38,33 +43,186 @@ impl CompilerPass for InstructionSelection {
}
}
#[allow(unused_variables)]
fn instruction_select(inst: &mut P<TreeNode>) {
trace!("instsel on node {}", inst);
match inst.v {
TreeNode_::Instruction(ref inst) => {
match inst.v {
Branch2{cond, ref true_dest, ref false_dest, true_prob} => {
let ref cond = inst.ops.borrow()[cond];
let (fallthrough_dest, branch_dest) = {
if true_prob > 0.5f32 {
(true_dest, false_dest)
} else {
(false_dest, true_dest)
}
};
let mut ops = inst.ops.borrow_mut();
process_dest(&mut ops, fallthrough_dest);
process_dest(&mut ops, branch_dest);
let ref mut cond = ops[cond];
match cond.op {
OpCode::Comparison(op) => {
trace!("Tile comp-branch2");
match cond.v {
TreeNode_::Instruction(ref inst) => {
match inst.v {
CmpOp(op, op1, op2) => {
// cmp op1 op2
// jcc branch_dest
// #fallthrough_dest:
// ..
},
_ => panic!("expected a comparison op")
}
},
_ => panic!("expected a comparison inst")
}
},
OpCode::RegI64 | OpCode::IntImmI64 => {
trace!("Tile value-branch2");
// test/cmp pv 0
// jcc branch_dest
// #fallthrough_dest:
// ...
},
_ => {
trace!("nested: compute cond");
// instsel for cond first
instruction_select(cond);
// test/cmp res 0
// jcc branch_dest
// #fallthrough_dest:
// ...
trace!("Tile value-branch2 after computing cond")
}
}
},
Branch1(ref dest) => {
let mut ops = inst.ops.borrow_mut();
process_dest(&mut ops, dest);
trace!("Tile branch1");
// jmp
},
ExprCall{ref data, is_abort} => {
trace!("Tile exprcall");
let mut ops = inst.ops.borrow_mut();
for arg_index in data.args.iter() {
let ref mut arg = ops[*arg_index];
trace!("arg {}", arg);
match arg.op {
OpCode::RegI64 | OpCode::IntImmI64 => {
trace!("Tile move-gpr-arg");
// move to register
},
OpCode::RegFP | OpCode::FPImm => {
trace!("Tile move-fpr-arg");
// move to fp register
},
_ => {
trace!("nested: compute arg");
// instself for arg first
instruction_select(arg);
_ => panic!("unexpected inst as child node of branch2: {}", cond)
// mov based on type
trace!("Tile move-arg after computing arg");
}
}
}
},
TreeNode_::Value(ref pv) => {
Return(ref vals) => {
let mut ops = inst.ops.borrow_mut();
for val_index in vals.iter() {
let ref mut val = ops[*val_index];
trace!("return val: {}", val);
match val.op {
OpCode::RegI64 | OpCode::IntImmI64 => {
trace!("Tile move-gpr-ret");
// move to return register
}
OpCode::RegFP | OpCode::FPImm => {
trace!("Tile move-fpr-ret");
// move to return fp register
}
_ => {
trace!("nested: compute return val");
// instsel for return val first
instruction_select(val);
// move based on type
trace!("Tile move-ret-val after computing arg");
}
}
}
},
BinOp(op, op1, op2) => {
match op {
op::BinOp::Add => {
trace!("Tile add");
// mov op1, res
// add op2 res
},
op::BinOp::Sub => {
trace!("Tile sub")
// mov op1, res
// sub op1, res
},
op::BinOp::Mul => {
trace!("Tile mul")
// mov op1 rax
// mul op2 rax
// mov rax res
},
_ => unimplemented!()
}
}
_ => unimplemented!()
} // main switch
},
_ => panic!("expected instruction")
}
}
#[allow(unused_variables)]
fn process_dest(ops: &mut Vec<P<TreeNode>>, dest: &Destination) {
for dest_arg in dest.args.iter() {
match dest_arg {
&DestArg::Normal(op_index) => {
let ref mut arg = ops[op_index];
match arg.op {
OpCode::RegI64
| OpCode::RegFP
| OpCode::IntImmI64
| OpCode::FPImm => {
// do nothing
},
_ => {
trace!("nested: compute arg for branch");
// nested: compute arg
instruction_select(arg);
}
}
},
&DestArg::Freshbound(_) => unimplemented!()
}
}
}
\ No newline at end of file
......@@ -32,6 +32,7 @@ impl CompilerPolicy {
passes.push(Box::new(passes::DefUse::new()));
passes.push(Box::new(passes::TreeGen::new()));
passes.push(Box::new(passes::ControlFlowAnalysis::new()));
passes.push(Box::new(passes::TraceGen::new()));
passes.push(Box::new(backend::inst_sel::InstructionSelection::new()));
CompilerPolicy{passes: passes}
......
......@@ -43,8 +43,8 @@ pub fn sum() -> VMContext {
// %entry(<@int_64> %n):
let mut blk_entry = Block::new("entry");
let blk_entry_n = func.new_ssa(0, "blk_entry_n", type_def_int64.clone());
let const_def_int64_0_local = func.new_value(const_def_int64_0.clone()); // FIXME: why we need a local version?
let const_def_int64_1_local = func.new_value(const_def_int64_1.clone());
let const_def_int64_0_local = func.new_constant(const_def_int64_0.clone()); // FIXME: why we need a local version?
let const_def_int64_1_local = func.new_constant(const_def_int64_1.clone());
// BRANCH %head
let blk_entry_term = TreeNode::new_inst(Instruction {
......@@ -184,7 +184,7 @@ pub fn factorial() -> VMContext {
// %blk_0(<@int_64> %n_3):
let mut blk_0 = Block::new("blk_0");
let blk_0_n_3 = func.new_ssa(0, "blk_0_n_3", type_def_int64.clone());
let const_def_int64_1_local = func.new_value(const_def_int64_1.clone());
let const_def_int64_1_local = func.new_constant(const_def_int64_1.clone());
// %v48 = EQ <@int_64> %n_3 @int_64_1
let blk_0_v48 = func.new_ssa(1, "blk_0_v48", type_def_int64.clone());
......
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