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

Adding arrays.

parent 10eead0a
var int[] x = {12, 232, 33} in
x[0]
\ No newline at end of file
def int foo(int[] x)
x[0]
var int[] x = {13, 25, 32} in
foo(x)
\ No newline at end of file
......@@ -12,7 +12,7 @@ use std::os::raw::{c_char, c_double, c_uint};
use crate::ir_macros;
use crate::ast::Type::Double;
use llvm_sys::LLVMIntPredicate::{LLVMIntULT, LLVMIntNE};
use llvm_sys::LLVMIntPredicate::{LLVMIntNE, LLVMIntULT};
use mu::ast::inst::Instruction_;
use mu::ast::inst::*;
use mu::ast::ir::*;
......@@ -34,6 +34,9 @@ pub enum Type {
Int,
Double,
Void,
IntArray(i64),
DoubleArray(i64),
BoolArray(i64),
// Type for anonymous functions to be resolved at runtime
Annon,
......@@ -247,6 +250,41 @@ impl VarExp {
}
}
#[derive(Clone)]
pub struct ArrayExp {
exps: Vec<Box<dyn Exp>>,
}
impl ArrayExp {
pub fn exps(&self) -> &Vec<Box<dyn Exp>> {
&self.exps
}
pub fn new(exps: Vec<Box<dyn Exp>>) -> ArrayExp {
ArrayExp { exps }
}
}
#[derive(Clone)]
pub struct ArrayAccess {
var: String,
idx: Box<dyn Exp>,
}
impl ArrayAccess {
pub fn var(&self) -> &String {
&self.var
}
pub fn idx(&self) -> &Box<dyn Exp> {
&self.idx
}
pub fn new(var: String, idx: Box<dyn Exp>) -> ArrayAccess {
ArrayAccess { var, idx }
}
}
#[derive(Clone)]
pub struct Prototype {
name: String,
......@@ -349,6 +387,165 @@ where
}
}
impl Exp for ArrayAccess {
fn print(&self) -> String {
format!("ArrayAccess({}, {:?})", self.var, self.idx.print())
}
unsafe fn code_gen(
&self,
module: &*mut LLVMModule,
context: &mut Context,
) -> Result<*mut LLVMValue, String> {
let array_idx: *mut LLVMValue = match self.idx().code_gen(module, context) {
Ok(result) => result,
e @ Err(_) => return e,
};
let type_x = context.var_type_map.get(self.var.as_str()).unwrap().clone();
match context.named_values.get(self.var()) {
Some(mut val) => {
let name = format!("{}\0", self.var.clone());
let mut val = *val;
let idx ;
// need to load the pointer first
if type_x == Type::IntArray(-1) {
val = LLVMBuildLoad(
context.builder,
val,
name.as_str().as_ptr() as *const c_char,
);
let pos = [
array_idx,
];
idx = LLVMBuildInBoundsGEP(
context.builder,
val,
pos.as_ptr() as *mut LLVMValueRef,
1,
"tmp\0".as_ptr() as *const c_char,
);
} else {
let pos = [
LLVMConstInt(context.get_llvm_type(&Type::Int), 0, false as i32),
array_idx,
];
idx = LLVMBuildInBoundsGEP(
context.builder,
val,
pos.as_ptr() as *mut LLVMValueRef,
2,
"tmp\0".as_ptr() as *const c_char,
);
}
let var = LLVMBuildLoad(context.builder, idx, "tmp\0".as_ptr() as *const c_char);
Ok(var)
}
None => unimplemented!(),
}
}
unsafe fn code_gen_mu(
&self,
vm: &mut Mu_VM,
fun_ver: &mut MuFunctionVersion,
) -> Result<Arc<TreeNode>, String> {
unimplemented!()
}
fn get_type(
&self,
var_type_table: &HashMap<String, Type, RandomState>,
fn_type_table: &HashMap<String, Type, RandomState>,
) -> Type {
match var_type_table.get(self.var.as_str()).unwrap() {
Type::IntArray(_) => Type::Int,
Type::DoubleArray(_) => Type::Double,
Type::BoolArray(_) => Type::Bool,
_ => Type::Void,
}
}
}
impl Exp for ArrayExp {
fn print(&self) -> String {
let mut exps = vec![];
for exp in self.exps() {
exps.push(exp.print())
}
format!("ArrayExp({:?})", exps)
}
unsafe fn code_gen(
&self,
module: &*mut LLVMModule,
context: &mut Context,
) -> Result<*mut LLVMValue, String> {
let mut llvm_exps = vec![];
for exp in self.exps() {
llvm_exps.push(exp.code_gen(module, context).unwrap());
}
let elem_type = self
.exps()
.get(0)
.unwrap()
.get_type(&context.var_type_map, &context.fn_type_map);
let array_const = LLVMConstArray(
context.get_llvm_type(&elem_type),
llvm_exps.as_ptr() as *mut LLVMValueRef,
self.exps.len() as u32,
);
Ok(array_const)
}
unsafe fn code_gen_mu(
&self,
vm: &mut Mu_VM,
fun_ver: &mut MuFunctionVersion,
) -> Result<Arc<TreeNode>, String> {
unimplemented!()
}
fn get_type(
&self,
var_type_table: &HashMap<String, Type, RandomState>,
fn_type_table: &HashMap<String, Type, RandomState>,
) -> Type {
if self.exps.len() > 0 {
let exp_type = self
.exps()
.get(0)
.unwrap()
.get_type(var_type_table, fn_type_table);
for exp in self.exps() {
assert_eq!(exp_type, exp.get_type(var_type_table, fn_type_table))
}
match exp_type {
Type::Int => Type::IntArray(self.exps.len() as i64),
Type::Bool => Type::BoolArray(self.exps.len() as i64),
Type::Double => Type::DoubleArray(self.exps.len() as i64),
_ => panic!("Unsupported type."),
}
} else {
panic!("Cannot get type of an empty array.")
}
}
}
impl Exp for VarExp {
fn print(&self) -> String {
let mut assigned_exps = vec![];
......@@ -380,11 +577,26 @@ impl Exp for VarExp {
e @ Err(_) => return e,
};
// initializing type of arrays with its proper dimension
let var_type = match var_type {
Type::IntArray(-1) => {
init_expr.get_type(&context.var_type_map, &context.fn_type_map)
}
Type::BoolArray(-1) => {
init_expr.get_type(&context.var_type_map, &context.fn_type_map)
}
Type::DoubleArray(-1) => {
init_expr.get_type(&context.var_type_map, &context.fn_type_map)
}
t => t.clone(),
};
old_type_bindings.push(context.var_type_map.remove(name.name.as_str()));
context
.var_type_map
.insert(name.name.clone(), var_type.clone());
let variable = create_block_alloca(context, llvm_block, name.name.as_str());
LLVMBuildStore(context.builder, init_value, variable);
old_bindings.push(context.named_values.remove(name.name.as_str()));
......@@ -487,7 +699,12 @@ impl Exp for VarExp {
var_type_table: &HashMap<String, Type, RandomState>,
fn_type_table: &HashMap<String, Type, RandomState>,
) -> Type {
self.body_exp.get_type(var_type_table, fn_type_table)
let mut local_vars = var_type_table.clone();
for (var_type, var, _) in self.vars() {
local_vars.insert(var.name.clone(), var_type.clone());
}
self.body_exp.get_type(&local_vars, fn_type_table)
}
}
......@@ -916,7 +1133,7 @@ impl Exp for ConditionalExp {
"ifcont\0".as_ptr() as *const c_char,
);
let if_type = self.get_type(&context.var_type_map, &context.fn_type_map);
let if_type = self.get_type(&context.var_type_map, &context.fn_type_map);
LLVMBuildCondBr(context.builder, ifcond, then_block, else_block);
......@@ -1271,7 +1488,9 @@ impl Exp for BinaryExp {
};
let exp_type = self.get_type(&context.var_type_map, &context.fn_type_map);
let lhs_type = self.lhs.get_type(&context.var_type_map, &context.fn_type_map);
let lhs_type = self
.lhs
.get_type(&context.var_type_map, &context.fn_type_map);
match self.c() {
'+' => match exp_type {
......@@ -1617,12 +1836,33 @@ impl Exp for Var {
match context.named_values.get(self.name()) {
Some(val) => {
let name = format!("{}\0", self.name.clone());
let var = LLVMBuildLoad(
context.builder,
*val,
name.as_str().as_ptr() as *const c_char,
);
Ok(var)
match self.get_type(&context.var_type_map, &context.fn_type_map) {
Type::Int | Type::Bool | Type::Double => {
let var = LLVMBuildLoad(
context.builder,
*val,
name.as_str().as_ptr() as *const c_char,
);
Ok(var)
}
Type::IntArray(_) | Type::BoolArray(_) | Type::DoubleArray(_) => {
let pos = [
LLVMConstInt(context.get_llvm_type(&Type::Int), 0, false as i32),
LLVMConstInt(context.get_llvm_type(&Type::Int), 0, false as i32),
];
let pointer = LLVMBuildInBoundsGEP(
context.builder,
*val,
pos.as_ptr() as *mut LLVMValueRef,
2,
"tmp\0".as_ptr() as *const c_char,
);
Ok(pointer)
}
_ => panic!("Unsupported type"),
}
}
None => unimplemented!(),
}
......
......@@ -15,17 +15,20 @@ use self::llvm::execution_engine::{
LLVMCreateExecutionEngineForModule, LLVMCreateJITCompilerForModule,
LLVMCreateSimpleMCJITMemoryManager, LLVMDisposeExecutionEngine, LLVMExecutionEngineRef,
LLVMFreeMachineCodeForFunction, LLVMGenericValueToFloat, LLVMGenericValueToInt,
LLVMInitializeMCJITCompilerOptions, LLVMLinkInMCJIT, LLVMMCJITCompilerOptions,
LLVMOpaqueExecutionEngine, LLVMRunFunction,
LLVMGenericValueToPointer, LLVMInitializeMCJITCompilerOptions, LLVMLinkInMCJIT,
LLVMMCJITCompilerOptions, LLVMOpaqueExecutionEngine, LLVMRunFunction,
};
use self::llvm::prelude::{
LLVMBasicBlockRef, LLVMBool, LLVMBuilderRef, LLVMContextRef, LLVMPassManagerRef, LLVMTypeRef,
};
use self::llvm::support::LLVMAddSymbol;
use self::llvm::target::{LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeTarget};
use self::llvm::target::{
LLVMIntPtrType, LLVMTargetDataRef, LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeTarget,
};
use self::llvm::target_machine::{
LLVMCodeGenFileType, LLVMCodeGenOptLevel, LLVMCodeModel, LLVMCreateTargetMachine,
LLVMGetDefaultTargetTriple, LLVMGetFirstTarget, LLVMRelocMode, LLVMTargetMachineEmitToFile,
LLVMCodeGenFileType, LLVMCodeGenOptLevel, LLVMCodeModel, LLVMCreateTargetDataLayout,
LLVMCreateTargetMachine, LLVMGetDefaultTargetTriple, LLVMGetFirstTarget, LLVMRelocMode,
LLVMTargetMachineEmitToFile, LLVMTargetMachineRef,
};
use self::llvm::transforms::scalar::{
LLVMAddBasicAliasAnalysisPass, LLVMAddCFGSimplificationPass, LLVMAddGVNPass,
......@@ -45,17 +48,20 @@ pub enum RunResult {
Double(f64),
Int(i64),
Bool(bool),
IntArray(Vec<i64>),
}
pub struct Context {
pub context: LLVMContextRef,
pub builder: LLVMBuilderRef,
pub named_values: HashMap<String, LLVMValueRef>,
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,
pub target_machine: LLVMTargetMachineRef,
pub target_data: LLVMTargetDataRef,
pub options: LLVMMCJITCompilerOptions,
}
impl Context {
......@@ -63,21 +69,47 @@ impl Context {
let context = llvm::core::LLVMContextCreate();
let builder = llvm::core::LLVMCreateBuilderInContext(context);
let named_values = HashMap::new();
let mut options = std::mem::uninitialized();
let mut types_map = HashMap::new();
types_map.insert(Type::Bool, LLVMInt1Type());
types_map.insert(Type::Int, LLVMInt64Type());
types_map.insert(Type::Double, LLVMDoubleType());
LLVMInitializeMCJITCompilerOptions(
&mut options,
std::mem::size_of::<LLVMMCJITCompilerOptions>(),
);
LLVMLinkInMCJIT();
LLVM_InitializeNativeTarget();
LLVM_InitializeNativeAsmPrinter();
LLVM_InitializeNativeTarget();
let triple = LLVMGetDefaultTargetTriple();
let target = LLVMGetFirstTarget();
let cpu = CString::new("x86-64").expect("invalid cpu");
let feature = CString::new("").expect("invalid feature");
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_data = LLVMCreateTargetDataLayout(target_machine);
Context {
context,
builder,
named_values,
llvm_types_map: types_map,
var_type_map: HashMap::new(),
fn_type_map: HashMap::new(),
curr_function: 0,
pass_manager,
target_machine,
target_data,
options,
}
}
......@@ -86,7 +118,16 @@ impl Context {
}
pub unsafe fn get_llvm_type(&self, t: &Type) -> LLVMTypeRef {
self.llvm_types_map.get(t).unwrap().clone()
match t {
Type::Bool => LLVMInt1Type(),
Type::Int => LLVMInt64Type(),
Type::Double => LLVMDoubleType(),
Type::IntArray(-1) => LLVMPointerType(LLVMInt64Type(), 0),
Type::IntArray(n) => LLVMArrayType(LLVMInt64Type(), *n as u32),
Type::DoubleArray(n) => LLVMArrayType(LLVMDoubleType(), *n as u32),
Type::BoolArray(n) => LLVMArrayType(LLVMInt1Type(), *n as u32),
_ => panic!("Unsupported type."),
}
}
}
......@@ -98,7 +139,6 @@ unsafe fn run_function(
) -> Result<RunResult, String> {
let mut ee = 0 as LLVMExecutionEngineRef;
let mut error = 0 as *mut c_char;
let mut options = std::mem::uninitialized();
if LLVMVerifyModule(module, LLVMAbortProcessAction, &mut error) > 0 {
let cstr_buf = std::ffi::CStr::from_ptr(error);
......@@ -109,17 +149,7 @@ unsafe fn run_function(
return Err(message);
}
LLVMInitializeMCJITCompilerOptions(
&mut options,
std::mem::size_of::<LLVMMCJITCompilerOptions>(),
);
LLVMLinkInMCJIT();
LLVM_InitializeNativeTarget();
LLVM_InitializeNativeAsmPrinter();
LLVM_InitializeNativeTarget();
if LLVMCreateJITCompilerForModule(&mut ee, module, options.OptLevel, &mut error) > 0 {
if LLVMCreateJITCompilerForModule(&mut ee, module, context.options.OptLevel, &mut error) > 0 {
let cstr_buf = std::ffi::CStr::from_ptr(error);
let result = String::from_utf8_lossy(cstr_buf.to_bytes()).into_owned();
let message = LLVMCreateMessage(error);
......@@ -138,28 +168,12 @@ unsafe fn run_function(
Err(e) => return Err(e),
};
let triple = LLVMGetDefaultTargetTriple();
let target = LLVMGetFirstTarget();
let cpu = CString::new("x86-64").expect("invalid cpu");
let feature = CString::new("").expect("invalid feature");
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 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,
context.target_machine,
module,
output_file.as_ptr() as *mut i8,
file_type,
......@@ -187,6 +201,10 @@ unsafe fn run_function(
let result = LLVMGenericValueToInt(result, 1) != 0;
Ok(RunResult::Bool(result))
}
// Type::IntArray => {
// let result = LLVMGenericValueToPointer(result) as Vec<i64>;
// Ok(RunResult::IntArray(result))
// }
_ => Err("invalid function type".parse().unwrap()),
}
}
......@@ -404,7 +422,7 @@ impl Code_gen for Function {
LLVMBuildRet(context.builder, body);
LLVMVerifyFunction(function, LLVMAbortProcessAction);
// LLVMVerifyFunction(function, LLVMAbortProcessAction);
// LLVMRunFunctionPassManager(context.pass_manager, function);
Ok(function)
......
......@@ -21,6 +21,9 @@ pub enum Token {
BOOL,
INT,
DOUBLE,
BOOL_ARRAY,
INT_ARRAY,
DOUBLE_ARRAY,
}
pub fn read_file() -> (String, Vec<Token>) {
......@@ -101,12 +104,29 @@ fn parse_identifier_or_keyword(c: char, input_str: &[u8], index: &mut i32) -> To
let mut result = String::new();
result.push(c);
let mut openedBracket = false;
while *index < input_str.len() as i32 {
let c = input_str[*index as usize] as char;
*index = *index + 1;
if c.is_alphanumeric() {
if c.is_alphanumeric() & !openedBracket {
result.push(c);
} else if c.is_alphanumeric() & openedBracket {
result.pop();
*index = *index - 2;
break;
} else if c == '[' {
result.push(c);
openedBracket = true;
} else if (c == ']') & openedBracket {
result.push(c);
break;
} else if openedBracket {
result.pop();
result.pop();
*index = *index - 2;
break;
} else {
*index = *index - 1;
break;
......@@ -124,6 +144,9 @@ fn parse_identifier_or_keyword(c: char, input_str: &[u8], index: &mut i32) -> To
let int_token = String::from("int");
let bool_token = String::from("bool");
let double_token = String::from("double");
let int_array_token = String::from("int[]");
let bool_array_token = String::from("bool[]");
let double_array_token = String::from("double[]");
let false_token = String::from("false");
let true_token = String::from("true");
......@@ -171,6 +194,18 @@ fn parse_identifier_or_keyword(c: char, input_str: &[u8], index: &mut i32) -> To
return Token::DOUBLE;
}
if result.eq(&int_array_token) {
return Token::INT_ARRAY;
}
if result.eq(&bool_array_token) {
return Token::BOOL_ARRAY;
}
if result.eq(&double_array_token) {
return Token::DOUBLE_ARRAY;
}
if result.eq(&false_token) {
return Token::BOOL_LIT(false);
}
......
......@@ -91,10 +91,12 @@ fn parse_top_level_expression(
}
fn parse_prototype(tokens: &Vec<Token>, curr_token: &mut usize) -> Option<Box<Prototype>> {
// TODO allow functions to return arrays
let proto_ret_type = match &tokens[*curr_token] {
Token::BOOL => Type::Bool,
Token::INT => Type::Int,
Token::DOUBLE => Type::Double,
_ => return None,
};
......@@ -123,6 +125,9 @@ fn parse_prototype(tokens: &Vec<Token>, curr_token: &mut usize) -> Option<Box<Pr
Token::BOOL => Type::Bool,
Token::INT => Type::Int,
Token::DOUBLE => Type::Double,
Token::BOOL_ARRAY => Type::BoolArray(-1),
Token::INT_ARRAY => Type::IntArray(-1),
Token::DOUBLE_ARRAY => Type::DoubleArray(-1),
_ => break,
};
......@@ -163,6 +168,7 @@ fn parse_primary(tokens: &Vec<Token>, curr_token: &mut usize) -> Option<Box<dyn
parse_number_exp(&tokens, curr_token)
}
Token::CHAR('(') => parse_parenthesized_exp(&tokens, curr_token),
Token::CHAR('{') => parse_array_exp(&tokens, curr_token),