1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
%% Filename : hipe_sparc_linker.erl
3
%% Module : hipe_sparc_linker
4
%% History : * 2000-10-30 Erik Johansson (happi@csd.uu.se):
8
%% $Date: 2002/11/05 12:22:43 $
10
%% ====================================================================
13
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15
-module(hipe_sparc_linker).
16
-export([pack_constants/1, preprocess/5, assemble/3]).
18
-include("../../kernel/src/hipe_ext_format.hrl").
19
-include("../main/hipe.hrl").
20
-include("../rtl/hipe_literals.hrl").
21
%%=====================================================================
24
%% Move to sparc_assembler...
25
assemble(Code,Map,ConstMap) ->
27
init_export_map(Map), %% Convert to more efficent
28
init_const_map(ConstMap), %% datastructures.
31
assemble1([{MFA,Hot,Cold}|Rest],HAddr,CAddr,Map,ConstMap,AccHCode,AccCCode,AccHRefs,AccCRefs) ->
32
%% io:format("Assembling ~w\n",[MFA]),
33
{HCode,NewHAddr,HRefs} =
34
assemble(Hot,MFA,HAddr,
35
local_labels(MFA,Map),
36
ConstMap,AccHRefs,[],hot),
37
{CCode,NewCAddr,CRefs} = assemble(Cold,MFA,CAddr,
38
local_labels(MFA,Map),
39
ConstMap,AccCRefs,[],cold),
40
assemble1(Rest,NewHAddr,NewCAddr,Map,ConstMap,AccHCode++HCode,AccCCode++CCode,HRefs,CRefs);
41
assemble1([],HAddr,CAddr,_Map,_ConstMap,AccHCode,AccCCode,AccHRefs,AccCRefs) ->
42
{HAddr,CAddr,AccHCode,AccCCode,AccHRefs,AccCRefs}.
44
assemble([I|Is],MFA,Addr,Map,ConstMap,Refs,Code,Seg) ->
45
Type = hipe_sparc:type(I),
49
call_link -> resolve_call_link(I,Addr,Refs,MFA,Map,Seg);
50
b -> resolve_b(I,Addr,Refs,MFA,Map,Seg);
51
goto -> resolve_goto(I,Addr,Refs,MFA,Map,Seg);
52
load_address -> resolve_load_address(I,Addr,Refs,MFA,Map,ConstMap);
53
load_atom -> resolve_load_atom(I,Addr,Refs,MFA,Map);
54
load_word_index -> resolve_load_word_index(I,Addr,Refs,MFA,Map,ConstMap);
55
alu -> {hipe_sparc_assemble:assemble_alu(I),Addr+4,Refs};
56
alu_cc -> {hipe_sparc_assemble:assemble_alu_cc(I),Addr+4,Refs};
57
store -> {hipe_sparc_assemble:assemble_store(I),Addr+4,Refs};
58
move -> {hipe_sparc_assemble:assemble_move(I),Addr+4,Refs};
59
load -> {hipe_sparc_assemble:assemble_load(I),Addr+4,Refs};
60
store_fp -> {hipe_sparc_assemble:assemble_store_fp(I),Addr+4,Refs};
61
load_fp -> {hipe_sparc_assemble:assemble_load_fp(I),Addr+4,Refs};
62
fb -> {hipe_sparc_assemble:assemble_fb(I),Addr+4,Refs};
63
fop -> {hipe_sparc_assemble:assemble_fop(I),Addr+4,Refs};
64
fcmp -> {hipe_sparc_assemble:assemble_fcmp(I),Addr+4,Refs};
65
fmov -> {hipe_sparc_assemble:assemble_fmov(I),Addr+4,Refs};
66
conv_fp -> {hipe_sparc_assemble:assemble_conv_fp(I),Addr+4,Refs};
67
jmp -> {hipe_sparc_assemble:assemble_jmp(I),Addr+4,Refs};
68
nop -> {hipe_sparc_assemble:assemble_nop(I),Addr+4,Refs};
69
sethi -> {hipe_sparc_assemble:assemble_sethi(I),Addr+4,Refs};
70
Other -> exit({bad_type,Other})
72
{[I1,I2],NewAddr,NewRefs} ->
73
assemble(Is,MFA,NewAddr,Map,ConstMap,NewRefs,[I1,I2|Code],Seg);
74
{C,NewAddr,NewRefs} ->
75
assemble(Is,MFA,NewAddr,Map,ConstMap,NewRefs,[C|Code],Seg)
77
assemble([],_,Addr,_,_,Refs,Code,_) ->
78
{lists:reverse(Code),Addr,Refs}.
80
resolve_load_address(Instr,Addr,Refs,MFA,Map,ConstMap)->
81
Dest = hipe_sparc:load_address_dest(Instr),
82
Address = hipe_sparc:load_address_address(Instr),
84
case hipe_sparc:load_address_type(Instr) of
86
{Zone,Offset} = find(Address, Map),
87
[{?PATCH_TYPE2EXT(load_address),
89
{label,Zone,Offset,MFA}}];
91
case lists:member(local,hipe_sparc:info(Instr)) of
92
true -> %% local enter
93
[{?PATCH_TYPE2EXT(load_address),
94
Addr, {local_function,Address}}];
95
false -> %% remote enter
96
[{?PATCH_TYPE2EXT(load_address),
97
Addr, {remote_function,Address}}]
100
ConstNo = find_const({MFA,Address},ConstMap),
101
[{?PATCH_TYPE2EXT(load_address),
102
Addr, {const, ConstNo}}];
104
[{?PATCH_TYPE2EXT(load_address),
105
Addr, {closure, Address}}];
107
[{?PATCH_TYPE2EXT(load_address),
108
Addr, {c_const, Address}}];
110
exit([{problem,{not_handled,{address,Type}}},{at,Instr}])
113
Hi = hipe_sparc:mk_imm(0),
114
Lo = hipe_sparc:mk_imm(0),
115
I1 = hipe_sparc:sethi_create(Dest,Hi,[]),
116
I2 = hipe_sparc:alu_create(Dest,Dest,'or',Lo,[]),
119
hipe_sparc_assemble:assemble_instr(alu,I2),
120
hipe_sparc_assemble:assemble_instr(sethi,I1)],
124
resolve_goto(I,Addr,Refs,_MFA,Map,Seg) ->
125
Dest = hipe_sparc:goto_label(I),
126
{DestSeg,Address} = find(Dest,Map),
127
RelDest = (Address - Addr) div 4,
129
case catch hipe_sparc_assert:check_branch_length(RelDest) of
131
{'EXIT',{too_long_branch,Length}} ->
132
exit([{problem,too_long_branch},
136
NewI = hipe_sparc:goto_label_update(I,RelDest),
137
Code = hipe_sparc_assemble:assemble_instr(goto,NewI),
140
NewI = hipe_sparc:goto_label_update(I,0),
141
Code = hipe_sparc_assemble:assemble_instr(goto,NewI),
142
{Code,Addr+4,[{goto,Addr,{DestSeg,Address}}|Refs]}
145
resolve_b(I,Addr,Refs,_MFA,Map,Seg) ->
146
Dest = hipe_sparc:b_label(I),
147
{DestSeg,Address} = find(Dest,Map),
148
RelDest = (Address - Addr) div 4,
150
case catch hipe_sparc_assert:check_branch_length(RelDest) of
152
{'EXIT',{too_long_branch,Length}} ->
153
exit([{problem,too_long_branch},
157
NewI = hipe_sparc:b_label_update(I,RelDest),
158
Code = hipe_sparc_assemble:assemble_instr(b,NewI),
161
NewI = hipe_sparc:b_label_update(I,0),
162
Code = hipe_sparc_assemble:assemble_instr(b,NewI),
163
{Code,Addr+4,[{b,Addr,{DestSeg,Address}}|Refs]}
166
resolve_load_atom(Instr,Addr,Refs,_MFA,_Map)->
167
Atom = hipe_sparc:load_atom_atom(Instr),
168
Dest = hipe_sparc:load_atom_dest(Instr),
169
Info = hipe_sparc:info(Instr),
170
I1 = hipe_sparc:sethi_create(Dest,
171
hipe_sparc:mk_imm(0),Info),
172
I2 = hipe_sparc:alu_create(Dest,Dest, 'or',
173
hipe_sparc:mk_imm(0),Info),
174
{[hipe_sparc_assemble:assemble_instr(alu,I2),
175
hipe_sparc_assemble:assemble_instr(sethi,I1)],
176
Addr+8,[{?PATCH_TYPE2EXT(load_atom),Addr, Atom}|Refs]}.
178
resolve_load_word_index(_Instr,_Addr,_Refs,_MFA,_Map,_ConstMap) ->
179
?EXIT({nyi,resolve_load_word_index}).
180
%% Index =hipe_sparc:load_word_index_index(Instr),
181
%% Block =hipe_sparc:load_word_index_block(Instr),
182
%% Dest = hipe_sparc:load_word_index_dest(Instr),
183
%% Info = hipe_sparc:info(Instr),
185
%% ConstNo = find_const({MFA,Block},ConstMap),
186
%% I1 = hipe_sparc:sethi_create(Dest,
187
%% hipe_sparc:mk_imm(0),Info),
188
%% I2 = hipe_sparc:alu_create(Dest,Dest, 'or',
189
%% hipe_sparc:mk_imm(0),Info),
190
%% {[hipe_sparc_assemble:assemble_instr(alu,I2),
191
%% hipe_sparc_assemble:assemble_instr(sethi,I1)],
192
%% Addr+8,[{?PATCH_TYPE2EXT(load_word_index),Addr, {word_index, ConstNo, Index}}|Refs]}.
194
resolve_call_link(Instr,Addr,OldRefs,_MFA,Map,_Seg)->
195
Target = hipe_sparc:call_link_target(Instr),
196
ExnLab = hipe_sparc:call_link_fail(Instr),
199
%% Get the stack descriptor information
200
SD = hipe_sparc:call_link_stack_desc(Instr),
201
FSize = hipe_sparc_stack_descriptors:get_size(SD),
202
Live = list_to_tuple(hipe_sparc_stack_descriptors:get_live(SD)),
203
Arity = case hipe_sparc_stack_descriptors:get_arity(SD) of
204
N when N > ?SPARC_ARGS_IN_REGS -> N - ?SPARC_ARGS_IN_REGS;
209
[] -> []; % don't cons up a new one
210
_ -> find(ExnLab,Map)
213
%% The stack descriptor needs to be inserted into the system at load-time.
215
[{?PATCH_TYPE2EXT(sdesc),
217
?STACK_DESC(ExnRA, FSize, Arity, Live)} | OldRefs],
219
case hipe_sparc:call_link_type(Instr) of
221
NewI = hipe_sparc:jmp_link_create(
222
hipe_sparc:call_link_target(Instr),
223
hipe_sparc:mk_imm(0),
224
hipe_sparc:mk_reg(hipe_sparc_registers:return_address()),
225
hipe_sparc:call_link_args(Instr),
226
hipe_sparc:info(Instr)),
227
Code = hipe_sparc_assemble:assemble_instr(jmp_link,NewI),
231
case lists:member(local,hipe_sparc:info(Instr)) of
232
true -> %% local call
233
[{?PATCH_TYPE2EXT(call_local),
234
Addr, Target} | Refs];
236
[{?PATCH_TYPE2EXT(call_remote),
237
Addr, Target} | Refs]
239
NewI = hipe_sparc:call_link_target_update(Instr,0),
240
Code = hipe_sparc_assemble:assemble_instr(call_link,NewI),
241
{Code,Addr+4,NewRefs}
249
preprocess({{Block,Entry},Rest},MFA,HotAddress,ColdAddress,Map) ->
250
%% io:format("~w at ~w ~w\n",[MFA,HotAddress,ColdAddress]),
251
process([{Block,Entry}|Rest],[],[],HotAddress,ColdAddress,
262
process([{Block,Code}|Rest],Hot,Cold,HotSize,ColdSize,Map,MFA) ->
266
{NewCode,NewSize,NewMap} = process_instr(Code,HotSize,Map,MFA,[],hot),
267
process(Rest,NewCode++Hot,Cold,NewSize,ColdSize,NewMap,MFA);
269
{NewCode,NewSize,NewMap} = process_instr(Code,ColdSize,Map,MFA,[],cold),
270
process(Rest,Hot,NewCode++Cold,HotSize,NewSize,NewMap,MFA)
272
process([],Hot,Cold,HotSize,ColdSize,Map,_) ->
273
{Hot,Cold,HotSize,ColdSize,Map}.
275
process_instr([I|Is],Size,Map,MFA,AccCode,Block) ->
276
case hipe_sparc:type(I) of
278
process_instr(Is,Size,[{{MFA,hipe_sparc:label_name(I)},Block,Size}|Map],MFA,AccCode,Block);
280
process_instr(Is,Size,Map,MFA,AccCode,Block);
282
process_instr(Is,Size+8,Map,MFA,[I|AccCode],Block);
284
process_instr(Is,Size+8,Map,MFA,[I|AccCode],Block);
286
process_instr(Is,Size+8,Map,MFA,[I|AccCode],Block);
288
process_instr(Is,Size+4,Map,MFA,[I|AccCode],Block)
290
process_instr([],Size,Map,_,Code,_) ->
291
{lists:reverse(Code),Size,Map}.
296
pack_constants(Data) ->
297
pack_constants(Data,0,0,[],[]).
299
pack_constants([{MFA,_,ConstTab}|Rest],AccSize,ConstNo,Acc,Refs) ->
300
Labels = hipe_consttab:labels(ConstTab),
301
%% RefToLabels = hipe_consttab:referred_labels(ConstTab),
302
{Size, Map, NewConstNo, RefToLabels} =
303
pack_labels(Labels,MFA,ConstTab,AccSize, ConstNo,[], []),
307
_ -> [{MFA,RefToLabels}| Refs]
310
pack_constants(Rest, Size, NewConstNo,
312
pack_constants([], Size, _, Acc, Refs) -> {Size, Acc, Refs}.
314
pack_labels([{_Label,ref}|Labels],MFA,ConstTab,AccSize, ConstNo, Acc, Refs) ->
315
pack_labels(Labels,MFA,ConstTab,AccSize, ConstNo, Acc, Refs);
316
pack_labels([Label|Labels],MFA,ConstTab,AccSize, ConstNo, Acc, Refs) ->
317
Const = hipe_consttab:lookup(Label,ConstTab),
318
Size = hipe_consttab:const_size(Const),
319
Align = hipe_consttab:const_align(Const),
321
case AccSize rem Align of
324
N -> AccSize + (Align -N)
326
Need = Size, %% Do we need to consider alignment?
327
%% io:format("Const ~w, Size ~w, Need ~w\n",[Const,Size,Need]),
328
RawType = hipe_consttab:const_type(Const),
329
Type = ?CONST_TYPE2EXT(RawType),
330
RawData = hipe_consttab:const_data(Const),
333
term -> {RawData,[]};
334
sorted_block -> {RawData, []};
337
{ElementType, ElementData} ->
338
decompose_block(ElementType, ElementData, Start);
339
{ElementType, ElementData, SortOrder} ->
340
{TblData, TblRefs} = get_sorted_refs(ElementData, SortOrder),
341
{hipe_consttab:decompose({ElementType, TblData}), [{sorted,Start,TblRefs}]}
346
pack_labels(Labels,MFA,ConstTab,Start+Need,ConstNo+1,
350
?BOOL2EXT(hipe_consttab:const_exported(Const))}|
353
pack_labels([],_,_,AccSize,ConstNo,Acc,Refs) ->
354
{AccSize,Acc, ConstNo, Refs}.
356
decompose_block(ElementType, Data, Addr) ->
357
ElementSize = hipe_consttab:size_of(ElementType),
358
{NewData, Refs} = get_refs(Data,Addr,ElementSize),
359
{hipe_consttab:decompose({ElementType, NewData}), Refs}.
361
get_refs([{label,L}|Rest],Pos,4) ->
362
{NewData, Refs} = get_refs(Rest, Pos+4, 4),
363
{[0|NewData],[{L,Pos}|Refs]};
364
get_refs([D|Rest],Pos, Size) ->
365
{NewData, Refs} = get_refs(Rest, Pos+Size, Size),
370
get_sorted_refs([{label,L}|Rest], [Ordering|Os]) ->
371
{NewData, Refs} = get_sorted_refs(Rest, Os),
372
{[0|NewData],[{L,Ordering}|Refs]};
373
get_sorted_refs([D|Rest], [_Ordering|Os]) ->
374
{NewData, Refs} = get_sorted_refs(Rest, Os),
376
get_sorted_refs([],[]) ->
380
%% ------------------------------------------------------------------
384
find_const(Name, Tree) ->
385
case gb_trees:lookup(Name,Tree) of
387
none -> ?EXIT({could_not_find_constant, Name, Tree})
390
init_const_map(List) ->
391
init_const_map(List, gb_trees:empty()).
392
init_const_map([{MFA,Label,ConstNo,_,_, _, _,_} | List], Tree) ->
393
init_const_map(List,gb_trees:insert({MFA,Label}, ConstNo ,Tree));
394
init_const_map([], Tree) -> Tree.
397
%% ------------------------------------------------------------------
402
find(Name,[{Name,Seg,Addr}|_]) ->
404
find(Name,[_|Rest]) ->
406
find({Name,entry},[]) -> %% This function is not being compiled.
408
init_export_map(List) ->
414
case gb_trees:lookup(Name,Tree) of
416
none -> {none,0} %% This function is not being compiled.
419
init_export_map(List) ->
420
init_export_map(List, gb_trees:empty()).
421
init_export_map([{Name,Seg,Addr}|List], Tree) ->
422
init_export_map(List,gb_trees:insert(Name,{Seg,Addr},Tree));
423
init_export_map([], Tree) -> Tree.
430
case dict:find(Name,Tree) of
432
error -> {none,0} %% This Label is not being compiled.
434
init_export_map(List) ->
435
init_export_map(List, dict:new()).
436
% init_export_map3([{Name,Seg,Addr}|List], Tree) ->
437
% init_export_map3(List,dict:store(Name,{Seg,Addr},Tree));
438
% init_export_map3([], Tree) -> Tree.
441
-ifdef(DOUBLEDICTMAP).
443
case dict:find(M,Tree) of
445
case dict:find(L,D) of
449
error -> {none,0} %% This Label is not being compiled.
452
init_export_map(List) ->
453
init_export_map(List, dict:new()).
455
init_export_map([{{M,L},Seg,Addr}|List], Tree) ->
456
init_export_map(List,init_dm(M,L,{Seg,Addr},Tree));
457
init_export_map([], Tree) -> Tree.
458
init_dm(M,L,Data,Tree) ->
459
case dict:find(M,Tree) of
461
dict:store(M, dict:store(L,Data,T2), Tree);
463
dict:store(M, dict:store(L,Data,dict:new()), Tree)
468
local_labels(MFA, Map) ->
469
case gb_trees:lookup(MFA, Map) of
471
none -> ?EXIT({mfa_not_in_map,MFA,Map})
476
{hot,hipe_bifs:array_sub(Arr,L)}.
478
init_export_map(List) ->
479
MaxL = highestl(List,0),
480
init_export_map(List, gb_trees:empty(), MaxL).
481
init_export_map([{{M,L},Seg,Addr}|List], Tree, MaxL) ->
482
init_export_map(List,init_m(M,L,Addr,Tree, MaxL), MaxL);
483
init_export_map([], Tree, _) ->
486
highestl([{{_,entry},_,_}|List], Max) ->
489
highestl([{{_,L},_,_}|List], Max) ->
495
highestl([], Max) -> Max+1.
497
init_m(M,entry,Data,Tree, MaxL) -> Tree;
498
init_m(M,L,Data,Tree, MaxL) ->
499
case gb_trees:lookup(M,Tree) of
501
hipe_bifs:array_update(T2,L,Data),
504
Arr = hipe_bifs:array(MaxL,0),
505
hipe_bifs:array_update(Arr,L,Data),
506
gb_trees:insert(M, Arr, Tree)
511
%% ----------------------------------------------------
515
local_labels(MFA, Map) ->
516
case gb_trees:lookup(MFA, Map) of
518
none -> ?EXIT({mfa_not_in_map,MFA,Map})
523
case gb_trees:lookup(L,Tree) of
525
none -> ?EXIT({label_not_in_map,L,Tree})
528
init_export_map(List) ->
529
init_export_map(List, gb_trees:empty()).
530
init_export_map([{{M,L},Seg,Addr}|List], Tree) ->
531
init_export_map(List,init_m(M,L,{Seg,Addr},Tree));
532
init_export_map([], Tree) -> Tree.
535
init_m(M,L,Data,Tree) ->
536
case gb_trees:lookup(M,Tree) of
538
gb_trees:update(M, gb_trees:insert(L,Data,T2), Tree);
540
gb_trees:insert(M, gb_trees:insert(L,Data,gb_trees:empty()), Tree)