Commit af6c5e98 authored by qinsoon's avatar qinsoon
Browse files

draft ir.rs

parent 241e50c3
use ast::types::*;
use std::sync::Arc;
pub type WPID = usize;
pub type MuID = usize;
pub type MuTag = &'static str;
pub type Address = usize; // TODO: replace this with Address(usize)
#[derive(Clone)]
pub struct SSAVar {
id: MuID,
tag:Option<MuTag>,
ty: Arc<MuType_>
}
#[derive(Copy, Clone)]
pub enum MemoryOrder {
NotAtomic,
Relaxed,
......@@ -10,6 +24,218 @@ pub enum MemoryOrder {
SeqCst
}
#[derive(Clone)]
pub enum Literal {
LitInt(usize, Arc<MuType_>),
LitFP(f64, Arc<MuType_>),
LitFPNaN(Arc<MuType_>),
LitFPInfPos(Arc<MuType_>),
LitFPInfNeg(Arc<MuType_>),
LitNull(Arc<MuType_>)
}
#[derive(Copy, Clone)]
pub enum CallConvention {
Mu,
Foreign(ForeignFFI)
}
#[derive(Copy, Clone)]
pub enum ForeignFFI {
C
}
#[derive(Clone)]
pub struct CallData {
func: SSAVar,
args: Vec<SSAVar>,
convention: CallConvention
}
#[derive(Clone)]
pub struct Block<'func> {
args: Vec<SSAVar>,
body: Vec<Instruction>,
exit: Terminal<'func>,
keepalives: Vec<SSAVar>
}
#[derive(Clone)]
pub struct TerminationData<'func> {
normal_dest: Destination<'func>,
exn_dest: Destination<'func>
}
#[derive(Clone)]
pub enum DestArg {
Normal(SSAVar),
Freshbound(usize)
}
#[derive(Clone)]
pub struct Destination<'func> {
block: &'func Block<'func>,
args: Vec<DestArg>
}
#[derive(Clone)]
pub enum Value {
Int(usize, usize),
IRef(Arc<MuType_>, Address),
FloatV(f32),
DoubleV(f64),
VectorV(Vec<Value>),
FuncRefV(Address),
UFuncRefV(Address)
}
#[derive(Clone)]
pub enum Expression {
BinOp(BinOp, SSAVar, SSAVar),
Value(Value),
// memory operations
CmpXchg{
is_iref: bool, // T for iref, F for ptr
is_strong: bool,
success_order: MemoryOrder,
fail_order: MemoryOrder,
mem_loc: SSAVar,
expected_value: SSAVar,
desired_value: SSAVar
},
AtomicRMW{
is_iref: bool, // T for iref, F for ptr
order: MemoryOrder,
op: AtomicRMWOp,
mem_loc: SSAVar,
value: SSAVar // operand for op
},
Fence(MemoryOrder),
// allocation operations
New(Arc<MuType_>),
AllocA(Arc<MuType_>),
NewHybrid{ // hybrid type, var part length
ty: Arc<MuType_>,
var_len: SSAVar
},
AllocAHybrid{
ty: Arc<MuType_>,
var_len: SSAVar
},
NewStack{
func: SSAVar
},
NewThread{
stack: SSAVar,
args: Vec<SSAVar>
},
NewThreadExn{ // NewThreadExn SSAVar (* stack id *) SSAVar (* exception value *) ???
stack: SSAVar,
exn: SSAVar
},
PushFrame{
stack: SSAVar,
func: SSAVar
},
PopFrame{
stack: SSAVar
}
}
#[derive(Clone)]
pub enum Instruction {
Assign{
left: Vec<SSAVar>,
right: Expression
},
Load{
dest: SSAVar,
is_iref: bool,
mem_loc: SSAVar,
order: MemoryOrder
},
Store{
src: SSAVar,
is_iref: bool,
mem_loc: SSAVar,
order: MemoryOrder
}
}
#[derive(Clone)]
pub enum Terminal<'func> {
Return(Vec<SSAVar>),
ThreadExit,
Throw(Vec<SSAVar>),
TailCall(CallData),
Branch1(Destination<'func>),
Branch2{
cond: SSAVar,
true_dest: Destination<'func>,
false_dest: Destination<'func>
},
Watchpoint, // TODO: Watchpoint ((wpid # destination) option) termination_data
WPBranch{
wp: WPID,
disable_dest: Destination<'func>,
enable_dest: Destination<'func>
},
Call{
data: CallData,
normal_dest: Destination<'func>,
exn_dest: Destination<'func>
},
SwapStack{
stack: SSAVar,
args: Vec<SSAVar>,
normal_dest: Destination<'func>,
exn_dest: Destination<'func>
},
Switch{
cond: SSAVar,
default: Destination<'func>,
branches: Vec<(Value, Destination<'func>)>
},
ExnInstruction{
inner: Expression,
term: TerminationData<'func>
}
}
#[derive(Clone)]
pub enum Declaration<'global> {
ConstDecl{
const_name: MuTag,
ty: Arc<MuType_>,
val: Value
},
TypeDef{
type_name: MuTag,
ty: Arc<MuType_>
},
FunctionSignature{
sig_name: MuTag,
ret_tys: Vec<Arc<MuType_>>,
arg_tys: Vec<Arc<MuType_>>
},
FuncDef{
fn_name: MuTag,
sig_name: MuTag,
label: MuTag, // ?
blocks: Vec<(MuTag, Block<'global>)>
}
}
#[derive(Copy, Clone)]
pub enum BinOp {
// Int(n) BinOp Int(n) -> Int(n)
Add,
......@@ -35,6 +261,7 @@ pub enum BinOp {
FRem
}
#[derive(Copy, Clone)]
pub enum CmpOp {
// for Int comparison
EQ,
......@@ -67,20 +294,17 @@ pub enum CmpOp {
FUNO
}
pub enum Literal_ {
LitIntDec(usize, MuType_),
LitIntHex(usize, MuType_),
LitFP(f64, MuType_),
LitFPNaN(MuType_),
LitFPInfPos(MuType_),
LitFPInfNeg(MuType_),
LitNull(MuType_)
}
pub struct SSAVar {
id: MuID,
tag:Option<MuTag>,
ty: MuType_
#[derive(Copy, Clone)]
pub enum AtomicRMWOp {
XCHG,
ADD,
SUB,
AND,
NAND,
OR,
XOR,
MAX,
MIN,
UMAX,
UMIN
}
\ No newline at end of file
pub mod types;
\ No newline at end of file
pub mod types;
pub mod ir;
\ No newline at end of file
extern crate std;
use ast::ir::*;
use std::collections::HashMap;
use std::sync::RwLock;
pub type MuID = usize;
pub type MuTag = &'static str;
use std::sync::Arc;
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum MuType {
pub enum MuType_ {
/// int <length>
Int (usize),
/// float
......@@ -16,23 +15,23 @@ pub enum MuType {
Double,
/// ref<T>
Ref (Box<MuType>), // Box is needed for non-recursive enum
Ref (Arc<MuType_>), // Box is needed for non-recursive enum
/// iref<T>: internal reference
IRef (Box<MuType>),
IRef (Arc<MuType_>),
/// weakref<T>
WeakRef (Box<MuType>),
WeakRef (Arc<MuType_>),
/// uptr<T>: unsafe pointer
UPtr (Box<MuType>),
UPtr (Arc<MuType_>),
/// struct<T1 T2 ...>
Struct (MuTag),
/// array<T length>
Array (Box<MuType>, usize),
Array (Arc<MuType_>, usize),
/// hybrid<F1 F2 ... V>: a hybrid of fixed length parts and a variable length part
Hybrid (Vec<Box<MuType>>, Box<MuType>),
Hybrid (Vec<Arc<MuType_>>, Arc<MuType_>),
/// void
Void,
......@@ -46,7 +45,7 @@ pub enum MuType {
Tagref64,
/// vector<T length>
Vector (Box<MuType>, usize),
Vector (Arc<MuType_>, usize),
/// funcref<@sig>
FuncRef (MuFuncSig),
......@@ -62,49 +61,49 @@ lazy_static! {
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct StructType_ {
tys: Vec<Box<MuType>>
tys: Vec<Arc<MuType_>>
}
impl StructType_ {
pub fn set_tys(&mut self, list: Vec<&MuType>) {
pub fn set_tys(&mut self, mut list: Vec<Arc<MuType_>>) {
self.tys.clear();
self.tys.append(&mut list.into_iter().map(|t| Box::new(t.clone())).collect());
self.tys.append(&mut list);
}
}
impl MuType {
pub fn int(len: usize) -> MuType {
MuType::Int(len)
impl MuType_ {
pub fn int(len: usize) -> MuType_ {
MuType_::Int(len)
}
pub fn float() -> MuType {
MuType::Float
pub fn float() -> MuType_ {
MuType_::Float
}
pub fn double() -> MuType {
MuType::Double
pub fn double() -> MuType_ {
MuType_::Double
}
pub fn muref(referent: &MuType) -> MuType {
MuType::Ref(Box::new(referent.clone()))
pub fn muref(referent: Arc<MuType_>) -> MuType_ {
MuType_::Ref(referent)
}
pub fn muref_void() -> MuType {
MuType::Ref(Box::new(MuType::void()))
pub fn muref_void() -> MuType_ {
MuType_::Ref(Arc::new(MuType_::void()))
}
pub fn iref(referent: &MuType) -> MuType {
MuType::IRef(Box::new(referent.clone()))
pub fn iref(referent: Arc<MuType_>) -> MuType_ {
MuType_::IRef(referent)
}
pub fn weakref(referent: &MuType) -> MuType {
MuType::WeakRef(Box::new(referent.clone()))
pub fn weakref(referent: Arc<MuType_>) -> MuType_ {
MuType_::WeakRef(referent)
}
pub fn uptr(referent: &MuType) -> MuType {
MuType::UPtr(Box::new(referent.clone()))
pub fn uptr(referent: Arc<MuType_>) -> MuType_ {
MuType_::UPtr(referent)
}
pub fn mustruct_empty(tag: MuTag) -> MuType {
pub fn mustruct_empty(tag: MuTag) -> MuType_ {
let struct_ty_ = StructType_{tys: vec![]};
STRUCT_TAG_MAP.write().unwrap().insert(tag, struct_ty_);
MuType::Struct(tag)
MuType_::Struct(tag)
}
pub fn mustruct(tag: MuTag, list: Vec<&MuType>) -> MuType {
let struct_ty_ = StructType_{tys: list.into_iter().map(|t| Box::new(t.clone())).collect()};
pub fn mustruct(tag: MuTag, list: Vec<Arc<MuType_>>) -> MuType_ {
let struct_ty_ = StructType_{tys: list};
// if there is an attempt to use a same tag for different struct,
// we panic
......@@ -121,93 +120,90 @@ impl MuType {
// otherwise, store the tag
STRUCT_TAG_MAP.write().unwrap().insert(tag, struct_ty_);
MuType::Struct(tag)
MuType_::Struct(tag)
}
pub fn array(ty: &MuType, len: usize) -> MuType {
MuType::Array(Box::new(ty.clone()), len)
pub fn array(ty: Arc<MuType_>, len: usize) -> MuType_ {
MuType_::Array(ty, len)
}
pub fn hybrid(fix_tys: Vec<&MuType>, var_ty: &MuType) -> MuType {
MuType::Hybrid(
fix_tys.into_iter().map(|t| Box::new(t.clone())).collect(),
Box::new(var_ty.clone())
)
pub fn hybrid(fix_tys: Vec<Arc<MuType_>>, var_ty: Arc<MuType_>) -> MuType_ {
MuType_::Hybrid(fix_tys, var_ty)
}
pub fn void() -> MuType {
MuType::Void
pub fn void() -> MuType_ {
MuType_::Void
}
pub fn threadref() -> MuType {
MuType::ThreadRef
pub fn threadref() -> MuType_ {
MuType_::ThreadRef
}
pub fn stackref() -> MuType {
MuType::StackRef
pub fn stackref() -> MuType_ {
MuType_::StackRef
}
pub fn tagref64() -> MuType {
MuType::Tagref64
pub fn tagref64() -> MuType_ {
MuType_::Tagref64
}
pub fn vector(ty: &MuType, len: usize) -> MuType {
MuType::Vector(Box::new(ty.clone()), len)
pub fn vector(ty: Arc<MuType_>, len: usize) -> MuType_ {
MuType_::Vector(ty, len)
}
pub fn funcref(sig: MuFuncSig) -> MuType {
MuType::FuncRef(sig)
pub fn funcref(sig: MuFuncSig) -> MuType_ {
MuType_::FuncRef(sig)
}
pub fn ufuncptr(sig: MuFuncSig) -> MuType {
MuType::UFuncPtr(sig)
pub fn ufuncptr(sig: MuFuncSig) -> MuType_ {
MuType_::UFuncPtr(sig)
}
}
/// is a type floating-point type?
pub fn is_fp(ty: &MuType) -> bool {
pub fn is_fp(ty: &MuType_) -> bool {
match *ty {
MuType::Float | MuType::Double => true,
MuType_::Float | MuType_::Double => true,
_ => false
}
}
/// is a type raw pointer?
pub fn is_ptr(ty: &MuType) -> bool {
pub fn is_ptr(ty: &MuType_) -> bool {
match *ty {
MuType::UPtr(_) | MuType::UFuncPtr(_) => true,
MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
_ => false
}
}
/// is a type scalar type?
pub fn is_scalar(ty: &MuType) -> bool {
pub fn is_scalar(ty: &MuType_) -> bool {
match *ty {
MuType::Int(_)
| MuType::Float
| MuType::Double
| MuType::Ref(_)
| MuType::IRef(_)
| MuType::WeakRef(_)
| MuType::FuncRef(_)
| MuType::UFuncPtr(_)
| MuType::ThreadRef
| MuType::StackRef
| MuType::Tagref64
| MuType::UPtr(_) => true,
MuType_::Int(_)
| MuType_::Float
| MuType_::Double
| MuType_::Ref(_)
| MuType_::IRef(_)
| MuType_::WeakRef(_)
| MuType_::FuncRef(_)
| MuType_::UFuncPtr(_)
| MuType_::ThreadRef
| MuType_::StackRef
| MuType_::Tagref64
| MuType_::UPtr(_) => true,
_ => false
}
}
/// is a type traced by the garbage collector?
/// Note: An aggregated type is traced if any of its part is traced.
pub fn is_traced(ty: &MuType) -> bool {
pub fn is_traced(ty: &MuType_) -> bool {
match *ty {
MuType::Ref(_) => true,
MuType::IRef(_) => true,
MuType::WeakRef(_) => true,
MuType::Array(ref elem_ty, _)
| MuType::Vector(ref elem_ty, _) => is_traced(elem_ty),
MuType::ThreadRef
| MuType::StackRef
| MuType::Tagref64 => true,
MuType::Hybrid(ref fix_tys, ref var_ty) => {
MuType_::Ref(_) => true,
MuType_::IRef(_) => true,
MuType_::WeakRef(_) => true,
MuType_::Array(ref elem_ty, _)
| MuType_::Vector(ref elem_ty, _) => is_traced(elem_ty),
MuType_::ThreadRef
| MuType_::StackRef
| MuType_::Tagref64 => true,
MuType_::Hybrid(ref fix_tys, ref var_ty) => {
is_traced(var_ty) ||
fix_tys.into_iter().map(|ty| is_traced(ty))
.fold(false, |ret, this| ret || this)
},
MuType::Struct(tag) => {
MuType_::Struct(tag) => {
let map = STRUCT_TAG_MAP.read().unwrap();
let struct_ty = map.get(tag).unwrap();
let ref field_tys = struct_ty.tys;
......@@ -221,22 +217,22 @@ pub fn is_traced(ty: &MuType) -> bool {
/// is a type native safe?
/// Note: An aggregated type is native safe if all of its parts are native safe.
pub fn is_native_safe(ty: &MuType) -> bool {
pub fn is_native_safe(ty: &MuType_) -> bool {
match *ty {
MuType::Int(_) => true,
MuType::Float => true,
MuType::Double => true,
MuType::Void => true,
MuType::Array(ref elem_ty, _)
| MuType::Vector(ref elem_ty, _) => is_native_safe(elem_ty),
MuType::UPtr(_) => true,
MuType::UFuncPtr(_) => true,
MuType::Hybrid(ref fix_tys, ref var_ty) => {
MuType_::Int(_) => true,
MuType_::Float => true,
MuType_::Double => true,
MuType_::Void => true,
MuType_::Array(ref elem_ty, _)
| MuType_::Vector(ref elem_ty, _) => is_native_safe(elem_ty),
MuType_::UPtr(_) => true,
MuType_::UFuncPtr(_) => true,
MuType_::Hybrid(ref fix_tys, ref var_ty) => {
is_native_safe(var_ty) &&
fix_tys.into_iter().map(|ty| is_native_safe(&ty))
.fold(true, |ret, this| ret && this)
},
MuType::Struct(tag) => {
MuType_::Struct(tag) => {
let map = STRUCT_TAG_MAP.read().unwrap();
let struct_ty = map.get(tag).unwrap();
let ref field_tys = struct_ty.tys;
......@@ -259,16 +255,13 @@ macro_rules! is_type (
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct MuFuncSig {
ret_tys : Vec<MuType>,
args_tys: Vec<MuType>
ret_tys : Vec<Arc<MuType_>>,
args_tys: Vec<Arc<MuType_>>
}
impl MuFuncSig {
pub fn new(ret_tys: Vec<&MuType>, args_tys: Vec<&MuType>) -> MuFuncSig {
MuFuncSig {
ret_tys : ret_tys.into_iter().map(|t| t.clone()).collect(),
args_tys: args_tys.into_iter().map(|t| t.clone()).collect()
}
pub fn new(ret_tys: Vec<Arc<MuType_>>, args_tys: Vec<Arc<MuType_>>) -> MuFuncSig {
MuFuncSig {ret_tys : ret_tys, args_tys: args_tys}
}
}
......@@ -276,6 +269,7 @@ impl MuFuncSig {
mod tests {
use super::*;
use super::STRUCT_TAG_MAP;
use std::sync::Arc;
macro_rules! assert_type (
($test:expr, $expect: expr) => (
......@@ -289,62 +283,62 @@ mod tests {
)
);
/// create one of each MuType
fn create_types() -> Vec<Box<MuType>> {
/// create one of each MuType_