WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

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 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