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

Adding types for literals.

parent 038e9270
This diff is collapsed.
......@@ -14,11 +14,12 @@ use self::llvm::analysis::{LLVMVerifyFunction, LLVMVerifyModule};
use self::llvm::execution_engine::{
LLVMCreateExecutionEngineForModule, LLVMCreateJITCompilerForModule,
LLVMCreateSimpleMCJITMemoryManager, LLVMDisposeExecutionEngine, LLVMExecutionEngineRef,
LLVMFreeMachineCodeForFunction, LLVMGenericValueToFloat, LLVMInitializeMCJITCompilerOptions,
LLVMLinkInMCJIT, LLVMMCJITCompilerOptions, LLVMOpaqueExecutionEngine, LLVMRunFunction,
LLVMFreeMachineCodeForFunction, LLVMGenericValueToFloat, LLVMGenericValueToInt,
LLVMInitializeMCJITCompilerOptions, LLVMLinkInMCJIT, LLVMMCJITCompilerOptions,
LLVMOpaqueExecutionEngine, LLVMRunFunction,
};
use self::llvm::prelude::{
LLVMBasicBlockRef, LLVMBool, LLVMBuilderRef, LLVMContextRef, LLVMPassManagerRef,
LLVMBasicBlockRef, LLVMBool, LLVMBuilderRef, LLVMContextRef, LLVMPassManagerRef, LLVMTypeRef,
};
use self::llvm::support::LLVMAddSymbol;
use self::llvm::target::{LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeTarget};
......@@ -33,16 +34,26 @@ use self::llvm::transforms::scalar::{
use self::llvm::transforms::util::LLVMAddPromoteMemoryToRegisterPass;
use self::llvm::LLVMRealPredicate::LLVMRealOLT;
use self::llvm::{LLVMModule, LLVMType, LLVMValue};
use crate::ast::Type::Annon;
use crate::lexer::Token::CHAR;
use llvm::core::*;
use std::borrow::Borrow;
use std::os::raw::{c_char, c_int, c_uint, c_void};
#[derive(Debug, PartialEq)]
pub enum RunResult {
Double(f64),
Int(i64),
Bool(bool),
}
pub struct Context {
pub context: LLVMContextRef,
pub builder: LLVMBuilderRef,
pub named_values: HashMap<String, LLVMValueRef>,
pub ty: *mut LLVMType,
pub llvm_types_map: HashMap<Type, *mut LLVMType>,
pub var_type_map: HashMap<String, Type>,
pub fn_type_map: HashMap<String, Type>,
pub curr_function: i32,
pub pass_manager: LLVMPassManagerRef,
}
......@@ -52,13 +63,19 @@ impl Context {
let context = llvm::core::LLVMContextCreate();
let builder = llvm::core::LLVMCreateBuilderInContext(context);
let named_values = HashMap::new();
let ty = LLVMDoubleType();
let mut types_map = HashMap::new();
types_map.insert(Type::Bool, LLVMInt1Type());
types_map.insert(Type::Int, LLVMInt64Type());
types_map.insert(Type::Double, LLVMDoubleType());
Context {
context,
builder,
named_values,
ty,
llvm_types_map: types_map,
var_type_map: HashMap::new(),
fn_type_map: HashMap::new(),
curr_function: 0,
pass_manager,
}
......@@ -67,13 +84,18 @@ impl Context {
pub unsafe fn dump(&self) {
LLVMContextDispose(self.context);
}
pub unsafe fn get_llvm_type(&self, t: &Type) -> LLVMTypeRef {
self.llvm_types_map.get(t).unwrap().clone()
}
}
unsafe fn run_function(
function: Result<*mut LLVMValue, String>,
function_type: &Type,
module: *mut LLVMModule,
context: &mut Context,
) -> Result<f64, String> {
) -> Result<RunResult, String> {
let mut ee = 0 as LLVMExecutionEngineRef;
let mut error = 0 as *mut c_char;
let mut options = std::mem::uninitialized();
......@@ -152,8 +174,21 @@ unsafe fn run_function(
return Err(message);
}
let result = LLVMGenericValueToFloat(LLVMDoubleType(), result);
Ok(result)
match function_type {
Type::Double => {
let result = LLVMGenericValueToFloat(LLVMDoubleType(), result);
Ok(RunResult::Double(result))
}
Type::Int => {
let result = LLVMGenericValueToInt(result, 1) as i64;
Ok(RunResult::Int(result))
}
Type::Bool => {
let result = LLVMGenericValueToInt(result, 1) != 0;
Ok(RunResult::Bool(result))
}
_ => Err("invalid function type".parse().unwrap()),
}
}
pub extern "C" fn putchard(x: f64) -> f64 {
......@@ -168,7 +203,7 @@ pub unsafe fn init() {
);
}
pub unsafe fn code_gen(filename: String, nodes: ASTNodes) -> Vec<Result<f64, String>> {
pub unsafe fn code_gen(filename: String, mut nodes: ASTNodes) -> Vec<Result<RunResult, String>> {
init();
let module = llvm::core::LLVMModuleCreateWithName(filename.as_str().as_ptr() as *const _);
let function_pass_manager = LLVMCreateFunctionPassManagerForModule(module);
......@@ -185,14 +220,14 @@ pub unsafe fn code_gen(filename: String, nodes: ASTNodes) -> Vec<Result<f64, Str
let mut module_number = 0;
let mut returning_values = vec![];
for prototype in nodes.prototypes {
for prototype in nodes.prototypes.iter_mut() {
let out_file = CString::new(format!("out_{}.ll", module_number)).unwrap();
prototype.code_gen(&module, &mut context);
llvm::core::LLVMPrintModuleToFile(module, out_file.as_ptr(), ptr::null_mut());
}
for function in nodes.functions {
for function in nodes.functions.iter_mut() {
let out_file = CString::new(format!("out_{}.ll", module_number)).unwrap();
let result = function.code_gen(&module, &mut context);
......@@ -201,7 +236,12 @@ pub unsafe fn code_gen(filename: String, nodes: ASTNodes) -> Vec<Result<f64, Str
// execute module
if function.proto().name() == "" {
returning_values.push(run_function(result, module, &mut context));
returning_values.push(run_function(
result,
function.proto().return_type(),
module,
&mut context,
));
}
let module = llvm::core::LLVMModuleCreateWithName(filename.as_str().as_ptr() as *const _);
let function_pass_manager = LLVMCreateFunctionPassManagerForModule(module);
......@@ -213,7 +253,7 @@ pub unsafe fn code_gen(filename: String, nodes: ASTNodes) -> Vec<Result<f64, Str
trait Code_gen {
unsafe fn code_gen(
&self,
&mut self,
module: &*mut LLVMModule,
context: &mut Context,
) -> Result<LLVMValueRef, String>;
......@@ -221,7 +261,7 @@ trait Code_gen {
impl Code_gen for Prototype {
unsafe fn code_gen(
&self,
&mut self,
module: &*mut LLVMModule,
context: &mut Context,
) -> Result<LLVMValueRef, String> {
......@@ -240,24 +280,36 @@ impl Code_gen for Prototype {
function
}
None => {
let mut param_types = iter::repeat(context.ty)
.take(self.args().len())
.collect::<Vec<_>>();
let mut param_types = vec![];
for (param_type, param_name) in self.args() {
param_types.push(context.get_llvm_type(param_type));
context
.var_type_map
.insert(param_name.clone(), param_type.clone());
}
let fty = LLVMFunctionType(
context.ty,
context.get_llvm_type(self.return_type()),
param_types.as_mut_ptr(),
param_types.len() as c_uint,
false as LLVMBool,
);
let name;
let fname;
if self.name().as_str().eq("") {
let fname = format!("f_anonn_{}", context.curr_function);
fname = format!("f_anonn_{}", context.curr_function);
context.curr_function += 1;
name = CString::new(fname.as_str()).unwrap();
} else {
fname = self.name().clone();
name = CString::new(self.name().clone().as_str()).unwrap();
}
let ftype = self.return_type();
context.fn_type_map.insert(fname.clone(), ftype.clone());
let function = LLVMAddFunction(*module, name.as_ptr() as *const c_char, fty);
for i in 0..self.args().len() {
......@@ -299,16 +351,28 @@ pub unsafe fn create_block_alloca(
let fi = LLVMGetFirstInstruction(block);
LLVMPositionBuilder(builder, block, fi);
let var = format!("{}\0", var_name);
LLVMBuildAlloca(builder, context.ty, var.as_str().as_ptr() as *const c_char)
LLVMBuildAlloca(
builder,
context.get_llvm_type(&Type::Double),
var.as_str().as_ptr() as *const c_char,
)
}
impl Code_gen for Function {
unsafe fn code_gen(
&self,
&mut self,
module: &*mut LLVMModule,
context: &mut Context,
) -> Result<LLVMValueRef, String> {
context.named_values.clear();
context.var_type_map.clear();
if self.proto().return_type().eq(&Type::Annon) {
let fn_type = self
.body()
.get_type(&context.var_type_map, &context.fn_type_map);
self.proto().replace_annon_type(fn_type);
}
let function = match self.proto().code_gen(module, context) {
Ok(function) => function,
......@@ -341,7 +405,7 @@ impl Code_gen for Function {
LLVMBuildRet(context.builder, body);
LLVMVerifyFunction(function, LLVMAbortProcessAction);
LLVMRunFunctionPassManager(context.pass_manager, function);
// LLVMRunFunctionPassManager(context.pass_manager, function);
Ok(function)
}
......
......@@ -13,7 +13,7 @@ pub mod mu_generator;
fn main() {
const USE_LLVM: bool = false;
const USE_AOT_MU_LLVM: bool = false;
const USE_AOT_MU_LLVM: bool = true;
// process chars into tokens
let (filename, tokens) = lexer::read_file();
......@@ -37,7 +37,7 @@ fn main() {
for value in values {
match value {
Ok(v) => println!("{}", v),
Ok(v) => println!("{:?}", v),
Err(e) => println!("{}", e),
}
}
......
extern crate llvm_sys as llvm;
use crate::ast::*;
use crate::generator::RunResult;
use crate::parser::*;
use mu::vm::api;
use mu::vm::api::api_c::*;
......@@ -35,13 +36,14 @@ pub struct Mu_VM {
pub curr_function: i32,
pub curr_block: MuID,
pub blocks_map: LinkedHashMap<MuID, Mu_Block>,
pub ty: P<MuType>,
pub int_ty: P<MuType>,
pub types_mu_types_map: HashMap<Type, P<MuType>>,
pub functions: HashMap<String, P<TreeNode>>,
pub extern_prototypes: HashMap<String, HashSet<i32>>,
pub extern_prototypes: HashMap<String, Prototype>,
pub whitelist: Vec<MuID>,
pub last_runnable_function: Option<MuEntityHeader>,
pub name_generator: HashMap<String, i32>,
pub fn_type_map: HashMap<String, Type>,
pub var_type_map: HashMap<String, Type>,
}
impl Mu_VM {
......@@ -62,17 +64,31 @@ impl Mu_VM {
let curr_function = 0;
let ty = vm.declare_type(
let mut types_mu_types_map = HashMap::new();
let double_ty = vm.declare_type(
MuEntityHeader::named(vm.next_id(), Mu(stringify!(double))),
MuType_::double(),
);
vm.set_name(ty.as_entity());
vm.set_name(double_ty.as_entity());
types_mu_types_map.insert(Type::Double, double_ty);
let int_ty = vm.declare_type(
let int_1_ty = vm.declare_type(
MuEntityHeader::named(vm.next_id(), Mu(stringify!(int_1))),
MuType_::int(1),
);
vm.set_name(int_ty.as_entity());
vm.set_name(int_1_ty.as_entity());
types_mu_types_map.insert(Type::Bool, int_1_ty);
let int_64_ty = vm.declare_type(
MuEntityHeader::named(vm.next_id(), Mu(stringify!(int_64))),
MuType_::int(64),
);
vm.set_name(int_64_ty.as_entity());
types_mu_types_map.insert(Type::Int, int_64_ty);
let functions = HashMap::new();
let extern_prototypes = HashMap::new();
......@@ -84,16 +100,21 @@ impl Mu_VM {
curr_function,
curr_block: 0,
blocks_map,
ty,
int_ty,
types_mu_types_map,
functions,
extern_prototypes,
whitelist,
last_runnable_function: None,
name_generator: HashMap::new(),
fn_type_map: HashMap::new(),
var_type_map: HashMap::new(),
}
}
pub fn get_mu_type(&self, t: &Type) -> P<MuType> {
self.types_mu_types_map.get(t).unwrap().clone()
}
pub fn generate_name(&mut self, name: String) -> String {
match self.name_generator.get(name.as_str()) {
Some(idx) => {
......@@ -116,35 +137,27 @@ pub struct Mu_Block {
pub block_actual_args: Vec<P<Value>>,
pub args_mapping: LinkedHashMap<String, P<TreeNode>>,
pub store: LinkedHashMap<String, P<TreeNode>>,
pub var_type_map: HashMap<String, Type>,
pub env: Vec<P<Value>>,
}
pub unsafe fn code_gen(
filename: String,
nodes: ASTNodes,
mut nodes: ASTNodes,
use_llvm_aot: bool,
debug: bool,
) -> Vec<Result<f64, String>> {
) -> Vec<Result<RunResult, String>> {
let mut vm = Mu_VM::new(use_llvm_aot, debug);
let mut results = vec![];
for prototype in nodes.prototypes {
let n_args = prototype.args().len() as i32;
match vm.extern_prototypes.get_mut(prototype.name()) {
Some(p) => {
p.insert(n_args);
}
None => {
let mut proto_args = HashSet::new();
proto_args.insert(n_args);
vm.extern_prototypes
.insert(prototype.name().clone(), proto_args);
}
}
vm.extern_prototypes
.insert(prototype.name().clone(), prototype.clone());
vm.fn_type_map
.insert(prototype.name().clone(), prototype.return_type().clone());
}
for function in nodes.functions {
for function in nodes.functions.iter_mut() {
function.code_gen_mu(&mut vm);
}
......@@ -166,7 +179,8 @@ pub unsafe fn code_gen(
for f in 0..vm.curr_function {
let f = format!("f_anonn_{}", f);
results.push(run_code(&vm, &f, &deps));
let f_type = vm.fn_type_map.get(f.as_str()).unwrap();
results.push(run_code(&vm, &f, f_type, &deps));
}
results
......@@ -206,7 +220,12 @@ fn make_boot_image(mu_vm: &Mu_VM, f: &MuEntityHeader, use_llvm_aot: bool) {
}
}
fn run_code(mu_vm: &Mu_VM, name: &String, deps: &Vec<String>) -> Result<f64, String> {
fn run_code(
mu_vm: &Mu_VM,
name: &String,
f_type: &Type,
deps: &Vec<String>,
) -> Result<RunResult, String> {
let libname = format!("lib{}.dylib", name);
let mut dylib_args = vec![Arc::new(name.clone())];
......@@ -219,17 +238,33 @@ fn run_code(mu_vm: &Mu_VM, name: &String, deps: &Vec<String>) -> Result<f64, Str
let lib = ll::Library::new(dylib.as_os_str()).unwrap();
unsafe {
let function: ll::Symbol<unsafe extern "C" fn() -> f64> = lib.get(name.as_bytes()).unwrap();
Ok(function())
match f_type {
Type::Double => {
let function: ll::Symbol<unsafe extern "C" fn() -> f64> =
lib.get(name.as_bytes()).unwrap();
Ok(RunResult::Double(function()))
}
Type::Int => {
let function: ll::Symbol<unsafe extern "C" fn() -> i64> =
lib.get(name.as_bytes()).unwrap();
Ok(RunResult::Int(function()))
}
Type::Bool => {
let function: ll::Symbol<unsafe extern "C" fn() -> bool> =
lib.get(name.as_bytes()).unwrap();
Ok(RunResult::Bool(function()))
}
_ => Err("unsupported function type.".parse().unwrap()),
}
}
}
trait Mu_code_gen {
unsafe fn code_gen_mu(&self, mu_vm: &mut Mu_VM);
unsafe fn code_gen_mu(&mut self, mu_vm: &mut Mu_VM);
}
impl Mu_code_gen for Function {
unsafe fn code_gen_mu(&self, mu_vm: &mut Mu_VM) {
unsafe fn code_gen_mu(&mut self, mu_vm: &mut Mu_VM) {
let runnable = self.proto().name() == "";
let mut vm = &mut mu_vm.vm;
......@@ -238,19 +273,37 @@ impl Mu_code_gen for Function {
if runnable {
name = format!("f_anonn_{}", &mu_vm.curr_function);
let curr_var_type_table = mu_vm.var_type_map.clone();
let curr_fn_type_table = mu_vm.fn_type_map.clone();
let function_type = self
.body()
.get_type(&curr_var_type_table, &curr_fn_type_table);
mu_vm.fn_type_map.insert(name.clone(), function_type.clone());
mu_vm.curr_function += 1;
function_sig = create_mu_sig(&mu_vm.vm, &name, vec![mu_vm.ty.clone()], vec![]);
function_sig = create_mu_sig(
&mu_vm.vm,
&name,
vec![mu_vm.get_mu_type(&function_type)],
vec![],
);
} else {
name = self.proto().name().clone();
mu_vm
.fn_type_map
.insert(name.clone(), self.proto().return_type().clone());
let arg_types: Vec<P<MuType>> = self
.proto()
.args()
.iter()
.map(|e| -> P<MuType> { mu_vm.ty.clone() })
.map(|(type_par, name_par)| -> P<MuType> { mu_vm.get_mu_type(type_par) })
.collect();
function_sig = create_mu_sig(&mu_vm.vm, &name, vec![mu_vm.ty.clone()], arg_types);
let return_type = mu_vm.get_mu_type(self.proto().return_type());
function_sig = create_mu_sig(&mu_vm.vm, &name, vec![return_type], arg_types);
}
let function_decl = declare_mu_function(&mu_vm.vm, &name, &function_sig);
......@@ -261,15 +314,17 @@ impl Mu_code_gen for Function {
let mut args = vec![];
let mut form_args = LinkedHashMap::new();
let mut var_type_map = HashMap::new();
let mut alloca_instr = vec![];
for (arg_type, arg_name) in self.proto().args() {
let form_arg = function_version.new_ssa(
MuEntityHeader::named(mu_vm.vm.next_id(), Arc::new(arg_name.clone())),
mu_vm.ty.clone(),
mu_vm.get_mu_type(arg_type),
);
mu_vm.vm.set_name(form_arg.as_entity());
form_args.insert(arg_name.clone(), form_arg.clone());
var_type_map.insert(arg_name.clone(), arg_type.clone());
args.push(form_arg.clone_value());
}
......@@ -286,6 +341,7 @@ impl Mu_code_gen for Function {
block_actual_args: args.clone(),
args_mapping: form_args.clone(),
store: form_args.clone(),
var_type_map: var_type_map.clone(),
env: args.clone(),
},
);
......@@ -338,10 +394,11 @@ pub fn create_mu_load(
mem_loc: P<TreeNode>,
name: String,
) -> (P<TreeNode>, P<TreeNode>) {
// TODO use proper type
let var_loaded_name = format!("{}_l", name);
let var_loaded = func_version.new_ssa(
MuEntityHeader::named(mu_vm.vm.next_id(), Arc::new(var_loaded_name.clone())),
mu_vm.ty.clone(),
mu_vm.get_mu_type(&Type::Double),
);
mu_vm.vm.set_name(var_loaded.as_entity());
......
......@@ -159,7 +159,9 @@ fn parse_expression(tokens: &Vec<Token>, curr_token: &mut usize) -> Option<Box<d
fn parse_primary(tokens: &Vec<Token>, curr_token: &mut usize) -> Option<Box<dyn Exp>> {
match &tokens[*curr_token] {
Token::ID(id) => parse_identifier_exp(&tokens, curr_token),
Token::REAL_LIT(_) | Token::INT_LIT(_) | Token::BOOL_LIT(_) => parse_number_exp(&tokens, curr_token),
Token::REAL_LIT(_) | Token::INT_LIT(_) | Token::BOOL_LIT(_) => {
parse_number_exp(&tokens, curr_token)
}
Token::CHAR('(') => parse_parenthesized_exp(&tokens, curr_token),
Token::IF => parse_conditional_exp(&tokens, curr_token),
Token::FOR => parse_for_exp(&tokens, curr_token),
......@@ -247,6 +249,15 @@ fn parse_for_exp(tokens: &Vec<Token>, curr_token: &mut usize) -> Option<Box<dyn
if let Token::FOR = &tokens[*curr_token] {
*curr_token += 1;
let var_type = match &tokens[*curr_token] {
Token::BOOL => Type::Bool,
Token::INT => Type::Int,
Token::DOUBLE => Type::Double,
_ => return None,
};
*curr_token += 1;
let var;
match &tokens[*curr_token] {
Token::ID(id) => {
......@@ -310,7 +321,7 @@ fn parse_for_exp(tokens: &Vec<Token>, curr_token: &mut usize) -> Option<Box<dyn
};
Some(Box::new(ForExp::new(
var, start_exp, end_exp, step_exp, body_exp,
var, var_type, start_exp, end_exp, step_exp, body_exp,
)))
} else {
None
......
use crate::generator;
use crate::generator::RunResult;
use crate::lexer;
use crate::mu_generator;
use crate::parser;
......@@ -27,7 +28,7 @@ fn test_single_exp() {
);
}
let expected: Vec<Result<f64, String>> = vec![Ok(42.0)];
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Double(42.0))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
......@@ -57,7 +58,8 @@ fn test_multiple_exps() {
);
}
let expected: Vec<Result<f64, String>> = vec![Ok(42.0), Ok(42.0)];
let expected: Vec<Result<RunResult, String>> =
vec![Ok(RunResult::Double(42.0)), Ok(RunResult::Double(42.0))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
......@@ -87,7 +89,7 @@ fn test_function_call() {
);
}
let expected: Vec<Result<f64, String>> = vec![Ok(6.0)];
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Double(6.0))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
......@@ -118,7 +120,7 @@ fn test_extern_function_call() {
);
}
let expected: Vec<Result<f64, String>> = vec![Ok(0.9424888019316975)];
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Double(0.9424888019316975))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
......@@ -144,7 +146,7 @@ fn test_simple_if() {
mu_generator::code_gen(String::from("test_simple_if\0"), nodes.clone(), true, false);
}
let expected: Vec<Result<f64, String>> = vec![Ok(1.0)];
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Double(1.0))];
assert_eq!(llvm_values, expected);