%% -*- erlang-indent-level: 2 -*-
-module(hipe_llvm).
-export([
mk_ret/1,
ret_ret_list/1,
mk_br/1,
br_dst/1,
mk_br_cond/3,
mk_br_cond/4,
br_cond_cond/1,
br_cond_true_label/1,
br_cond_false_label/1,
br_cond_meta/1,
mk_indirectbr/3,
indirectbr_type/1,
indirectbr_address/1,
indirectbr_label_list/1,
mk_switch/4,
switch_type/1,
switch_value/1,
switch_default_label/1,
switch_value_label_list/1,
mk_invoke/9,
invoke_dst/1,
invoke_cconv/1,
invoke_ret_attrs/1,
invoke_type/1,
invoke_fnptrval/1,
invoke_arglist/1,
invoke_fn_attrs/1,
invoke_to_label/1,
invoke_unwind_label/1,
mk_operation/6,
operation_dst/1,
operation_op/1,
operation_type/1,
operation_src1/1,
operation_src2/1,
operation_options/1,
mk_extractvalue/5,
extractvalue_dst/1,
extractvalue_type/1,
extractvalue_val/1,
extractvalue_idx/1,
extractvalue_idxs/1,
mk_insertvalue/7,
insertvalue_dst/1,
insertvalue_val_type/1,
insertvalue_val/1,
insertvalue_elem_type/1,
insertvalue_elem/1,
insertvalue_idx/1,
insertvalue_idxs/1,
mk_alloca/4,
alloca_dst/1,
alloca_type/1,
alloca_num/1,
alloca_align/1,
mk_load/6,
load_dst/1,
load_p_type/1,
load_pointer/1,
load_alignment/1,
load_nontemporal/1,
load_volatile/1,
mk_store/7,
store_type/1,
store_value/1,
store_p_type/1,
store_pointer/1,
store_alignment/1,
store_nontemporal/1,
store_volatile/1,
mk_getelementptr/5,
getelementptr_dst/1,
getelementptr_p_type/1,
getelementptr_value/1,
getelementptr_typed_idxs/1,
getelementptr_inbounds/1,
mk_conversion/5,
conversion_dst/1,
conversion_op/1,
conversion_src_type/1,
conversion_src/1,
conversion_dst_type/1,
mk_sitofp/4,
sitofp_dst/1,
sitofp_src_type/1,
sitofp_src/1,
sitofp_dst_type/1,
mk_ptrtoint/4,
ptrtoint_dst/1,
ptrtoint_src_type/1,
ptrtoint_src/1,
ptrtoint_dst_type/1,
mk_inttoptr/4,
inttoptr_dst/1,
inttoptr_src_type/1,
inttoptr_src/1,
inttoptr_dst_type/1,
mk_icmp/5,
icmp_dst/1,
icmp_cond/1,
icmp_type/1,
icmp_src1/1,
icmp_src2/1,
mk_fcmp/5,
fcmp_dst/1,
fcmp_cond/1,
fcmp_type/1,
fcmp_src1/1,
fcmp_src2/1,
mk_phi/3,
phi_dst/1,
phi_type/1,
phi_value_label_list/1,
mk_select/6,
select_dst/1,
select_cond/1,
select_typ1/1,
select_val1/1,
select_typ2/1,
select_val2/1,
mk_call/8,
call_dst/1,
call_is_tail/1,
call_cconv/1,
call_ret_attrs/1,
call_type/1,
call_fnptrval/1,
call_arglist/1,
call_fn_attrs/1,
mk_fun_def/10,
fun_def_linkage/1,
fun_def_visibility/1,
fun_def_cconv/1,
fun_def_ret_attrs/1,
fun_def_type/1,
fun_def_name/1,
fun_def_arglist/1,
fun_def_fn_attrs/1,
fun_def_align/1,
fun_def_body/1,
mk_fun_decl/8,
fun_decl_linkage/1,
fun_decl_visibility/1,
fun_decl_cconv/1,
fun_decl_ret_attrs/1,
fun_decl_type/1,
fun_decl_name/1,
fun_decl_arglist/1,
fun_decl_align/1,
mk_landingpad/0,
mk_comment/1,
comment_text/1,
mk_label/1,
label_label/1,
is_label/1,
mk_const_decl/4,
const_decl_dst/1,
const_decl_decl_type/1,
const_decl_type/1,
const_decl_value/1,
mk_asm/1,
asm_instruction/1,
mk_adj_stack/3,
adj_stack_offset/1,
adj_stack_register/1,
adj_stack_type/1,
mk_meta/2,
meta_id/1,
meta_operands/1
]).
-export([
mk_void/0,
mk_label_type/0,
mk_int/1,
int_width/1,
mk_double/0,
mk_pointer/1,
pointer_type/1,
mk_array/2,
array_size/1,
array_type/1,
mk_vector/2,
vector_size/1,
vector_type/1,
mk_struct/1,
struct_type_list/1,
mk_fun/2,
function_ret_type/1,
function_arg_type_list/1
]).
-export([pp_ins_list/3, pp_ins/3]).
%%-----------------------------------------------------------------------------
%% Abstract Data Types for LLVM Assembly.
%%-----------------------------------------------------------------------------
%% Terminator Instructions
-record(llvm_ret, {ret_list=[]}).
-type llvm_ret() :: #llvm_ret{}.
-record(llvm_br, {dst}).
-type llvm_br() :: #llvm_br{}.
-record(llvm_br_cond, {'cond', true_label, false_label, meta=[]}).
-type llvm_br_cond() :: #llvm_br_cond{}.
-record(llvm_indirectbr, {type, address, label_list}).
-type llvm_indirectbr() :: #llvm_indirectbr{}.
-record(llvm_switch, {type, value, default_label, value_label_list=[]}).
-type llvm_switch() :: #llvm_switch{}.
-record(llvm_invoke, {dst, cconv=[], ret_attrs=[], type, fnptrval, arglist=[],
fn_attrs=[], to_label, unwind_label}).
-type llvm_invoke() :: #llvm_invoke{}.
%% Binary Operations
-record(llvm_operation, {dst, op, type, src1, src2, options=[]}).
-type llvm_operation() :: #llvm_operation{}.
%% Aggregate Operations
-record(llvm_extractvalue, {dst, type, val, idx, idxs=[]}).
-type llvm_extractvalue() :: #llvm_extractvalue{}.
-record(llvm_insertvalue, {dst, val_type, val, elem_type, elem, idx, idxs=[]}).
-type llvm_insertvalue() :: #llvm_insertvalue{}.
%% Memory Access and Addressing Operations
-record(llvm_alloca, {dst, type, num=[], align=[]}).
-type llvm_alloca() :: #llvm_alloca{}.
-record(llvm_load, {dst, p_type, pointer, alignment=[], nontemporal=[],
volatile=false}).
-type llvm_load() :: #llvm_load{}.
-record(llvm_store, {type, value, p_type, pointer, alignment=[],
nontemporal=[], volatile=false}).
-type llvm_store() :: #llvm_store{}.
-record(llvm_getelementptr, {dst, p_type, value, typed_idxs, inbounds}).
-type llvm_getelementptr() :: #llvm_getelementptr{}.
%% Conversion Operations
-record(llvm_conversion, {dst, op, src_type, src, dst_type}).
-type llvm_conversion() :: #llvm_conversion{}.
-record(llvm_sitofp, {dst, src_type, src, dst_type}).
-type llvm_sitofp() :: #llvm_sitofp{}.
-record(llvm_ptrtoint, {dst, src_type, src, dst_type}).
-type llvm_ptrtoint() :: #llvm_ptrtoint{}.
-record(llvm_inttoptr, {dst, src_type, src, dst_type}).
-type llvm_inttoptr() :: #llvm_inttoptr{}.
%% Other Operations
-record(llvm_icmp, {dst, 'cond', type, src1, src2}).
-type llvm_icmp() :: #llvm_icmp{}.
-record(llvm_fcmp, {dst, 'cond', type, src1, src2}).
-type llvm_fcmp() :: #llvm_fcmp{}.
-record(llvm_phi, {dst, type, value_label_list}).
-type llvm_phi() :: #llvm_phi{}.
-record(llvm_select, {dst, 'cond', typ1, val1, typ2, val2}).
-type llvm_select() :: #llvm_select{}.
-record(llvm_call, {dst=[], is_tail = false, cconv = [], ret_attrs = [], type,
fnptrval, arglist = [], fn_attrs = []}).
-type llvm_call() :: #llvm_call{}.
-record(llvm_fun_def, {linkage=[], visibility=[], cconv=[], ret_attrs=[],
type, 'name', arglist=[], fn_attrs=[], align=[], body=[]}).
-type llvm_fun_def() :: #llvm_fun_def{}.
-record(llvm_fun_decl, {linkage=[], visibility=[], cconv=[], ret_attrs=[],
type, 'name', arglist=[], align=[]}).
-type llvm_fun_decl() :: #llvm_fun_decl{}.
-record(llvm_landingpad, {}).
-type llvm_landingpad() :: #llvm_landingpad{}.
-record(llvm_comment, {text}).
-type llvm_comment() :: #llvm_comment{}.
-record(llvm_label, {label}).
-type llvm_label() :: #llvm_label{}.
-record(llvm_const_decl, {dst, decl_type, type, value}).
-type llvm_const_decl() :: #llvm_const_decl{}.
-record(llvm_asm, {instruction}).
-type llvm_asm() :: #llvm_asm{}.
-record(llvm_adj_stack, {offset, 'register', type}).
-type llvm_adj_stack() :: #llvm_adj_stack{}.
-record(llvm_meta, {id :: string(),
operands :: [string() | integer() | llvm_meta()]}).
-type llvm_meta() :: #llvm_meta{}.
%% A type for any LLVM instruction
-type llvm_instr() :: llvm_ret() | llvm_br() | llvm_br_cond()
| llvm_indirectbr() | llvm_switch() | llvm_invoke()
| llvm_operation() | llvm_extractvalue()
| llvm_insertvalue() | llvm_alloca() | llvm_load()
| llvm_store() | llvm_getelementptr() | llvm_conversion()
| llvm_sitofp() | llvm_ptrtoint() | llvm_inttoptr()
| llvm_icmp() | llvm_fcmp() | llvm_phi() | llvm_select()
| llvm_call() | llvm_fun_def() | llvm_fun_decl()
| llvm_landingpad() | llvm_comment() | llvm_label()
| llvm_const_decl() | llvm_asm() | llvm_adj_stack()
| llvm_meta().
%% Types
-record(llvm_void, {}).
%-type llvm_void() :: #llvm_void{}.
-record(llvm_label_type, {}).
%-type llvm_label_type() :: #llvm_label_type{}.
-record(llvm_int, {width}).
%-type llvm_int() :: #llvm_int{}.
-record(llvm_float, {}).
%-type llvm_float() :: #llvm_float{}.
-record(llvm_double, {}).
%-type llvm_double() :: #llvm_double{}.
-record(llvm_fp80, {}).
%-type llvm_fp80() :: #llvm_fp80{}.
-record(llvm_fp128, {}).
%-type llvm_fp128() :: #llvm_fp128{}.
-record(llvm_ppc_fp128, {}).
%-type llvm_ppc_fp128() :: #llvm_ppc_fp128{}.
-record(llvm_pointer, {type}).
%-type llvm_pointer() :: #llvm_pointer{}.
-record(llvm_vector, {'size', type}).
%-type llvm_vector() :: #llvm_vector{}.
-record(llvm_struct, {type_list}).
%-type llvm_struct() :: #llvm_struct{}.
-record(llvm_array, {'size', type}).
%-type llvm_array() :: #llvm_array{}.
-record(llvm_fun, {ret_type, arg_type_list}).
%-type llvm_fun() :: #llvm_fun{}.
%%-----------------------------------------------------------------------------
%% Accessor Functions
%%-----------------------------------------------------------------------------
%% ret
mk_ret(Ret_list) -> #llvm_ret{ret_list=Ret_list}.
ret_ret_list(#llvm_ret{ret_list=Ret_list}) -> Ret_list.
%% br
mk_br(Dst) -> #llvm_br{dst=Dst}.
br_dst(#llvm_br{dst=Dst}) -> Dst.
%% br_cond
mk_br_cond(Cond, True_label, False_label) ->
#llvm_br_cond{'cond'=Cond, true_label=True_label, false_label=False_label}.
mk_br_cond(Cond, True_label, False_label, Metadata) ->
#llvm_br_cond{'cond'=Cond, true_label=True_label, false_label=False_label,
meta=Metadata}.
br_cond_cond(#llvm_br_cond{'cond'=Cond}) -> Cond.
br_cond_true_label(#llvm_br_cond{true_label=True_label}) -> True_label.
br_cond_false_label(#llvm_br_cond{false_label=False_label}) ->
False_label.
br_cond_meta(#llvm_br_cond{meta=Metadata}) -> Metadata.
%% indirectbr
mk_indirectbr(Type, Address, Label_list) -> #llvm_indirectbr{type=Type, address=Address, label_list=Label_list}.
indirectbr_type(#llvm_indirectbr{type=Type}) -> Type.
indirectbr_address(#llvm_indirectbr{address=Address}) -> Address.
indirectbr_label_list(#llvm_indirectbr{label_list=Label_list}) -> Label_list.
%% invoke
mk_invoke(Dst, Cconv, Ret_attrs, Type, Fnptrval, Arglist, Fn_attrs, To_label, Unwind_label) ->
#llvm_invoke{dst=Dst, cconv=Cconv, ret_attrs=Ret_attrs, type=Type,
fnptrval=Fnptrval, arglist=Arglist, fn_attrs=Fn_attrs, to_label=To_label,
unwind_label=Unwind_label}.
invoke_dst(#llvm_invoke{dst=Dst}) -> Dst.
invoke_cconv(#llvm_invoke{cconv=Cconv}) -> Cconv.
invoke_ret_attrs(#llvm_invoke{ret_attrs=Ret_attrs}) -> Ret_attrs.
invoke_type(#llvm_invoke{type=Type}) -> Type.
invoke_fnptrval(#llvm_invoke{fnptrval=Fnptrval}) -> Fnptrval.
invoke_arglist(#llvm_invoke{arglist=Arglist}) -> Arglist.
invoke_fn_attrs(#llvm_invoke{fn_attrs=Fn_attrs}) -> Fn_attrs.
invoke_to_label(#llvm_invoke{to_label=To_label}) -> To_label.
invoke_unwind_label(#llvm_invoke{unwind_label=Unwind_label}) -> Unwind_label.
%% switch
mk_switch(Type, Value, Default_label, Value_label_list) ->
#llvm_switch{type=Type, value=Value, default_label=Default_label,
value_label_list=Value_label_list}.
switch_type(#llvm_switch{type=Type}) -> Type.
switch_value(#llvm_switch{value=Value}) -> Value.
switch_default_label(#llvm_switch{default_label=Default_label}) ->
Default_label.
switch_value_label_list(#llvm_switch{value_label_list=Value_label_list}) ->
Value_label_list.
%% operation
mk_operation(Dst, Op, Type, Src1, Src2, Options) ->
#llvm_operation{dst=Dst, op=Op, type=Type, src1=Src1, src2=Src2,
options=Options}.
operation_dst(#llvm_operation{dst=Dst}) -> Dst.
operation_op(#llvm_operation{op=Op}) -> Op.
operation_type(#llvm_operation{type=Type}) -> Type.
operation_src1(#llvm_operation{src1=Src1}) -> Src1.
operation_src2(#llvm_operation{src2=Src2}) -> Src2.
operation_options(#llvm_operation{options=Options}) -> Options.
%% extractvalue
mk_extractvalue(Dst, Type, Val, Idx, Idxs) ->
#llvm_extractvalue{dst=Dst,type=Type,val=Val,idx=Idx,idxs=Idxs}.
extractvalue_dst(#llvm_extractvalue{dst=Dst}) -> Dst.
extractvalue_type(#llvm_extractvalue{type=Type}) -> Type.
extractvalue_val(#llvm_extractvalue{val=Val}) -> Val.
extractvalue_idx(#llvm_extractvalue{idx=Idx}) -> Idx.
extractvalue_idxs(#llvm_extractvalue{idxs=Idxs}) -> Idxs.
%% insertvalue
mk_insertvalue(Dst, Val_type, Val, Elem_type, Elem, Idx, Idxs) ->
#llvm_insertvalue{dst=Dst, val_type=Val_type, val=Val, elem_type=Elem_type,
elem=Elem, idx=Idx, idxs=Idxs}.
insertvalue_dst(#llvm_insertvalue{dst=Dst}) -> Dst.
insertvalue_val_type(#llvm_insertvalue{val_type=Val_type}) -> Val_type.
insertvalue_val(#llvm_insertvalue{val=Val}) -> Val.
insertvalue_elem_type(#llvm_insertvalue{elem_type=Elem_type}) -> Elem_type.
insertvalue_elem(#llvm_insertvalue{elem=Elem}) -> Elem.
insertvalue_idx(#llvm_insertvalue{idx=Idx}) -> Idx.
insertvalue_idxs(#llvm_insertvalue{idxs=Idxs}) -> Idxs.
%% alloca
mk_alloca(Dst, Type, Num, Align) ->
#llvm_alloca{dst=Dst, type=Type, num=Num, align=Align}.
alloca_dst(#llvm_alloca{dst=Dst}) -> Dst.
alloca_type(#llvm_alloca{type=Type}) -> Type.
alloca_num(#llvm_alloca{num=Num}) -> Num.
alloca_align(#llvm_alloca{align=Align}) -> Align.
%% load
mk_load(Dst, Type, Pointer, Alignment, Nontemporal, Volatile) ->
#llvm_load{dst=Dst, p_type=Type, pointer=Pointer, alignment=Alignment,
nontemporal=Nontemporal, volatile=Volatile}.
load_dst(#llvm_load{dst=Dst}) -> Dst.
load_p_type(#llvm_load{p_type=Type}) -> Type.
load_pointer(#llvm_load{pointer=Pointer}) -> Pointer.
load_alignment(#llvm_load{alignment=Alignment}) -> Alignment.
load_nontemporal(#llvm_load{nontemporal=Nontemporal}) -> Nontemporal.
load_volatile(#llvm_load{volatile=Volatile}) -> Volatile.
%% store
mk_store(Type, Value, P_Type, Pointer, Alignment, Nontemporal, Volatile) ->
#llvm_store{type=Type, value=Value, p_type=P_Type, pointer=Pointer, alignment=Alignment,
nontemporal=Nontemporal, volatile=Volatile}.
store_type(#llvm_store{type=Type}) -> Type.
store_value(#llvm_store{value=Value}) -> Value.
store_p_type(#llvm_store{p_type=P_Type}) -> P_Type.
store_pointer(#llvm_store{pointer=Pointer}) -> Pointer.
store_alignment(#llvm_store{alignment=Alignment}) -> Alignment.
store_nontemporal(#llvm_store{nontemporal=Nontemporal}) -> Nontemporal.
store_volatile(#llvm_store{volatile=Volatile}) -> Volatile.
%% getelementptr
mk_getelementptr(Dst, P_Type, Value, Typed_Idxs, Inbounds) ->
#llvm_getelementptr{dst=Dst,p_type=P_Type, value=Value,
typed_idxs=Typed_Idxs, inbounds=Inbounds}.
getelementptr_dst(#llvm_getelementptr{dst=Dst}) -> Dst.
getelementptr_p_type(#llvm_getelementptr{p_type=P_Type}) -> P_Type.
getelementptr_value(#llvm_getelementptr{value=Value}) -> Value.
getelementptr_typed_idxs(#llvm_getelementptr{typed_idxs=Typed_Idxs}) -> Typed_Idxs.
getelementptr_inbounds(#llvm_getelementptr{inbounds=Inbounds}) -> Inbounds.
%% conversion
mk_conversion(Dst, Op, Src_type, Src, Dst_type) ->
#llvm_conversion{dst=Dst, op=Op, src_type=Src_type, src=Src, dst_type=Dst_type}.
conversion_dst(#llvm_conversion{dst=Dst}) -> Dst.
conversion_op(#llvm_conversion{op=Op}) -> Op.
conversion_src_type(#llvm_conversion{src_type=Src_type}) -> Src_type.
conversion_src(#llvm_conversion{src=Src}) -> Src.
conversion_dst_type(#llvm_conversion{dst_type=Dst_type}) -> Dst_type.
%% sitofp
mk_sitofp(Dst, Src_type, Src, Dst_type) ->
#llvm_sitofp{dst=Dst, src_type=Src_type, src=Src, dst_type=Dst_type}.
sitofp_dst(#llvm_sitofp{dst=Dst}) -> Dst.
sitofp_src_type(#llvm_sitofp{src_type=Src_type}) -> Src_type.
sitofp_src(#llvm_sitofp{src=Src}) -> Src.
sitofp_dst_type(#llvm_sitofp{dst_type=Dst_type}) -> Dst_type.
%% ptrtoint
mk_ptrtoint(Dst, Src_Type, Src, Dst_Type) ->
#llvm_ptrtoint{dst=Dst, src_type=Src_Type, src=Src, dst_type=Dst_Type}.
ptrtoint_dst(#llvm_ptrtoint{dst=Dst}) -> Dst.
ptrtoint_src_type(#llvm_ptrtoint{src_type=Src_Type}) -> Src_Type.
ptrtoint_src(#llvm_ptrtoint{src=Src}) -> Src.
ptrtoint_dst_type(#llvm_ptrtoint{dst_type=Dst_Type}) -> Dst_Type .
%% inttoptr
mk_inttoptr(Dst, Src_Type, Src, Dst_Type) ->
#llvm_inttoptr{dst=Dst, src_type=Src_Type, src=Src, dst_type=Dst_Type}.
inttoptr_dst(#llvm_inttoptr{dst=Dst}) -> Dst.
inttoptr_src_type(#llvm_inttoptr{src_type=Src_Type}) -> Src_Type.
inttoptr_src(#llvm_inttoptr{src=Src}) -> Src.
inttoptr_dst_type(#llvm_inttoptr{dst_type=Dst_Type}) -> Dst_Type .
%% icmp
mk_icmp(Dst, Cond, Type, Src1, Src2) ->
#llvm_icmp{dst=Dst,'cond'=Cond,type=Type,src1=Src1,src2=Src2}.
icmp_dst(#llvm_icmp{dst=Dst}) -> Dst.
icmp_cond(#llvm_icmp{'cond'=Cond}) -> Cond.
icmp_type(#llvm_icmp{type=Type}) -> Type.
icmp_src1(#llvm_icmp{src1=Src1}) -> Src1.
icmp_src2(#llvm_icmp{src2=Src2}) -> Src2.
%% fcmp
mk_fcmp(Dst, Cond, Type, Src1, Src2) ->
#llvm_fcmp{dst=Dst,'cond'=Cond,type=Type,src1=Src1,src2=Src2}.
fcmp_dst(#llvm_fcmp{dst=Dst}) -> Dst.
fcmp_cond(#llvm_fcmp{'cond'=Cond}) -> Cond.
fcmp_type(#llvm_fcmp{type=Type}) -> Type.
fcmp_src1(#llvm_fcmp{src1=Src1}) -> Src1.
fcmp_src2(#llvm_fcmp{src2=Src2}) -> Src2.
%% phi
mk_phi(Dst, Type, Value_label_list) ->
#llvm_phi{dst=Dst, type=Type,value_label_list=Value_label_list}.
phi_dst(#llvm_phi{dst=Dst}) -> Dst.
phi_type(#llvm_phi{type=Type}) -> Type.
phi_value_label_list(#llvm_phi{value_label_list=Value_label_list}) ->
Value_label_list.
%% select
mk_select(Dst, Cond, Typ1, Val1, Typ2, Val2) ->
#llvm_select{dst=Dst, 'cond'=Cond, typ1=Typ1, val1=Val1, typ2=Typ2, val2=Val2}.
select_dst(#llvm_select{dst=Dst}) -> Dst.
select_cond(#llvm_select{'cond'=Cond}) -> Cond.
select_typ1(#llvm_select{typ1=Typ1}) -> Typ1.
select_val1(#llvm_select{val1=Val1}) -> Val1.
select_typ2(#llvm_select{typ2=Typ2}) -> Typ2.
select_val2(#llvm_select{val2=Val2}) -> Val2.
%% call
mk_call(Dst, Is_tail, Cconv, Ret_attrs, Type, Fnptrval, Arglist, Fn_attrs) ->
#llvm_call{dst=Dst, is_tail=Is_tail, cconv=Cconv, ret_attrs=Ret_attrs,
type=Type, fnptrval=Fnptrval, arglist=Arglist, fn_attrs=Fn_attrs}.
call_dst(#llvm_call{dst=Dst}) -> Dst.
call_is_tail(#llvm_call{is_tail=Is_tail}) -> Is_tail.
call_cconv(#llvm_call{cconv=Cconv}) -> Cconv.
call_ret_attrs(#llvm_call{ret_attrs=Ret_attrs}) -> Ret_attrs.
call_type(#llvm_call{type=Type}) -> Type.
call_fnptrval(#llvm_call{fnptrval=Fnptrval}) -> Fnptrval.
call_arglist(#llvm_call{arglist=Arglist}) -> Arglist.
call_fn_attrs(#llvm_call{fn_attrs=Fn_attrs}) -> Fn_attrs.
%% fun_def
mk_fun_def(Linkage, Visibility, Cconv, Ret_attrs, Type, Name, Arglist,
Fn_attrs, Align, Body) ->
#llvm_fun_def{
linkage=Linkage,
visibility=Visibility,
cconv=Cconv,
ret_attrs=Ret_attrs,
type=Type,
'name'=Name,
arglist=Arglist,
fn_attrs=Fn_attrs,
align=Align,
body=Body
}.
fun_def_linkage(#llvm_fun_def{linkage=Linkage}) -> Linkage.
fun_def_visibility(#llvm_fun_def{visibility=Visibility}) -> Visibility.
fun_def_cconv(#llvm_fun_def{cconv=Cconv}) -> Cconv .
fun_def_ret_attrs(#llvm_fun_def{ret_attrs=Ret_attrs}) -> Ret_attrs.
fun_def_type(#llvm_fun_def{type=Type}) -> Type.
fun_def_name(#llvm_fun_def{'name'=Name}) -> Name.
fun_def_arglist(#llvm_fun_def{arglist=Arglist}) -> Arglist.
fun_def_fn_attrs(#llvm_fun_def{fn_attrs=Fn_attrs}) -> Fn_attrs.
fun_def_align(#llvm_fun_def{align=Align}) -> Align.
fun_def_body(#llvm_fun_def{body=Body}) -> Body.
%% fun_decl
mk_fun_decl(Linkage, Visibility, Cconv, Ret_attrs, Type, Name, Arglist, Align)->
#llvm_fun_decl{
linkage=Linkage,
visibility=Visibility,
cconv=Cconv,
ret_attrs=Ret_attrs,
type=Type,
'name'=Name,
arglist=Arglist,
align=Align
}.
fun_decl_linkage(#llvm_fun_decl{linkage=Linkage}) -> Linkage.
fun_decl_visibility(#llvm_fun_decl{visibility=Visibility}) -> Visibility.
fun_decl_cconv(#llvm_fun_decl{cconv=Cconv}) -> Cconv .
fun_decl_ret_attrs(#llvm_fun_decl{ret_attrs=Ret_attrs}) -> Ret_attrs.
fun_decl_type(#llvm_fun_decl{type=Type}) -> Type.
fun_decl_name(#llvm_fun_decl{'name'=Name}) -> Name.
fun_decl_arglist(#llvm_fun_decl{arglist=Arglist}) -> Arglist.
fun_decl_align(#llvm_fun_decl{align=Align}) -> Align.
%% landingpad
mk_landingpad() -> #llvm_landingpad{}.
%% comment
mk_comment(Text) -> #llvm_comment{text=Text}.
comment_text(#llvm_comment{text=Text}) -> Text.
%% label
mk_label(Label) -> #llvm_label{label=Label}.
label_label(#llvm_label{label=Label}) -> Label.
-spec is_label(llvm_instr()) -> boolean().
is_label(#llvm_label{}) -> true;
is_label(#llvm_ret{}) -> false;
is_label(#llvm_br{}) -> false;
is_label(#llvm_br_cond{}) -> false;
is_label(#llvm_indirectbr{}) -> false;
is_label(#llvm_switch{}) -> false;
is_label(#llvm_invoke{}) -> false;
is_label(#llvm_operation{}) -> false;
is_label(#llvm_extractvalue{}) -> false;
is_label(#llvm_insertvalue{}) -> false;
is_label(#llvm_alloca{}) -> false;
is_label(#llvm_load{}) -> false;
is_label(#llvm_store{}) -> false;
is_label(#llvm_getelementptr{}) -> false;
is_label(#llvm_conversion{}) -> false;
is_label(#llvm_sitofp{}) -> false;
is_label(#llvm_ptrtoint{}) -> false;
is_label(#llvm_inttoptr{}) -> false;
is_label(#llvm_icmp{}) -> false;
is_label(#llvm_fcmp{}) -> false;
is_label(#llvm_phi{}) -> false;
is_label(#llvm_select{}) -> false;
is_label(#llvm_call{}) -> false;
is_label(#llvm_fun_def{}) -> false;
is_label(#llvm_fun_decl{}) -> false;
is_label(#llvm_landingpad{}) -> false;
is_label(#llvm_comment{}) -> false;
is_label(#llvm_const_decl{}) -> false;
is_label(#llvm_asm{}) -> false;
is_label(#llvm_adj_stack{}) -> false;
is_label(#llvm_meta{}) -> false.
%% const_decl
mk_const_decl(Dst, Decl_type, Type, Value) ->
#llvm_const_decl{dst=Dst, decl_type=Decl_type, type=Type, value=Value}.
const_decl_dst(#llvm_const_decl{dst=Dst}) -> Dst.
const_decl_decl_type(#llvm_const_decl{decl_type=Decl_type}) -> Decl_type.
const_decl_type(#llvm_const_decl{type=Type}) -> Type.
const_decl_value(#llvm_const_decl{value=Value}) -> Value.
%% asm
mk_asm(Instruction) -> #llvm_asm{instruction=Instruction}.
asm_instruction(#llvm_asm{instruction=Instruction}) -> Instruction.
%% adj_stack
mk_adj_stack(Offset, Register, Type) ->
#llvm_adj_stack{offset=Offset, 'register'=Register, type=Type}.
adj_stack_offset(#llvm_adj_stack{offset=Offset}) -> Offset.
adj_stack_register(#llvm_adj_stack{'register'=Register}) -> Register.
adj_stack_type(#llvm_adj_stack{type=Type}) -> Type.
%% meta-data
mk_meta(Id, Operands) ->
#llvm_meta{id=Id, operands=Operands}.
meta_id(#llvm_meta{id=Id}) -> Id.
meta_operands(#llvm_meta{operands=Operands}) -> Operands.
%% types
mk_void() -> #llvm_void{}.
mk_label_type() -> #llvm_label_type{}.
mk_int(Width) -> #llvm_int{width=Width}.
int_width(#llvm_int{width=Width}) -> Width.
mk_double() -> #llvm_double{}.
mk_pointer(Type) -> #llvm_pointer{type=Type}.
pointer_type(#llvm_pointer{type=Type}) -> Type.
mk_array(Size, Type) -> #llvm_array{'size'=Size, type=Type}.
array_size(#llvm_array{'size'=Size}) -> Size.
array_type(#llvm_array{type=Type}) -> Type.
mk_vector(Size, Type) -> #llvm_vector{'size'=Size, type=Type}.
vector_size(#llvm_vector{'size'=Size}) -> Size.
vector_type(#llvm_vector{type=Type}) -> Type.
mk_struct(Type_list) -> #llvm_struct{type_list=Type_list}.
struct_type_list(#llvm_struct{type_list=Type_list}) -> Type_list.
mk_fun(Ret_type, Arg_type_list) ->
#llvm_fun{ret_type=Ret_type, arg_type_list=Arg_type_list}.
function_ret_type(#llvm_fun{ret_type=Ret_type}) -> Ret_type.
function_arg_type_list(#llvm_fun{arg_type_list=Arg_type_list}) ->
Arg_type_list.
%%----------------------------------------------------------------------------
%% Pretty-printer Functions
%%----------------------------------------------------------------------------
-type llvm_version() :: {Major :: integer(), Minor :: integer()}.
%% @doc Pretty-print a list of LLVM instructions to a Device, using syntax
%% compatible with LLVM v. Major.Minor
-spec pp_ins_list(file:io_device(), llvm_version(), [llvm_instr()]) -> ok.
pp_ins_list(_Dev, _Ver, []) -> ok;
pp_ins_list(Dev, Ver={_,_}, [I|Is]) ->
pp_ins(Dev, Ver, I),
pp_ins_list(Dev, Ver, Is).
pp_ins(Dev, Ver, I) ->
case indent(I) of
true -> write(Dev, " ");
false -> ok
end,
case I of
#llvm_ret{} ->
write(Dev, "ret "),
case ret_ret_list(I) of
[] -> write(Dev, "void");
List -> pp_args(Dev, List)
end,
write(Dev, "\n");
#llvm_br{} ->
write(Dev, ["br label ", br_dst(I), "\n"]);
#llvm_switch{} ->
write(Dev, "switch "),
pp_type(Dev, switch_type(I)),
write(Dev, [" ", switch_value(I), ", label ", switch_default_label(I),
" \n [\n"]),
pp_switch_value_label_list(Dev, switch_type(I),
switch_value_label_list(I)),
write(Dev, " ]\n");
#llvm_invoke{} ->
write(Dev, [invoke_dst(I), " = invoke ", invoke_cconv(I), " "]),
pp_options(Dev, invoke_ret_attrs(I)),
pp_type(Dev, invoke_type(I)),
write(Dev, [" ", invoke_fnptrval(I), "("]),
pp_args(Dev, invoke_arglist(I)),
write(Dev, ") "),
pp_options(Dev, invoke_fn_attrs(I)),
write(Dev, [" to label ", invoke_to_label(I)," unwind label ",
invoke_unwind_label(I), " \n"]);
#llvm_br_cond{} ->
write(Dev, ["br i1 ", br_cond_cond(I), ", label ", br_cond_true_label(I),
", label ", br_cond_false_label(I)]),
case br_cond_meta(I) of
[] -> ok;
Metadata ->
write(Dev, [", !prof !", Metadata])
end,
write(Dev, "\n");
#llvm_indirectbr{} ->
write(Dev, "indirectbr "),
pp_type(Dev, indirectbr_type(I)),
write(Dev, [" ", indirectbr_address(I), ", [ "]),
pp_args(Dev, indirectbr_label_list(I)),
write(Dev, " ]\n");
#llvm_operation{} ->
write(Dev, [operation_dst(I), " = ", atom_to_list(operation_op(I)), " "]),
case op_has_options(operation_op(I)) of
true -> pp_options(Dev, operation_options(I));
false -> ok
end,
pp_type(Dev, operation_type(I)),
write(Dev, [" ", operation_src1(I), ", ", operation_src2(I), "\n"]);
#llvm_extractvalue{} ->
write(Dev, [extractvalue_dst(I), " = extractvalue "]),
pp_type(Dev, extractvalue_type(I)),
%% TODO Print idxs
write(Dev, [" ", extractvalue_val(I), ", ", extractvalue_idx(I), "\n"]);
#llvm_insertvalue{} ->
write(Dev, [insertvalue_dst(I), " = insertvalue "]),
pp_type(Dev, insertvalue_val_type(I)),
write(Dev, [" ", insertvalue_val(I), ", "]),
pp_type(Dev, insertvalue_elem_type(I)),
%%TODO Print idxs
write(Dev, [" ", insertvalue_elem(I), ", ", insertvalue_idx(I), "\n"]);
#llvm_alloca{} ->
write(Dev, [alloca_dst(I), " = alloca "]),
pp_type(Dev, alloca_type(I)),
case alloca_num(I) of
[] -> ok;
Num ->
write(Dev, ", "),
pp_type(Dev, alloca_type(I)),
write(Dev, [" ", Num, " "])
end,
case alloca_align(I) of
[] -> ok;
Align -> write(Dev, [",align ", Align])
end,
write(Dev, "\n");
#llvm_load{} ->
write(Dev, [load_dst(I), " = "]),
write(Dev, "load "),
case load_volatile(I) of
true -> write(Dev, "volatile ");
false -> ok
end,
pp_dereference_type(Dev, load_p_type(I)),
write(Dev, [" ", load_pointer(I), " "]),
case load_alignment(I) of
[] -> ok;
Al -> write(Dev, [", align ", Al, " "])
end,
case load_nontemporal(I) of
[] -> ok;
In -> write(Dev, [", !nontemporal !", In])
end,
write(Dev, "\n");
#llvm_store{} ->
write(Dev, "store "),
case store_volatile(I) of
true -> write(Dev, "volatile ");
false -> ok
end,
pp_type(Dev, store_type(I)),
write(Dev, [" ", store_value(I), ", "]),
pp_type(Dev, store_p_type(I)),
write(Dev, [" ", store_pointer(I), " "]),
case store_alignment(I) of
[] -> ok;
Al -> write(Dev, [", align ", Al, " "])
end,
case store_nontemporal(I) of
[] -> ok;
In -> write(Dev, [", !nontemporal !", In])
end,
write(Dev, "\n");
#llvm_getelementptr{} ->
write(Dev, [getelementptr_dst(I), " = getelementptr "]),
case getelementptr_inbounds(I) of
true -> write(Dev, "inbounds ");
false -> ok
end,
pp_dereference_type(Dev, getelementptr_p_type(I)),
write(Dev, [" ", getelementptr_value(I)]),
pp_typed_idxs(Dev, getelementptr_typed_idxs(I)),
write(Dev, "\n");
#llvm_conversion{} ->
write(Dev, [conversion_dst(I), " = ", atom_to_list(conversion_op(I)), " "]),
pp_type(Dev, conversion_src_type(I)),
write(Dev, [" ", conversion_src(I), " to "]),
pp_type(Dev, conversion_dst_type(I)),
write(Dev, "\n");
#llvm_icmp{} ->
write(Dev, [icmp_dst(I), " = icmp ", atom_to_list(icmp_cond(I)), " "]),
pp_type(Dev, icmp_type(I)),
write(Dev, [" ", icmp_src1(I), ", ", icmp_src2(I), "\n"]);
#llvm_fcmp{} ->
write(Dev, [fcmp_dst(I), " = fcmp ", atom_to_list(fcmp_cond(I)), " "]),
pp_type(Dev, fcmp_type(I)),
write(Dev, [" ", fcmp_src1(I), ", ", fcmp_src2(I), "\n"]);
#llvm_phi{} ->
write(Dev, [phi_dst(I), " = phi "]),
pp_type(Dev, phi_type(I)),
pp_phi_value_labels(Dev, phi_value_label_list(I)),
write(Dev, "\n");
#llvm_select{} ->
write(Dev, [select_dst(I), " = select i1 ", select_cond(I), ", "]),
pp_type(Dev, select_typ1(I)),
write(Dev, [" ", select_val1(I), ", "]),
pp_type(Dev, select_typ2(I)),
write(Dev, [" ", select_val2(I), "\n"]);
#llvm_call{} ->
case call_dst(I) of
[] -> ok;
Dst -> write(Dev, [Dst, " = "])
end,
case call_is_tail(I) of
true -> write(Dev, "tail ");
false -> ok
end,
write(Dev, ["call ", call_cconv(I), " "]),
pp_options(Dev, call_ret_attrs(I)),
pp_type(Dev, call_type(I)),
write(Dev, [" ", call_fnptrval(I), "("]),
pp_args(Dev, call_arglist(I)),
write(Dev, ") "),
pp_options(Dev, call_fn_attrs(I)),
write(Dev, "\n");
#llvm_fun_def{} ->
write(Dev, "define "),
pp_options(Dev, fun_def_linkage(I)),
pp_options(Dev, fun_def_visibility(I)),
case fun_def_cconv(I) of
[] -> ok;
Cc -> write(Dev, [Cc, " "])
end,
pp_options(Dev, fun_def_ret_attrs(I)),
write(Dev, " "),
pp_type(Dev, fun_def_type(I)),
write(Dev, [" @", fun_def_name(I), "("]),
pp_args(Dev, fun_def_arglist(I)),
write(Dev, ") "),
pp_options(Dev, fun_def_fn_attrs(I)),
write(Dev, "personality i32 (i32, i64, i8*,i8*)* "
"@__gcc_personality_v0 "),
case fun_def_align(I) of
[] -> ok;
N -> write(Dev, ["align ", N])
end,
write(Dev, "{\n"),
pp_ins_list(Dev, Ver, fun_def_body(I)),
write(Dev, "}\n");
#llvm_fun_decl{} ->
write(Dev, "declare "),
pp_options(Dev, fun_decl_linkage(I)),
pp_options(Dev, fun_decl_visibility(I)),
case fun_decl_cconv(I) of
[] -> ok;
Cc -> write(Dev, [Cc, " "])
end,
pp_options(Dev, fun_decl_ret_attrs(I)),
pp_type(Dev, fun_decl_type(I)),
write(Dev, [" ", fun_decl_name(I), "("]),
pp_type_list(Dev, fun_decl_arglist(I)),
write(Dev, ") "),
case fun_decl_align(I) of
[] -> ok;
N -> write(Dev, ["align ", N])
end,
write(Dev, "\n");
#llvm_comment{} ->
write(Dev, ["; ", atom_to_list(comment_text(I)), "\n"]);
#llvm_label{} ->
write(Dev, [label_label(I), ":\n"]);
#llvm_const_decl{} ->
write(Dev, [const_decl_dst(I), " = ", const_decl_decl_type(I), " "]),
pp_type(Dev, const_decl_type(I)),
write(Dev, [" ", const_decl_value(I), "\n"]);
#llvm_landingpad{} ->
write(Dev, "landingpad { i8*, i32 } cleanup\n");
#llvm_asm{} ->
write(Dev, [asm_instruction(I), "\n"]);
#llvm_adj_stack{} ->
write(Dev, ["call void asm sideeffect \"sub $0, ",
adj_stack_register(I), "\", \"r\"("]),
pp_type(Dev, adj_stack_type(I)),
write(Dev, [" ", adj_stack_offset(I),")\n"]);
#llvm_meta{} ->
write(Dev, ["!", meta_id(I), " = !{ "]),
write(Dev, string:join([if is_list(Op) -> ["!\"", Op, "\""];
is_integer(Op) -> ["i32 ", integer_to_list(Op)];
is_record(Op, llvm_meta) ->
["!", meta_id(Op)]
end || Op <- meta_operands(I)], ", ")),
write(Dev, " }\n");
Other ->
exit({?MODULE, pp_ins, {"Unknown LLVM instruction", Other}})
end.
%% @doc Print the type of a dereference in an LLVM instruction.
pp_dereference_type(Dev, Type) ->
pp_type(Dev, pointer_type(Type)),
write(Dev, ", "),
pp_type(Dev, Type).
%% @doc Pretty-print a list of types
pp_type_list(_Dev, []) -> ok;
pp_type_list(Dev, [T]) ->
pp_type(Dev, T);
pp_type_list(Dev, [T|Ts]) ->
pp_type(Dev, T),
write(Dev, ", "),
pp_type_list(Dev, Ts).
pp_type(Dev, Type) ->
case Type of
#llvm_void{} ->
write(Dev, "void");
#llvm_label_type{} ->
write(Dev, "label");
%% Integer
#llvm_int{} ->
write(Dev, ["i", integer_to_list(int_width(Type))]);
%% Float
#llvm_float{} ->
write(Dev, "float");
#llvm_double{} ->
write(Dev, "double");
#llvm_fp80{} ->
write(Dev, "x86_fp80");
#llvm_fp128{} ->
write(Dev, "fp128");
#llvm_ppc_fp128{} ->
write(Dev, "ppc_fp128");
%% Pointer
#llvm_pointer{} ->
pp_type(Dev, pointer_type(Type)),
write(Dev, "*");
%% Function
#llvm_fun{} ->
pp_type(Dev, function_ret_type(Type)),
write(Dev, " ("),
pp_type_list(Dev, function_arg_type_list(Type)),
write(Dev, ")");
%% Aggregate
#llvm_array{} ->
write(Dev, ["[", integer_to_list(array_size(Type)), " x "]),
pp_type(Dev, array_type(Type)),
write(Dev, "]");
#llvm_struct{} ->
write(Dev, "{"),
pp_type_list(Dev, struct_type_list(Type)),
write(Dev, "}");
#llvm_vector{} ->
write(Dev, ["{", integer_to_list(vector_size(Type)), " x "]),
pp_type(Dev, vector_type(Type)),
write(Dev, "}")
end.
%% @doc Pretty-print a list of typed arguments
pp_args(_Dev, []) -> ok;
pp_args(Dev, [{Type, Arg} | []]) ->
pp_type(Dev, Type),
write(Dev, [" ", Arg]);
pp_args(Dev, [{Type, Arg} | Args]) ->
pp_type(Dev, Type),
write(Dev, [" ", Arg, ", "]),
pp_args(Dev, Args).
%% @doc Pretty-print a list of options
pp_options(_Dev, []) -> ok;
pp_options(Dev, [O|Os]) ->
write(Dev, [atom_to_list(O), " "]),
pp_options(Dev, Os).
%% @doc Pretty-print a list of phi value-labels
pp_phi_value_labels(_Dev, []) -> ok;
pp_phi_value_labels(Dev, [{Value, Label}|[]]) ->
write(Dev, ["[ ", Value, ", ", Label, " ]"]);
pp_phi_value_labels(Dev,[{Value, Label}|VL]) ->
write(Dev, ["[ ", Value, ", ", Label, " ], "]),
pp_phi_value_labels(Dev, VL).
%% @doc Pretty-print a list of typed indexes
pp_typed_idxs(_Dev, []) -> ok;
pp_typed_idxs(Dev, [{Type, Id} | Tids]) ->
write(Dev, ", "),
pp_type(Dev, Type),
write(Dev, [" ", Id]),
pp_typed_idxs(Dev, Tids).
%% @doc Pretty-print a switch label list
pp_switch_value_label_list(_Dev, _Type, []) -> ok;
pp_switch_value_label_list(Dev, Type, [{Value, Label} | VLs]) ->
write(Dev, " "),
pp_type(Dev, Type),
write(Dev, [" ", Value, ", label ", Label, "\n"]),
pp_switch_value_label_list(Dev, Type, VLs).
%%----------------------------------------------------------------------------
%% Auxiliary Functions
%%----------------------------------------------------------------------------
%% @doc Returns if an instruction needs to be intended
indent(I) ->
case I of
#llvm_label{} -> false;
#llvm_fun_def{} -> false;
#llvm_fun_decl{} -> false;
#llvm_const_decl{} -> false;
#llvm_meta{} -> false;
_ -> true
end.
op_has_options(Op) ->
case Op of
'and' -> false;
'or' -> false;
'xor' -> false;
_ -> true
end.
%% @doc Abstracts actual writing to file operations
write(Dev, Msg) ->
ok = file:write(Dev, Msg).