To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

Commit 47b56f7d authored by qinsoon's avatar qinsoon
Browse files

a test to construct a factorial fucntion

parent af6c5e98
#![allow(dead_code)]
#![allow(unused_variables)]
use ast::ptr::P;
use ast::types::*;
use std::sync::Arc;
pub type WPID = usize;
pub type MuID = usize;
......@@ -8,9 +11,15 @@ pub type Address = usize; // TODO: replace this with Address(usize)
#[derive(Clone)]
pub struct SSAVar {
id: MuID,
tag:Option<MuTag>,
ty: Arc<MuType_>
pub id: MuID,
pub tag: MuTag,
pub ty: P<MuType_>
}
#[derive(Clone)]
pub enum Value {
SSAVar(SSAVar),
Constant(MuConstant)
}
#[derive(Copy, Clone)]
......@@ -24,18 +33,6 @@ 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,
......@@ -47,54 +44,64 @@ pub enum ForeignFFI {
C
}
#[derive(Clone)]
pub struct CallData {
func: SSAVar,
args: Vec<SSAVar>,
convention: CallConvention
pub func: P<SSAVar>,
pub args: Vec<P<Value>>,
pub convention: CallConvention
}
#[derive(Clone)]
pub struct Block<'func> {
args: Vec<SSAVar>,
body: Vec<Instruction>,
exit: Terminal<'func>,
keepalives: Vec<SSAVar>
pub struct Block {
label: MuTag,
content: Option<BlockContent>
}
#[derive(Clone)]
pub struct TerminationData<'func> {
normal_dest: Destination<'func>,
exn_dest: Destination<'func>
impl Block {
pub fn new(label: MuTag) -> Block {
Block{label: label, content: None}
}
pub fn set_content(&mut self, v: BlockContent) {
self.content = Some(v);
}
}
pub struct BlockContent {
pub args: Vec<P<Value>>,
pub body: Vec<Instruction>,
pub exit: Terminal,
pub keepalives: Option<Vec<P<SSAVar>>>
}
pub struct TerminationData {
normal_dest: Destination,
exn_dest: Destination
}
#[derive(Clone)]
pub enum DestArg {
Normal(SSAVar),
Normal(P<Value>),
Freshbound(usize)
}
#[derive(Clone)]
pub struct Destination<'func> {
block: &'func Block<'func>,
args: Vec<DestArg>
pub struct Destination {
pub target: MuTag,
pub args: Vec<DestArg>
}
#[derive(Clone)]
pub enum Value {
pub enum Constant {
Int(usize, usize),
IRef(Arc<MuType_>, Address),
IRef(P<MuType_>, Address),
FloatV(f32),
DoubleV(f64),
VectorV(Vec<Value>),
VectorV(Vec<Constant>),
FuncRefV(Address),
UFuncRefV(Address)
}
#[derive(Clone)]
pub enum Expression {
BinOp(BinOp, SSAVar, SSAVar),
Value(Value),
BinOp(BinOp, P<Value>, P<Value>),
CmpOp(CmpOp, P<Value>, P<Value>),
Constant(P<Constant>),
// memory operations
......@@ -103,136 +110,136 @@ pub enum Expression {
is_strong: bool,
success_order: MemoryOrder,
fail_order: MemoryOrder,
mem_loc: SSAVar,
expected_value: SSAVar,
desired_value: SSAVar
mem_loc: P<SSAVar>,
expected_value: P<Value>,
desired_value: P<Value>
},
AtomicRMW{
is_iref: bool, // T for iref, F for ptr
order: MemoryOrder,
op: AtomicRMWOp,
mem_loc: SSAVar,
value: SSAVar // operand for op
mem_loc: P<Value>,
value: P<Value> // operand for op
},
Fence(MemoryOrder),
// allocation operations
New(Arc<MuType_>),
AllocA(Arc<MuType_>),
New(P<MuType_>),
AllocA(P<MuType_>),
NewHybrid{ // hybrid type, var part length
ty: Arc<MuType_>,
var_len: SSAVar
ty: P<MuType_>,
var_len: P<Value>
},
AllocAHybrid{
ty: Arc<MuType_>,
var_len: SSAVar
ty: P<MuType_>,
var_len: P<Value>
},
NewStack{
func: SSAVar
func: P<Value>
},
NewThread{
stack: SSAVar,
args: Vec<SSAVar>
stack: P<Value>,
args: Vec<P<Value>>
},
NewThreadExn{ // NewThreadExn SSAVar (* stack id *) SSAVar (* exception value *) ???
stack: SSAVar,
exn: SSAVar
stack: P<Value>,
exn: P<Value>
},
PushFrame{
stack: SSAVar,
func: SSAVar
stack: P<Value>,
func: P<Value>
},
PopFrame{
stack: SSAVar
stack: P<Value>
}
}
#[derive(Clone)]
pub enum Instruction {
Assign{
left: Vec<SSAVar>,
left: Vec<P<Value>>,
right: Expression
},
Load{
dest: SSAVar,
dest: P<SSAVar>,
is_iref: bool,
mem_loc: SSAVar,
mem_loc: P<Value>,
order: MemoryOrder
},
Store{
src: SSAVar,
src: P<SSAVar>,
is_iref: bool,
mem_loc: SSAVar,
mem_loc: P<Value>,
order: MemoryOrder
}
}
#[derive(Clone)]
pub enum Terminal<'func> {
Return(Vec<SSAVar>),
pub enum Terminal {
Return(Vec<P<Value>>),
ThreadExit,
Throw(Vec<SSAVar>),
Throw(Vec<P<Value>>),
TailCall(CallData),
Branch1(Destination<'func>),
Branch1(Destination),
Branch2{
cond: SSAVar,
true_dest: Destination<'func>,
false_dest: Destination<'func>
cond: P<Value>,
true_dest: Destination,
false_dest: Destination
},
Watchpoint, // TODO: Watchpoint ((wpid # destination) option) termination_data
WPBranch{
wp: WPID,
disable_dest: Destination<'func>,
enable_dest: Destination<'func>
disable_dest: Destination,
enable_dest: Destination
},
Call{
data: CallData,
normal_dest: Destination<'func>,
exn_dest: Destination<'func>
normal_dest: Destination,
exn_dest: Option<Destination>
},
SwapStack{
stack: SSAVar,
args: Vec<SSAVar>,
normal_dest: Destination<'func>,
exn_dest: Destination<'func>
stack: P<Value>,
args: Vec<P<Value>>,
normal_dest: Destination,
exn_dest: Destination
},
Switch{
cond: SSAVar,
default: Destination<'func>,
branches: Vec<(Value, Destination<'func>)>
cond: P<Value>,
default: Destination,
branches: Vec<(P<Constant>, Destination)>
},
ExnInstruction{
inner: Expression,
term: TerminationData<'func>
term: TerminationData
}
}
#[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>)>
}
pub struct MuConstant{
ty: P<MuType_>,
val: Constant
}
pub struct MuFunction {
pub fn_name: MuTag,
pub sig: P<MuFuncSig>,
pub entry: MuTag,
pub blocks: Vec<(MuTag, Block)>
}
pub fn declare_const(const_name: MuTag, ty: P<MuType_>, val: Constant) -> Value {
Value::Constant(MuConstant{ty: ty, val: val})
}
pub fn declare_type(type_name: MuTag, ty: P<MuType_>) -> P<MuType_> {
ty
}
pub fn declare_func_sig(sig_name: MuTag, ret_tys: Vec<P<MuType_>>, arg_tys: Vec<P<MuType_>>) -> MuFuncSig {
MuFuncSig::new(ret_tys, arg_tys)
}
pub fn declare_func (fn_name: MuTag, sig: P<MuFuncSig>, entry: MuTag, blocks: Vec<(MuTag, Block)>) -> MuFunction {
MuFunction{fn_name: fn_name, sig: sig, entry: entry, blocks: blocks}
}
#[derive(Copy, Clone)]
......
pub mod types;
pub mod ir;
\ No newline at end of file
pub mod ir;
pub mod ptr;
\ No newline at end of file
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The AST pointer
//!
//! Provides `P<T>`, a frozen owned smart pointer, as a replacement for `@T` in
//! the AST.
//!
//! # Motivations and benefits
//!
//! * **Identity**: sharing AST nodes is problematic for the various analysis
//! passes (e.g. one may be able to bypass the borrow checker with a shared
//! `ExprAddrOf` node taking a mutable borrow). The only reason `@T` in the
//! AST hasn't caused issues is because of inefficient folding passes which
//! would always deduplicate any such shared nodes. Even if the AST were to
//! switch to an arena, this would still hold, i.e. it couldn't use `&'a T`,
//! but rather a wrapper like `P<'a, T>`.
//!
//! * **Immutability**: `P<T>` disallows mutating its inner `T`, unlike `Box<T>`
//! (unless it contains an `Unsafe` interior, but that may be denied later).
//! This mainly prevents mistakes, but can also enforces a kind of "purity".
//!
//! * **Efficiency**: folding can reuse allocation space for `P<T>` and `Vec<T>`,
//! the latter even when the input and output types differ (as it would be the
//! case with arenas or a GADT AST using type parameters to toggle features).
//!
//! * **Maintainability**: `P<T>` provides a fixed interface - `Deref`,
//! `and_then` and `map` - which can remain fully functional even if the
//! implementation changes (using a special thread-local heap, for example).
//! Moreover, a switch to, e.g. `P<'a, T>` would be easy and mostly automated.
use std::fmt::{self, Display, Debug};
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::ptr;
/// An owned smart pointer.
pub struct P<T> {
ptr: Box<T>
}
#[allow(non_snake_case)]
/// Construct a `P<T>` from a `T` value.
pub fn P<T: 'static>(value: T) -> P<T> {
P {
ptr: Box::new(value)
}
}
impl<T: 'static> P<T> {
/// Move out of the pointer.
/// Intended for chaining transformations not covered by `map`.
pub fn and_then<U, F>(self, f: F) -> U where
F: FnOnce(T) -> U,
{
f(*self.ptr)
}
}
impl<T> Deref for P<T> {
type Target = T;
fn deref<'a>(&'a self) -> &'a T {
&*self.ptr
}
}
impl<T: 'static + Clone> Clone for P<T> {
fn clone(&self) -> P<T> {
P((**self).clone())
}
}
impl<T: PartialEq> PartialEq for P<T> {
fn eq(&self, other: &P<T>) -> bool {
**self == **other
}
}
impl<T: Eq> Eq for P<T> {}
impl<T: Debug> Debug for P<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&**self, f)
}
}
impl<T: Display> Display for P<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&**self, f)
}
}
impl<T> fmt::Pointer for P<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self.ptr, f)
}
}
impl<T: Hash> Hash for P<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
extern crate std;
use ast::ptr::*;
use ast::ir::*;
use std::collections::HashMap;
use std::sync::RwLock;
use std::sync::Arc;
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum MuType_ {
......@@ -15,23 +15,23 @@ pub enum MuType_ {
Double,
/// ref<T>
Ref (Arc<MuType_>), // Box is needed for non-recursive enum
Ref (P<MuType_>), // Box is needed for non-recursive enum
/// iref<T>: internal reference
IRef (Arc<MuType_>),
IRef (P<MuType_>),
/// weakref<T>
WeakRef (Arc<MuType_>),
WeakRef (P<MuType_>),
/// uptr<T>: unsafe pointer
UPtr (Arc<MuType_>),
UPtr (P<MuType_>),
/// struct<T1 T2 ...>
Struct (MuTag),
/// array<T length>
Array (Arc<MuType_>, usize),
Array (P<MuType_>, usize),
/// hybrid<F1 F2 ... V>: a hybrid of fixed length parts and a variable length part
Hybrid (Vec<Arc<MuType_>>, Arc<MuType_>),
Hybrid (Vec<P<MuType_>>, P<MuType_>),
/// void
Void,
......@@ -45,27 +45,27 @@ pub enum MuType_ {
Tagref64,
/// vector<T length>
Vector (Arc<MuType_>, usize),
Vector (P<MuType_>, usize),
/// funcref<@sig>
FuncRef (MuFuncSig),
FuncRef (P<MuFuncSig>),
/// ufuncptr<@sig>
UFuncPtr (MuFuncSig),
UFuncPtr (P<MuFuncSig>),
}
lazy_static! {
/// storing a map from MuTag to StructType_
static ref STRUCT_TAG_MAP : RwLock<HashMap<MuTag, StructType_>> = RwLock::new(HashMap::new());
pub static ref STRUCT_TAG_MAP : RwLock<HashMap<MuTag, StructType_>> = RwLock::new(HashMap::new());
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct StructType_ {
tys: Vec<Arc<MuType_>>
tys: Vec<P<MuType_>>
}
impl StructType_ {
pub fn set_tys(&mut self, mut list: Vec<Arc<MuType_>>) {
pub fn set_tys(&mut self, mut list: Vec<P<MuType_>>) {
self.tys.clear();
self.tys.append(&mut list);
}
......@@ -81,19 +81,19 @@ impl MuType_ {
pub fn double() -> MuType_ {
MuType_::Double
}
pub fn muref(referent: Arc<MuType_>) -> MuType_ {
pub fn muref(referent: P<MuType_>) -> MuType_ {
MuType_::Ref(referent)
}
pub fn muref_void() -> MuType_ {
MuType_::Ref(Arc::new(MuType_::void()))
MuType_::Ref(P(MuType_::void()))
}
pub fn iref(referent: Arc<MuType_>) -> MuType_ {
pub fn iref(referent: P<MuType_>) -> MuType_ {
MuType_::IRef(referent)
}
pub fn weakref(referent: Arc<MuType_>) -> MuType_ {
pub fn weakref(referent: P<MuType_>) -> MuType_ {
MuType_::WeakRef(referent)
}
pub fn uptr(referent: Arc<MuType_>) -> MuType_ {
pub fn uptr(referent: P<MuType_>) -> MuType_ {
MuType_::UPtr(referent)
}
pub fn mustruct_empty(tag: MuTag) -> MuType_ {
......@@ -102,7 +102,7 @@ impl MuType_ {
MuType_::Struct(tag)
}
pub fn mustruct(tag: MuTag, list: Vec<Arc<MuType_>>) -> MuType_ {
pub fn mustruct(tag: MuTag, list: Vec<P<MuType_>>) -> MuType_ {
let struct_ty_ = StructType_{tys: list};
// if there is an attempt to use a same tag for different struct,
......@@ -122,10 +122,10 @@ impl MuType_ {
MuType_::Struct(tag)
}
pub fn array(ty: Arc<MuType_>, len: usize) -> MuType_ {
pub fn array(ty: P<MuType_>, len: usize) -> MuType_ {
MuType_::Array(ty, len)
}
pub fn hybrid(fix_tys: Vec<Arc<MuType_>>, var_ty: Arc<MuType_>) -> MuType_ {
pub fn hybrid(fix_tys: Vec<P<MuType_>>, var_ty: P<MuType_>) -> MuType_ {
MuType_::Hybrid(fix_tys, var_ty)
}
pub fn void() -> MuType_ {
......@@ -140,13 +140,13 @@ impl MuType_ {
pub fn tagref64() -> MuType_ {
MuType_::Tagref64
}
pub fn vector(ty: Arc<MuType_>, len: usize) -> MuType_ {
pub fn vector(ty: P<MuType_>, len: usize) -> MuType_ {
MuType_::Vector(ty, len)
}
pub fn funcref(sig: MuFuncSig) -> MuType_ {
pub fn funcref(sig: P<MuFuncSig>) -> MuType_ {
MuType_::FuncRef(sig)
}
pub fn ufuncptr(sig: MuFuncSig) -> MuType_ {
pub fn ufuncptr(sig: P<MuFuncSig>) -> MuType_ {
MuType_::UFuncPtr(sig)
}
}
......@@ -255,204 +255,12 @@ macro_rules! is_type (
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct MuFuncSig {
ret_tys : Vec<Arc<MuType_>>,
args_tys: Vec<Arc<MuType_>>
ret_tys : Vec<P<MuType_>>,
arg_tys: Vec<P<MuType_>>
}
impl MuFuncSig {
pub fn new(ret_tys: Vec<Arc<MuType_>>, args_tys: Vec<Arc<MuType_>>) -> MuFuncSig {
MuFuncSig {ret_tys : ret_tys, args_tys: args_tys}
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::STRUCT_TAG_MAP;
use std::sync::Arc;
macro_rules! assert_type (
($test:expr, $expect: expr) => (
assert_eq!(format!("{:?}", $test), $expect)
)
);
macro_rules! println_type (
($test:expr) => (