let promote_variable t parameter_list f =
let address_of_variable, max_temp_id = get_address_of f in
let declaration = hoist_declaration max_temp_id f in
let max_temp_id = max_temp_id + List.length declaration in
let environment = Array.create (max_temp_id * 2) null_variable_attribute in
let variable_map = Hashtbl.create 32 in
let variable_counter = ref (max_temp_id + 1) in
let new_temp_id() =
let n = !variable_counter in
incr variable_counter;
n
in
let promote s =
try
Hashtbl.find variable_map s
with Not_found ->
let n = new_temp_id() in
Hashtbl.add variable_map s n;
n
in
let promote_lvalue = function
ILlvPtr _ as v -> v
| ILlvVar( s, _ ) as v ->
if Hashtbl.mem address_of_variable s then
v
else
ILlvTemp (promote s)
| ILlvTemp _ as v -> v
in
let promote_expression = function
ILexpCoerce _ as e -> e
| ILexpConstant _ as e -> e
| ILexpBinop _ as e -> e
| ILexpUnaryop _ as e -> e
| ILexpInvoke( v, l ) -> ILexpInvoke( promote_lvalue v, l )
| ILexpAddress _ as e -> e
| ILexpArgument _ as e -> e
| ILexpIdent _ as e -> e
in
let rec promote_statement = function
[] -> []
| i::l ->
match i.il1_t with
IL1stmtDeclAutoScalar _ -> assert false
| IL1stmtDeclBulk( c, t, s, i ) ->
begin
match promote_lvalue (ILlvVar( s, t )) with
ILlvTemp n -> ILstmtInitialize( n, t, i )::promote_statement l
| lv ->
let n = new_temp_id() in
ILstmtRead( n, t, lv, [] )
::ILstmtInitialize( n, t, i )
::promote_statement l
end
| IL1stmtSequence statement_list ->
ILstmtSequence (promote_statement statement_list)
::promote_statement l
| IL1stmtParallel statement_list ->
ILstmtParallel (promote_statement statement_list)
::promote_statement l
| IL1stmtIf( c, n, m ) -> ILstmtIf( c, n, m )::promote_statement l
| IL1stmtSwitch( n, jump_table ) ->
ILstmtSwitch( n, jump_table )::promote_statement l
| IL1stmtGoto n -> ILstmtGoto n::promote_statement l
| IL1stmtReturn n -> ILstmtReturn n::promote_statement l
| IL1stmtDefTemp( n, t, e ) ->
ILstmtAssign( n, t, e )::promote_statement l
| IL1stmtReadToTemp( n, t, v, field_list ) ->
begin
match promote_lvalue v, field_list with
ILlvTemp m, [] -> ILstmtAssign( n, t, ILexpIdent m )
| lv, _ -> ILstmtRead( n, t, lv, field_list )
end
::promote_statement l
| IL1stmtWrite( ILlvVar( _, t ) as lv, field_list, n ) ->
begin
match promote_lvalue lv, field_list with
ILlvTemp m, [] -> ILstmtAssign( m, t, ILexpIdent n )
| lv, _ -> ILstmtWrite( lv, field_list, n )
end
::promote_statement l
| IL1stmtWrite( ILlvPtr _ as lv, field_list, n ) ->
ILstmtWrite( lv, field_list, n )::promote_statement l
| IL1stmtWrite _ -> assert false
in
let f =
Array.map (function b ->
{
predecessor = b.Il1.predecessor;
successor = b.Il1.successor;
immediate_dominator = b.Il1.immediate_dominator;
nest_level = 0;
phi_function = [];
code = promote_statement b.Il1.code
}) f
in
let parameter_type_list = match_parameter_type t.ct_ty parameter_list in
let rec make_parameter_initialization i = function
[] -> []
| ( s, t )::l ->
try
let n = Hashtbl.find variable_map s in
environment.(n) <-
{ original_name = Some s; variable_type = t; storage_class = FuncArgs };
ILstmtAssign( n, t, ILexpArgument i )::make_parameter_initialization (i + 1) l
with Not_found ->
let n = new_temp_id() in
environment.(n) <-
{ original_name = Some s; variable_type = t; storage_class = FuncArgs };
ILstmtAssign( n, t, ILexpArgument i )
::ILstmtWrite( ILlvVar( s, t ), [], n )
::make_parameter_initialization (i + 1) l
in
let set_environment( c, t, s ) =
try
let n = Hashtbl.find variable_map s in
environment.(n) <-
{ original_name = Some s; variable_type = t; storage_class = c }
with Not_found -> ()
in
List.iter set_environment declaration;
f.(0).code <- (make_parameter_initialization 0 parameter_type_list)@f.(0).code;
f, Array.sub environment 0 (!variable_counter)