From 264a46f80cfc9f0ff9707709c6103575cafb6044 Mon Sep 17 00:00:00 2001 From: Rohan Jacob-Rao Date: Mon, 3 Aug 2015 14:16:52 -0700 Subject: [PATCH] Initial attempt to translate alloca instruction. --- infer/src/llvm/examples/alloca.ll | 5 +++++ infer/src/llvm/lAst.ml | 2 ++ infer/src/llvm/lLexer.mll | 2 +- infer/src/llvm/lParser.mly | 25 +++++++++---------------- infer/src/llvm/lTrans.ml | 17 +++++++++++------ 5 files changed, 28 insertions(+), 23 deletions(-) create mode 100644 infer/src/llvm/examples/alloca.ll diff --git a/infer/src/llvm/examples/alloca.ll b/infer/src/llvm/examples/alloca.ll new file mode 100644 index 000000000..a80b6f547 --- /dev/null +++ b/infer/src/llvm/examples/alloca.ll @@ -0,0 +1,5 @@ +; Allocate stack variable using alloca instruction +define i32 @main() { + %a = alloca i32 + ret i32 0 +} diff --git a/infer/src/llvm/lAst.ml b/infer/src/llvm/lAst.ml index dd133ba40..b63403f4e 100644 --- a/infer/src/llvm/lAst.ml +++ b/infer/src/llvm/lAst.ml @@ -40,6 +40,8 @@ type instr = | CondBranch of operand * variable * variable | Load of variable * typ * variable | Store of operand * typ * variable + | Alloc of variable * typ * int * int (* return variable, element type, + number of elements, alignment *) type func_def = FuncDef of variable * typ option * (typ * string) list * instr list diff --git a/infer/src/llvm/lLexer.mll b/infer/src/llvm/lLexer.mll index 8554c9ca8..4ea44ec69 100644 --- a/infer/src/llvm/lLexer.mll +++ b/infer/src/llvm/lLexer.mll @@ -120,7 +120,7 @@ rule token = parse (*| "extractvalue" { EXTRACTVALUE }*) (*| "insertvalue" { INSERTVALUE }*) (* memory access and addressing operations *) - (*| "alloca" { ALLOCA }*) + | "alloca" { ALLOCA } | "load" { LOAD } | "store" { STORE } (*| "fence" { FENCE }*) diff --git a/infer/src/llvm/lParser.mly b/infer/src/llvm/lParser.mly index e55afd151..72e15dc91 100644 --- a/infer/src/llvm/lParser.mly +++ b/infer/src/llvm/lParser.mly @@ -94,7 +94,8 @@ (*%token EXTRACTVALUE*) (*%token INSERTVALUE*) (* memory access and addressing operations *) -(*%token ALLOCA*) +%token ALLOCA +%token ALIGN (* argument for alloca *) %token LOAD %token STORE (*%token FENCE*) @@ -184,25 +185,17 @@ block: | LBRACE instrs = list(instr) RBRACE { instrs } instr: - | term = terminator { term } - | variable EQUALS binop { Ret None } (* TODO *) + (* terminator instructions *) + | RET tp=typ op=operand { Ret (Some (tp, op)) } + | RET VOID { Ret None } + | BR LABEL lbl=variable { UncondBranch lbl } + | BR BIT op=operand COMMA LABEL lbl1=variable COMMA LABEL lbl2=variable { CondBranch (op, lbl1, lbl2) } + (* Memory access operations *) + | var=variable EQUALS ALLOCA tp=typ (*COMMA ALIGN sz=SIZE*) { Alloc (var, tp, 1, 1) } | var = variable EQUALS LOAD tp = ptr_typ ptr = variable { Load (var, tp, ptr) } | STORE val_tp = typ value = operand COMMA ptr_tp = ptr_typ var = variable { Store (value, val_tp, var) } (* don't yet know why val_tp and ptr_tp would be different *) -terminator: - | RET tp = typ op = operand { Ret (Some (tp, op)) } - | RET VOID { Ret None } - | BR LABEL lbl = variable { UncondBranch lbl } - | BR BIT op = operand COMMA LABEL lbl1 = variable COMMA LABEL lbl2 = variable { CondBranch (op, lbl1, lbl2) } - (* - | switch - | indirectbr - | invoke - | resume - | unreachable - *) - binop: | ADD arith_options binop_args { () } | FADD fast_math_flags binop_args { () } diff --git a/infer/src/llvm/lTrans.ml b/infer/src/llvm/lTrans.ml index a860cfb0f..e204091f4 100644 --- a/infer/src/llvm/lTrans.ml +++ b/infer/src/llvm/lTrans.ml @@ -33,15 +33,22 @@ let rec trans_typ : LAst.typ -> Sil.typ = function | Tlabel -> raise (ImproperTypeError "Tried to generate Sil type from LLVM label type.") | Tmetadata -> raise (ImproperTypeError "Tried to generate Sil type from LLVM metadata type.") -let trans_instr (cfg : Cfg.cfg) (pdesc : Cfg.Procdesc.t) : LAst.instr -> Sil.instr list = function +let trans_instr (cfg : Cfg.cfg) (procdesc : Cfg.Procdesc.t) : LAst.instr -> Sil.instr list = + let procname = Cfg.Procdesc.get_proc_name procdesc in + function | Ret None -> [] | Ret (Some (tp, exp)) -> - let ret_var = Sil.get_ret_pvar (Cfg.Procdesc.get_proc_name pdesc) in + let ret_var = Sil.get_ret_pvar procname in [Sil.Set (Sil.Lvar ret_var, trans_typ tp, trans_operand exp, Sil.dummy_location)] | Load (var, tp, ptr) -> [Sil.Letderef (ident_of_variable var, trans_variable ptr, trans_typ tp, Sil.dummy_location)] | Store (op, tp, var) -> [Sil.Set (trans_variable var, trans_typ tp, trans_operand op, Sil.dummy_location)] + | Alloc (var, tp, num_elems, alignment) -> + let mangled_var_name = Mangled.from_string (LAst.string_of_variable var) in + let pvar = Sil.mk_pvar mangled_var_name procname in + (* currently only declare one variable - num_elems is ignored *) + [Sil.Declare_locals ([(pvar, trans_typ (Tptr tp))], Sil.dummy_location)] | _ -> raise (Unimplemented "Need to translate instruction to SIL.") (* Update CFG and call graph with new function definition *) @@ -80,11 +87,9 @@ let trans_func_def (cfg : Cfg.cfg) (cg: Cg.t) : LAst.func_def -> unit = function let start_node = Cfg.Node.create cfg Sil.dummy_location start_kind [] procdesc [] in let exit_kind = Cfg.Node.Exit_node procdesc in let exit_node = Cfg.Node.create cfg Sil.dummy_location exit_kind [] procdesc [] in - let nodekind_of_instr : LAst.instr -> Cfg.Node.nodekind = function - | Ret _ | Load _ | Store _ -> Cfg.Node.Stmt_node "method_body" - | _ -> raise (Unimplemented "Need to get node type for instruction.") in let node_of_instr (cfg : Cfg.cfg) (procdesc : Cfg.Procdesc.t) (instr : LAst.instr) : Cfg.Node.t = - Cfg.Node.create cfg Sil.dummy_location (nodekind_of_instr instr) (trans_instr cfg procdesc instr) procdesc [] in + Cfg.Node.create cfg Sil.dummy_location (Cfg.Node.Stmt_node "method_body") + (trans_instr cfg procdesc instr) procdesc [] in let rec link_nodes (start_node : Cfg.Node.t) : Cfg.Node.t list -> unit = function (* link all nodes in a chain for now *) | [] -> Cfg.Node.set_succs_exn start_node [exit_node] [exit_node]