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 7653b21f authored by Eduardo Souza's avatar Eduardo Souza
Browse files

Added for expressions and LLVM, and Mu backends.

parent af3c686a
......@@ -6,7 +6,7 @@ use llvm_sys::LLVMRealPredicate::{LLVMRealOLT, LLVMRealONE};
use llvm_sys::{LLVMModule, LLVMValue};
use mu::vm::VM;
use std::ffi::CString;
use std::os::raw::{c_char, c_uint};
use std::os::raw::{c_char, c_double, c_uint};
#[macro_use]
use crate::ir_macros;
......@@ -18,6 +18,7 @@ use mu::ast::types::*;
use mu::runtime::*;
use mu::utils::LinkedHashMap;
use mu::vm::*;
use mu_aot_llvm::instr::gen_instr_branch2;
use std::borrow::Borrow;
use std::ops::Add;
......@@ -82,6 +83,388 @@ impl CallExp {
}
}
pub struct ForExp {
var: Var,
start_exp: Box<dyn Exp>,
end_exp: Box<dyn Exp>,
step_exp: Box<dyn Exp>,
body_exp: Box<dyn Exp>,
}
impl ForExp {
pub fn var(&self) -> &Var {
&self.var
}
pub fn start_exp(&self) -> &Box<dyn Exp> {
&self.start_exp
}
pub fn end_exp(&self) -> &Box<dyn Exp> {
&self.end_exp
}
pub fn step_exp(&self) -> &Box<dyn Exp> {
&self.step_exp
}
pub fn body_exp(&self) -> &Box<dyn Exp> {
&self.body_exp
}
pub fn new(
var: Var,
start_exp: Box<dyn Exp>,
end_exp: Box<dyn Exp>,
step_exp: Box<dyn Exp>,
body_exp: Box<dyn Exp>,
) -> ForExp {
ForExp {
var,
start_exp,
end_exp,
step_exp,
body_exp,
}
}
}
impl Exp for ForExp {
fn print(&self) -> String {
format!(
"ForExpr({:?}, {:?}, {:?}, {:?}, {:?})",
self.var.print(),
self.start_exp.print(),
self.end_exp.print(),
self.step_exp.print(),
self.body_exp.print(),
)
}
unsafe fn code_gen(
&self,
module: &*mut LLVMModule,
context: &mut Context,
) -> Result<*mut LLVMValue, String> {
let start_exp: *mut LLVMValue = match self.start_exp().code_gen(module, context) {
Ok(result) => result,
e @ Err(_) => return e,
};
let preheader_block = LLVMGetInsertBlock(context.builder);
let mut function = LLVMGetBasicBlockParent(preheader_block);
let preloop_block = LLVMAppendBasicBlockInContext(
context.context,
function,
"preloop\0".as_ptr() as *const c_char,
);
LLVMBuildBr(context.builder, preloop_block);
LLVMPositionBuilderAtEnd(context.builder, preloop_block);
let mut phi = LLVMBuildPhi(
context.builder,
context.ty,
self.var.name().as_str().as_ptr() as *const c_char,
);
LLVMAddIncoming(
phi,
vec![start_exp].as_mut_slice().as_mut_ptr(),
vec![preheader_block].as_mut_slice().as_mut_ptr(),
1 as c_uint,
);
let old_value = context.named_values.remove(self.var.name());
context.named_values.insert(self.var.name().clone(), phi);
let end_exp: *mut LLVMValue = match self.end_exp().code_gen(module, context) {
Ok(result) => result,
e @ Err(_) => return e,
};
let zero = LLVMConstReal(context.ty, 0.0);
let end_cond = LLVMBuildFCmp(
context.builder,
LLVMRealONE,
end_exp,
zero,
"loopcond\0".as_ptr() as *const c_char,
);
let mut after_block = LLVMAppendBasicBlockInContext(
context.context,
function,
"afterloop\0".as_ptr() as *const c_char,
);
let mut loop_block = LLVMAppendBasicBlockInContext(
context.context,
function,
"loop\0".as_ptr() as *const c_char,
);
LLVMBuildCondBr(context.builder, end_cond, loop_block, after_block);
LLVMPositionBuilderAtEnd(context.builder, loop_block);
match self.body_exp().code_gen(module, context) {
Ok(result) => result,
e @ Err(_) => return e,
};
let step_exp: *mut LLVMValue = match self.step_exp().code_gen(module, context) {
Ok(result) => result,
e @ Err(_) => return e,
};
let next_value = LLVMBuildFAdd(
context.builder,
phi,
step_exp,
"nextvar\0".as_ptr() as *const c_char,
);
let loop_end_block = LLVMGetInsertBlock(context.builder);
LLVMAddIncoming(
phi,
vec![next_value].as_mut_slice().as_mut_ptr(),
vec![loop_block].as_mut_slice().as_mut_ptr(),
1 as c_uint,
);
LLVMBuildBr(context.builder, preloop_block);
LLVMPositionBuilderAtEnd(context.builder, after_block);
context.named_values.remove(self.var.name());
match old_value {
Some(v) => {
context.named_values.insert(self.var.name().clone(), v);
}
None => (),
}
Ok(zero)
}
unsafe fn code_gen_mu(
&self,
vm: &mut Mu_VM,
fun_ver: &mut MuFunctionVersion,
) -> Result<Arc<TreeNode>, String> {
let start_exp = match self.start_exp.code_gen_mu(vm, fun_ver) {
Ok(r) => r,
e @ Err(_) => return e,
};
// create preloop block
let preloop_block = Block::new(MuEntityHeader::named(
vm.vm.next_id(),
Arc::new(vm.generate_name(String::from("preloop"))),
));
&vm.vm.set_name(preloop_block.as_entity());
let preloop_block_id = preloop_block.hdr.id();
let phi_node_name = vm.generate_name(String::from("phi_node"));
let phi_node = fun_ver.new_ssa(
MuEntityHeader::named(vm.vm.next_id(), Arc::new(phi_node_name.clone())),
vm.ty.clone(),
);
vm.vm.set_name(phi_node.as_entity());
// branch to preloop
let current_block = vm.blocks_map.get_mut(&vm.curr_block).unwrap();
let current_block_args = (&current_block.args).clone();
let current_block_form_args = (&current_block.form_args).clone();
let mut args_preloop = current_block_args.clone();
let mut form_args_preloop = current_block_form_args.clone();
form_args_preloop.insert(phi_node_name.clone(), phi_node.clone());
args_preloop.push(phi_node.clone_value());
let mut args = vec![];
for (_, arg) in &current_block_form_args {
args.push(arg.clone());
}
args.push(start_exp);
let branch_preloop = create_branch1_instr(vm.vm.next_id(), fun_ver, args, &preloop_block);
current_block.instr.push(branch_preloop);
vm.blocks_map.insert(
preloop_block_id,
Mu_Block {
block: preloop_block.clone(),
instr: vec![],
args: args_preloop.clone(),
form_args: form_args_preloop.clone(),
},
);
vm.curr_block = preloop_block_id;
let current_block = vm.blocks_map.get_mut(&vm.curr_block).unwrap();
let old_value = current_block.form_args.remove(self.var.name());
current_block
.form_args
.insert(self.var.name().clone(), phi_node.clone());
// build end loop check
let end_exp = match self.end_exp.code_gen_mu(vm, fun_ver) {
Ok(r) => r,
e @ Err(_) => return e,
};
let name = format!("const_{}", 0);
let name = vm.generate_name(name);
let false_const = vm.vm.declare_const(
MuEntityHeader::named(vm.vm.next_id(), Arc::new(name)),
vm.int_ty.clone(),
Constant::Int(1),
);
let false_local = fun_ver.new_constant(false_const.clone());
let loop_check = fun_ver.new_ssa(
MuEntityHeader::named(
vm.vm.next_id(),
Arc::new(vm.generate_name(String::from("loop_check"))),
),
vm.int_ty.clone(),
);
vm.vm.set_name(loop_check.as_entity());
let loop_check_inst = create_int_cmp_op_instruction_eq(
fun_ver,
vm,
&loop_check,
vec![end_exp.clone(), false_local.clone()],
);
let current_block = vm.blocks_map.get_mut(&vm.curr_block).unwrap();
current_block.instr.push(loop_check_inst);
// create after_loop and loop blocks
let loop_block = Block::new(MuEntityHeader::named(
vm.vm.next_id(),
Arc::new(vm.generate_name(String::from("loop"))),
));
&vm.vm.set_name(loop_block.as_entity());
let loop_block_id = loop_block.hdr.id();
vm.blocks_map.insert(
loop_block_id,
Mu_Block {
block: loop_block.clone(),
instr: vec![],
args: args_preloop.clone(),
form_args: form_args_preloop.clone(),
},
);
let after_loop_block = Block::new(MuEntityHeader::named(
vm.vm.next_id(),
Arc::new(vm.generate_name(String::from("after_loop"))),
));
&vm.vm.set_name(after_loop_block.as_entity());
let after_loop_block_id = after_loop_block.hdr.id();
vm.blocks_map.insert(
after_loop_block_id,
Mu_Block {
block: after_loop_block.clone(),
instr: vec![],
args: current_block_args.clone(),
form_args: current_block_form_args.clone(),
},
);
let mut ops = vec![loop_check];
for arg in current_block_form_args.values() {
ops.push(arg.clone())
}
ops.push(phi_node.clone());
let form_args_true = vm.blocks_map.get(&loop_block_id).unwrap();
let form_args_false = vm.blocks_map.get(&after_loop_block_id).unwrap();
let branch_loop_check = create_branch2_instr(
vm.vm.next_id(),
fun_ver,
ops,
form_args_true.form_args.clone(),
form_args_false.form_args.clone(),
&loop_block,
&after_loop_block
);
let current_block = vm.blocks_map.get_mut(&vm.curr_block).unwrap();
current_block.instr.push(branch_loop_check);
vm.curr_block = loop_block_id;
match self.body_exp.code_gen_mu(vm, fun_ver) {
Ok(r) => r,
e @ Err(_) => return e,
};
let step_exp = match self.step_exp.code_gen_mu(vm, fun_ver) {
Ok(r) => r,
e @ Err(_) => return e,
};
let name = vm.generate_name(String::from("step"));
let var = fun_ver.new_ssa(
MuEntityHeader::named(vm.vm.next_id(), Arc::new(name)),
vm.ty.clone(),
);
vm.vm.set_name(var.as_entity());
let step_inst = fun_ver.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(vm.vm.next_id()),
value: Some(vec![var.clone_value()]),
ops: vec![phi_node.clone(), step_exp.clone()],
v: Instruction_::BinOp(FAdd, 0, 1),
});
let mut ops = vec![];
for arg in current_block_form_args.values() {
ops.push(arg.clone())
}
ops.push(var.clone());
let branch_preloop = create_branch1_instr(vm.vm.next_id(), fun_ver, ops, &preloop_block);
let current_block = vm.blocks_map.get_mut(&vm.curr_block).unwrap();
current_block.instr.push(step_inst);
current_block.instr.push(branch_preloop);
vm.curr_block = after_loop_block_id;
let preloop_block = vm.blocks_map.get_mut(&preloop_block_id).unwrap();
match old_value {
Some(v) => {
preloop_block.form_args.insert(self.var.name.clone(), v);
},
None => ()
}
// for loop returns 0
let name = vm.generate_name(String::from("zero").clone());
let zero_const = vm.vm.declare_const(
MuEntityHeader::named(vm.vm.next_id(), Arc::new(name)),
vm.ty.clone(),
Constant::Double(0.0),
);
let zero_local = fun_ver.new_constant(zero_const.clone());
Ok(zero_local)
}
}
pub struct ConditionalExp {
cond: Box<dyn Exp>,
then_branch: Box<dyn Exp>,
......@@ -207,7 +590,6 @@ impl Exp for ConditionalExp {
vm: &mut Mu_VM,
fun_ver: &mut MuFunctionVersion,
) -> Result<Arc<TreeNode>, String> {
// process and create cond
let cond = match self.cond.code_gen_mu(vm, fun_ver) {
Ok(r) => r,
......@@ -274,45 +656,20 @@ impl Exp for ConditionalExp {
let current_block_args = (&current_block.args).clone();
let current_block_form_args = (&current_block.form_args).clone();
let branch_then_inst = fun_ver.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(vm.vm.next_id()),
value: None,
ops: {
let mut ops = vec![var.clone()];
for arg in current_block_form_args.values() {
ops.push(arg.clone())
}
ops
},
v: Instruction_::Branch2 {
cond: 0,
true_dest: Destination {
target: then_branch_block.hdr.clone(),
args: {
let mut args = vec![];
for pos_arg in 1..current_block_form_args.len() + 1 {
args.push(pos_arg)
}
args.iter()
.map(|x| -> DestArg { DestArg::Normal(*x) })
.collect()
},
},
false_dest: Destination {
target: else_branch_block.hdr.clone(),
args: {
let mut args = vec![];
for pos_arg in 1..current_block_form_args.len() + 1 {
args.push(pos_arg)
}
args.iter()
.map(|x| -> DestArg { DestArg::Normal(*x) })
.collect()
},
},
true_prob: 0.5,
},
});
let mut ops = vec![var.clone()];
for arg in current_block_form_args.values() {
ops.push(arg.clone())
}
let branch_then_inst = create_branch2_instr(
vm.vm.next_id(),
fun_ver,
ops,
current_block_form_args.clone(),
current_block_form_args.clone(),
&then_branch_block,
&else_branch_block,
);
current_block.instr.push(branch_then_inst.clone());
......@@ -404,6 +761,50 @@ impl Exp for ConditionalExp {
}
}
fn create_branch2_instr(
id: MuID,
fun_ver: &mut MuFunctionVersion,
ops: Vec<P<TreeNode>>,
form_args_true: LinkedHashMap<String, P<TreeNode>>,
form_args_false: LinkedHashMap<String, P<TreeNode>>,
true_dest: &Block,
false_dest: &Block,
) -> P<TreeNode> {
fun_ver.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(id),
value: None,
ops,
v: Instruction_::Branch2 {
cond: 0,
true_dest: Destination {
target: true_dest.hdr.clone(),
args: {
let mut args = vec![];
for pos_arg in 1..form_args_true.len() + 1 {
args.push(pos_arg)
}
args.iter()
.map(|x| -> DestArg { DestArg::Normal(*x) })
.collect()
},
},
false_dest: Destination {
target: false_dest.hdr.clone(),
args: {
let mut args = vec![];
for pos_arg in 1..form_args_false.len() + 1 {
args.push(pos_arg)
}
args.iter()
.map(|x| -> DestArg { DestArg::Normal(*x) })
.collect()
},
},
true_prob: 0.5,
},
})
}
fn create_branch1_instr(
id: MuID,
fun_ver: &mut MuFunctionVersion,
......
......@@ -18,14 +18,18 @@ use self::llvm::execution_engine::{
LLVMLinkInMCJIT, LLVMMCJITCompilerOptions, LLVMOpaqueExecutionEngine, LLVMRunFunction,
};
use self::llvm::prelude::{LLVMBool, LLVMBuilderRef, LLVMContextRef};
use self::llvm::support::LLVMAddSymbol;
use self::llvm::target::{LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeTarget};
use self::llvm::target_machine::{
LLVMCodeGenFileType, LLVMCodeGenOptLevel, LLVMCodeModel, LLVMCreateTargetMachine,
LLVMGetDefaultTargetTriple, LLVMGetFirstTarget, LLVMRelocMode, LLVMTargetMachineEmitToFile,
};
use self::llvm::LLVMRealPredicate::LLVMRealOLT;
use self::llvm::{LLVMModule, LLVMType, LLVMValue};
use crate::lexer::Token::CHAR;
use llvm::core::*;
use std::borrow::Borrow;
use std::os::raw::{c_char, c_int, c_uint};
use self::llvm::target_machine::{LLVMTargetMachineEmitToFile, LLVMGetDefaultTargetTriple, LLVMGetFirstTarget, LLVMCodeGenOptLevel, LLVMRelocMode, LLVMCodeModel, LLVMCreateTargetMachine, LLVMCodeGenFileType};
use std::os::raw::{c_char, c_int, c_uint, c_void};
pub struct Context {
pub context: LLVMContextRef,
......@@ -47,7 +51,7 @@ impl Context {
builder,
named_values,
ty,
curr_function : 0,
curr_function: 0,
}
}
......@@ -96,12 +100,10 @@ unsafe fn run_function(
let mut args = vec![];
let (f, result) = match function {
Ok(f) => {
(
f,
LLVMRunFunction(ee, f, args.len() as c_uint, args.as_mut_ptr()),
)
}
Ok(f) => (
f,
LLVMRunFunction(ee, f, args.len() as c_uint, args.as_mut_ptr()),
),
Err(e) => {
println!("{}", e);
return;
......@@ -115,12 +117,26 @@ unsafe fn run_function(
let opt_level = LLVMCodeGenOptLevel::LLVMCodeGenLevelNone;
let reloc_mode = LLVMRelocMode::LLVMRelocDefault;
let code_model = LLVMCodeModel::LLVMCodeModelDefault;
let target_machine = LLVMCreateTargetMachine(target, triple, cpu.as_ptr(), feature.as_ptr(), opt_level, reloc_mode, code_model);
let target_machine = LLVMCreateTargetMachine(
target,
triple,
cpu.as_ptr(),
feature.as_ptr(),
opt_level,
reloc_mode,
code_model,
);
let file_type = LLVMCodeGenFileType::LLVMAssemblyFile;
let output_file = CString::new("output.S").expect("invalid file");
let mut error_str = ptr::null_mut();
let res = LLVMTargetMachineEmitToFile(target_machine, module, output_file.as_ptr() as *mut i8, file_type, &mut error_str);
let res = LLVMTargetMachineEmitToFile(
target_machine,
module,
output_file.as_ptr() as *mut i8,
file_type,
&mut error_str,
);
if res == 1 {
let x = CStr::from_ptr(error_str);
let result = String::from_utf8_lossy(x.to_bytes()).into_owned();
......@@ -131,12 +147,25 @@ unsafe fn run_function(
}
let result = LLVMGenericValueToFloat(LLVMDoubleType(), result);
// LLVMDisposeExecutionEngine(ee);
// LLVMDisposeExecutionEngine(ee);
println!("\n{}", result);
}
println!("{}", result);
pub extern "C" fn putchard(x: f64) -> f64 {
print!("{}", x as u8 as char);
x
}
pub unsafe fn init() {
LLVMAddSymbol(
"putchard\0".as_ptr() as *const c_char,
putchard as *mut c_void,
);
}
pub unsafe fn code_gen(filename: String, nodes: ASTNodes) {
init();
let mut context = Context::new();