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::ptr::P;
use ast::types::*; use ast::types::*;
use ast::inst::*; use ast::inst::*;
use ast::op::*;
use common::vector_as_str; use common::vector_as_str;
use std::collections::HashMap; use std::collections::HashMap;
...@@ -21,7 +22,7 @@ pub struct MuFunction { ...@@ -21,7 +22,7 @@ pub struct MuFunction {
pub sig: P<MuFuncSig>, pub sig: P<MuFuncSig>,
pub content: Option<FunctionContent>, pub content: Option<FunctionContent>,
pub context: FunctionContext, pub context: FunctionContext,
pub block_trace: Option<Vec<MuTag>> // only available after Trace Generation Pass pub block_trace: Option<Vec<MuTag>> // only available after Trace Generation Pass
} }
...@@ -29,15 +30,16 @@ impl MuFunction { ...@@ -29,15 +30,16 @@ impl MuFunction {
pub fn new(fn_name: MuTag, sig: P<MuFuncSig>) -> MuFunction { pub fn new(fn_name: MuTag, sig: P<MuFuncSig>) -> MuFunction {
MuFunction{fn_name: fn_name, sig: sig, content: None, context: FunctionContext::new(), block_trace: None} MuFunction{fn_name: fn_name, sig: sig, content: None, context: FunctionContext::new(), block_trace: None}
} }
pub fn define(&mut self, content: FunctionContent) { pub fn define(&mut self, content: FunctionContent) {
self.content = Some(content) self.content = Some(content)
} }
pub fn new_ssa(&mut self, id: MuID, tag: MuTag, ty: P<MuType>) -> P<TreeNode> { pub fn new_ssa(&mut self, id: MuID, tag: MuTag, ty: P<MuType>) -> P<TreeNode> {
self.context.values.insert(id, ValueEntry{id: id, tag: tag, ty: ty.clone(), use_count: Cell::new(0), expr: None}); self.context.values.insert(id, ValueEntry{id: id, tag: tag, ty: ty.clone(), use_count: Cell::new(0), expr: None});
P(TreeNode { P(TreeNode {
op: pick_op_code_for_ssa(&ty),
v: TreeNode_::Value(P(Value{ v: TreeNode_::Value(P(Value{
tag: tag, tag: tag,
ty: ty, ty: ty,
...@@ -45,22 +47,13 @@ impl MuFunction { ...@@ -45,22 +47,13 @@ impl MuFunction {
})) }))
}) })
} }
pub fn new_constant(&mut self, tag: MuTag, ty: P<MuType>, v: Constant) -> P<TreeNode> { pub fn new_constant(&mut self, v: P<Value>) -> 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> {
P(TreeNode{ P(TreeNode{
op: pick_op_code_for_const(&v.ty),
v: TreeNode_::Value(v) v: TreeNode_::Value(v)
}) })
} }
} }
#[derive(Debug)] #[derive(Debug)]
...@@ -73,11 +66,11 @@ impl FunctionContent { ...@@ -73,11 +66,11 @@ impl FunctionContent {
pub fn get_entry_block(&self) -> &Block { pub fn get_entry_block(&self) -> &Block {
self.get_block(self.entry) self.get_block(self.entry)
} }
pub fn get_entry_block_mut(&mut self) -> &mut Block { pub fn get_entry_block_mut(&mut self) -> &mut Block {
self.get_block_mut(self.entry) self.get_block_mut(self.entry)
} }
pub fn get_block(&self, tag: MuTag) -> &Block { pub fn get_block(&self, tag: MuTag) -> &Block {
let ret = self.blocks.get(tag); let ret = self.blocks.get(tag);
match ret { match ret {
...@@ -85,14 +78,14 @@ impl FunctionContent { ...@@ -85,14 +78,14 @@ impl FunctionContent {
None => panic!("cannot find block {}", tag) None => panic!("cannot find block {}", tag)
} }
} }
pub fn get_block_mut(&mut self, tag: MuTag) -> &mut Block { pub fn get_block_mut(&mut self, tag: MuTag) -> &mut Block {
let ret = self.blocks.get_mut(tag); let ret = self.blocks.get_mut(tag);
match ret { match ret {
Some(b) => b, Some(b) => b,
None => panic!("cannot find block {}", tag) None => panic!("cannot find block {}", tag)
} }
} }
} }
#[derive(Debug)] #[derive(Debug)]
...@@ -106,11 +99,11 @@ impl FunctionContext { ...@@ -106,11 +99,11 @@ impl FunctionContext {
values: HashMap::new() values: HashMap::new()
} }
} }
pub fn get_value(&self, id: MuID) -> Option<&ValueEntry> { pub fn get_value(&self, id: MuID) -> Option<&ValueEntry> {
self.values.get(&id) self.values.get(&id)
} }
pub fn get_value_mut(&mut self, id: MuID) -> Option<&mut ValueEntry> { pub fn get_value_mut(&mut self, id: MuID) -> Option<&mut ValueEntry> {
self.values.get_mut(&id) self.values.get_mut(&id)
} }
...@@ -142,14 +135,14 @@ impl ControlFlow { ...@@ -142,14 +135,14 @@ impl ControlFlow {
} else { } else {
let mut hot_blk = self.succs[0].target; let mut hot_blk = self.succs[0].target;
let mut hot_prob = self.succs[0].probability; let mut hot_prob = self.succs[0].probability;
for edge in self.succs.iter() { for edge in self.succs.iter() {
if edge.probability > hot_prob { if edge.probability > hot_prob {
hot_blk = edge.target; hot_blk = edge.target;
hot_prob = edge.probability; hot_prob = edge.probability;
} }
} }
Some(hot_blk) Some(hot_blk)
} }
} }
...@@ -191,21 +184,21 @@ pub enum EdgeKind { ...@@ -191,21 +184,21 @@ pub enum EdgeKind {
pub struct BlockContent { pub struct BlockContent {
pub args: Vec<P<TreeNode>>, pub args: Vec<P<TreeNode>>,
pub body: Vec<P<TreeNode>>, pub body: Vec<P<TreeNode>>,
pub keepalives: Option<Vec<P<TreeNode>>> pub keepalives: Option<Vec<P<TreeNode>>>
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
/// always use with P<TreeNode> /// always use with P<TreeNode>
pub struct TreeNode { pub struct TreeNode {
// pub op: OpCode, pub op: OpCode,
pub v: TreeNode_ pub v: TreeNode_,
} }
impl TreeNode { impl TreeNode {
pub fn new_inst(v: Instruction) -> P<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> { pub fn extract_ssa_id(&self) -> Option<MuID> {
match self.v { match self.v {
TreeNode_::Value(ref pv) => { TreeNode_::Value(ref pv) => {
...@@ -229,7 +222,7 @@ impl fmt::Display for TreeNode { ...@@ -229,7 +222,7 @@ impl fmt::Display for TreeNode {
write!(f, "+({} %{}#{})", pv.ty, pv.tag, id) write!(f, "+({} %{}#{})", pv.ty, pv.tag, id)
}, },
Value_::Constant(ref c) => { Value_::Constant(ref c) => {
write!(f, "+({} {})", pv.ty, c) write!(f, "+({} {})", pv.ty, c)
} }
} }
}, },
...@@ -265,11 +258,11 @@ pub struct ValueEntry { ...@@ -265,11 +258,11 @@ pub struct ValueEntry {
pub id: MuID, pub id: MuID,
pub tag: MuTag, pub tag: MuTag,
pub ty: P<MuType>, pub ty: P<MuType>,
// how many times this entry is used // how many times this entry is used
// availalbe after DefUse pass // availalbe after DefUse pass
pub use_count: Cell<usize>, pub use_count: Cell<usize>,
// this field is only used during TreeGeneration pass // this field is only used during TreeGeneration pass
pub expr: Option<Instruction> pub expr: Option<Instruction>
} }
...@@ -294,7 +287,7 @@ pub enum Constant { ...@@ -294,7 +287,7 @@ pub enum Constant {
IRef(Address), IRef(Address),
FuncRef(Address), FuncRef(Address),
UFuncRef(Address), UFuncRef(Address),
Vector(Vec<Constant>), Vector(Vec<Constant>),
} }
impl fmt::Display for Constant { impl fmt::Display for Constant {
...@@ -330,4 +323,4 @@ pub fn op_vector_str(vec: &Vec<OpIndex>, ops: &Vec<P<TreeNode>>) -> String { ...@@ -330,4 +323,4 @@ pub fn op_vector_str(vec: &Vec<OpIndex>, ops: &Vec<P<TreeNode>>) -> String {
} }
} }
ret ret
} }
\ No newline at end of file
use ast::ptr::P;
use ast::types::*;
use ast::inst::*;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum OpCode { pub enum OpCode {
// SSA // SSA
RegI64, RegI64,
RegFP, RegFP,
// Constant // Constant
IntImmI64, IntImmI64,
FPImm, FPImm,
// non-terminal // non-terminal
Assign, Assign,
Fence, Fence,
//terminal //terminal
Return, Return,
ThreadExit, ThreadExit,
...@@ -25,15 +29,16 @@ pub enum OpCode { ...@@ -25,15 +29,16 @@ pub enum OpCode {
SwapStack, SwapStack,
Switch, Switch,
ExnInstruction, ExnInstruction,
// expression // expression
BinOp, Binary(BinOp),
CmpOp, Comparison(CmpOp),
AtomicRMW(AtomicRMWOp),
ExprCall, ExprCall,
Load, Load,
Store, Store,
CmpXchg, CmpXchg,
AtomicRMWOp,
New, New,
AllocA, AllocA,
NewHybrid, NewHybrid,
...@@ -49,6 +54,64 @@ pub enum OpCode { ...@@ -49,6 +54,64 @@ pub enum OpCode {
GetVarPartIRef 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)] #[derive(Copy, Clone, Debug)]
pub enum BinOp { pub enum BinOp {
// Int(n) BinOp Int(n) -> Int(n) // Int(n) BinOp Int(n) -> Int(n)
...@@ -61,14 +124,14 @@ pub enum BinOp { ...@@ -61,14 +124,14 @@ pub enum BinOp {
And, And,
Or, Or,
Xor, Xor,
// Int(n) BinOp Int(m) -> Int(n) // Int(n) BinOp Int(m) -> Int(n)
Shl, Shl,
Lshr, Lshr,
AsHR, Ashr,
// FP BinOp FP -> FP // FP BinOp FP -> FP
Fadd, FAdd,
FSub, FSub,
FMul, FMul,
FDiv, FDiv,
...@@ -88,7 +151,7 @@ pub enum CmpOp { ...@@ -88,7 +151,7 @@ pub enum CmpOp {
UGT, UGT,
ULE, ULE,
ULT, ULT,
// for FP comparison // for FP comparison
FFALSE, FFALSE,
FTRUE, FTRUE,
...@@ -121,4 +184,42 @@ pub enum AtomicRMWOp { ...@@ -121,4 +184,42 @@ pub enum AtomicRMWOp {
MIN, MIN,
UMAX, UMAX,
UMIN UMIN
} }
\ No newline at end of file
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::ir::*;
use ast::ptr::*; use ast::ptr::*;
use ast::inst::Destination;
use ast::inst::DestArg;
use ast::inst::Instruction_::*; use ast::inst::Instruction_::*;
use ast::op;
use ast::op::OpCode;
use vm::context::VMContext; use vm::context::VMContext;
use compiler::CompilerPass; use compiler::CompilerPass;
...@@ -19,18 +23,19 @@ impl CompilerPass for InstructionSelection { ...@@ -19,18 +23,19 @@ impl CompilerPass for InstructionSelection {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
self.name self.name
} }
#[allow(unused_variables)] #[allow(unused_variables)]
fn start_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) { fn start_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
debug!("{}", self.name()); debug!("{}", self.name());
} }
#[allow(unused_variables)]
fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) { fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
for block_label in func.block_trace.as_ref().unwrap() { for block_label in func.block_trace.as_ref().unwrap() {
let block = func.content.as_mut().unwrap().get_block_mut(block_label); let block = func.content.as_mut().unwrap().get_block_mut(block_label);
let block_content = block.content.as_mut().unwrap(); let block_content = block.content.as_mut().unwrap();
for inst in block_content.body.iter_mut() { for inst in block_content.body.iter_mut() {
instruction_select(inst); instruction_select(inst);
} }
...@@ -38,33 +43,186 @@ impl CompilerPass for InstructionSelection { ...@@ -38,33 +43,186 @@ impl CompilerPass for InstructionSelection {
} }
} }
#[allow(unused_variables)]
fn instruction_select(inst: &mut P<TreeNode>) { fn instruction_select(inst: &mut P<TreeNode>) {
trace!("instsel on node {}", inst);
match inst.v { match inst.v {
TreeNode_::Instruction(ref inst) => { TreeNode_::Instruction(ref inst) => {
match inst.v { match inst.v {
Branch2{cond, ref true_dest, ref false_dest, true_prob} => { 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)
}
};
match cond.v { let mut ops = inst.ops.borrow_mut();
TreeNode_::Instruction(ref inst) => {
match inst.v { process_dest(&mut ops, fallthrough_dest);
CmpOp(op, op1, op2) => { 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!("unexpected inst as child node of branch2: {}", cond) _ => panic!("expected a comparison inst")
} }
}, },
TreeNode_::Value(ref pv) => { 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")