1
%% -*- erlang-indent-level: 2 -*-
2
%% ====================================================================
3
%% Filename : hipe_sparc_assemble.erl
4
%% Module : hipe_sparc_assemble
5
%% Purpose : Writes SPARC-code to memory.
6
%% Notes : Not all SPARC instructions are handled.
7
%% History : * 1998-06-18 Erik Johansson (happi@csd.uu.se): Created.
10
%% ====================================================================
13
%% Module that assembles SPARC code and returns it in the form of
14
%% HiPE's external format.
16
%% The external format for SPARC code is a binary representation of an
17
%% Erlang list of the form:
19
%% [Version::version(),
20
%% ConstSize::size(), ConstMap::constmap(), LabelMap::labelmap(),
21
%% ExportMap::exportmap(),
22
%% HotSize::size(), HotCode::code(), HotRefs::refs(),
23
%% ColdSize::size(), ColdCode::code(), ColdRefs::refs()
28
%% <li><code> version(): {VERSION::string(), SYSTEM-CHECKSUM} </code></li>
29
%% <li><code> size(): non_neg_integer() </code></li>
30
%% <li><code> constmap(): [ConstNo::integer(), Offset::integer(),
31
%% Need::integer(), Type::consttype(),
32
%% Exported::bool(), Data::term()
33
%% | constmap] </code></li>
34
%% <li><code> labelmap(): [{DataOffset:integer, CodeOffset:integer}
35
%% | labelmap] </code></li>
36
%% <li><code> exportmap(): [Offset::integer(), Module::atom(),
37
%% Function::atom(), Arity::integer()
38
%% | exportmap()] </code>
39
%% A list sorted on <code>Offset</code>. </li>
40
%% <li><code> code(): [B4::byte(), B3::byte(), B2::byte(), B1::byte()
41
%% | code()] </code></li>
42
%% <li><code> refs(): [{RefType:integer, Reflist:reflist}
43
%% | refs()] </code></li>
45
%% <li><code> reflist(): [{Data::term(),Offsets::offests()}
46
%% | reflist()] </code></li>
47
%% <li><code> offsets(): [Offset::integer() | offsets()] </code></li>
49
%% <li><code> constype(): 0 | 1 </code> (0 -> term (arbitrary erlang term),
50
%% 1 -> block (a list of bytes)) </li>
51
%% <li><code> bool(): 0 | 1 </code> (false, true) </li>
52
%% <li><code> mode(): hot | cold</code></li>
56
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58
-module(hipe_sparc_assemble).
59
-export([assemble/4]).
64
-define(DO_ASSERT,true).
66
-include("../../kernel/src/hipe_ext_format.hrl").
67
-include("../main/hipe.hrl").
68
-include("hipe_sparc.hrl").
69
-include("../rtl/hipe_literals.hrl").
71
%%---------------------------------------------------------------------
72
%% @spec assemble(term(), term(), [terms()], [Option]) -> binary()
74
%% @doc Assembles the compiled code in a SPARC-specific way and
75
%% returns a binary according to HiPE's external format.
77
%%---------------------------------------------------------------------
79
assemble(CompiledCode, Closures, Exports, Options) ->
80
?when_option(time, Options, ?start_timer("SPARC assembler")),
81
{ConstAlign,ConstSize,ConstMap,RefsFromConsts} =
82
hipe_pack_constants:pack_constants(CompiledCode,
83
hipe_sparc_registers:alignment()),
84
%% io:format("Const Size ~w\n",[ConstSize]),
85
{CodeSize,ExportMap,Code} = get_code(CompiledCode),
86
{AccHCode,AccHRefs} = linker(Code,ExportMap,ConstMap),
87
CodeBinary = mk_code_binary(AccHCode),
88
Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
89
ConstAlign, ConstSize,
90
hipe_pack_constants:slim_constmap(ConstMap),
91
mk_labelmap(RefsFromConsts, ExportMap),
92
slim_exportmap(ExportMap, Closures, Exports),
94
hipe_pack_constants:slim_refs(AccHRefs),
95
0,[] % ColdCodeSize, SlimColdRefs
97
?when_option(time, Options, ?stop_timer("SPARC assembler")),
100
mk_code_binary(AccHCode) ->
101
list_to_binary(words32towords8(AccHCode)).
103
words32towords8(List) ->
104
lists:foldr(fun word32towords8/2, [], List).
106
word32towords8(X1, Acc) ->
110
[X4, (X3 band 16#ff), X2 band 16#ff, X1 band 16#ff | Acc].
112
mk_labelmap(Map, ExportMap) ->
113
%% msg("Map: ~w Map\n",[Map]),
114
LblMap = lists:flatten(mk_labelmap(Map, ExportMap, [])),
115
%% msg("LblMap: ~w Map\n",[LblMap]),
118
mk_labelmap([{MFA, Labels}| Rest], ExportMap, Acc) ->
121
{Pos, find_offset({MFA,L}, ExportMap)};
122
{sorted,Base,OrderedLabels} ->
123
{sorted, Base, [{Order, find_offset({MFA,L}, ExportMap)}
124
|| {L,Order} <- OrderedLabels]}
125
end || Label <- Labels],
126
%% msg("Map: ~w Map\n",[Map]),
127
mk_labelmap(Rest, ExportMap, [Map,Acc]);
128
mk_labelmap([], _, Acc) -> Acc.
130
find_offset({MFA,L},[{{MFA,L},hot,Adr}|_Rest]) ->
132
find_offset(L,[_|Rest]) ->
135
?EXIT({label_not_found,L}).
137
slim_exportmap(Map, Closures, Exports) ->
138
SortedMap = lists:sort(slim_exportmap1(Map, [])),
139
slim_sorted_exportmap(SortedMap, Closures, Exports).
141
slim_exportmap1([{{{M,F,A},entry},hot,Adr}|Rest], Acc) ->
142
slim_exportmap1(Rest, [{Adr,M,F,A}|Acc]);
143
slim_exportmap1([_|Rest], Acc) ->
144
slim_exportmap1(Rest, Acc);
145
slim_exportmap1([], Acc) ->
148
slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
149
IsClosure = lists:member({M,F,A}, Closures),
150
IsExported = is_exported(F, A, Exports),
151
[Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
152
slim_sorted_exportmap([],_,_) -> [].
154
is_exported(F, A, Exports) -> lists:member({F,A}, Exports).
156
%%---------------------------------------------------------------------
157
%% assemble_instr(Instr)
159
%% Arguments: Instr - The complete instruction.
160
%% Description: Returns the 32-bit SPARC code for the instruction Instr.
161
%%---------------------------------------------------------------------
170
%% assemble_alu_cc(I);
172
%% assemble_store(I);
182
assemble_call_link(I);
184
assemble_jmp_link(I);
190
%% assemble_load_fp(I);
192
%% assemble_store_fp(I);
200
%% assemble_fmove(I);
202
%% assemble_conv_fp(I);
207
check_simm13(Val,I) ->
208
case hipe_sparc:is_imm(Val) of
210
V = hipe_sparc:imm_value(Val),
212
V > 4095 -> %% 12 bits
213
exit([{problem,{too_big_imm,Val}},{at,I}]);
215
exit([{problem,{too_small_imm,Val}},{at,I}]);
222
check_imm22(Val,I) ->
223
case hipe_sparc:is_imm(Val) of
225
V = hipe_sparc:imm_value(Val),
227
V > 4194303 -> %% 22 bits
228
exit([{problem,{too_big_imm,Val}},{at,I}]);
230
exit([{problem,{too_small_imm,Val}},{at,I}]);
240
assemble_move(Instr) ->
241
% move is a syntetic instruction, implemented with 'or'.
242
Dst = hipe_sparc:reg_nr(hipe_sparc:move_dest(Instr)),
243
Src = hipe_sparc:move_src(Instr),
245
%% Check if the source is a register.
246
case hipe_sparc:is_reg(Src) of
248
%% Check if source is an immediate.
249
case hipe_sparc:is_imm(Src) of
251
check_simm13(Src,Instr), %% Throws exception...
252
hipe_sparc_op:ori(0,hipe_sparc:imm_value(Src),Dst);
253
_ -> exit([{problem,{not_handled_operand,Src}},{at,Instr}])
256
hipe_sparc_op:or_op(0,hipe_sparc:reg_nr(Src),Dst)
259
%% Dst Src1 AluOp Src2
260
%% alu reg reg op reg
261
%% alu reg reg op imm
262
assemble_alu(Instr) ->
263
Dst = hipe_sparc:reg_nr(hipe_sparc:alu_dest(Instr)),
264
Src1 = hipe_sparc:reg_nr(hipe_sparc:alu_src1(Instr)),
265
SymSrc2 = hipe_sparc:alu_src2(Instr),
266
AluOp = hipe_sparc:alu_operator(Instr),
267
case hipe_sparc:is_reg(SymSrc2) of
269
case hipe_sparc:is_imm(SymSrc2) of
271
check_simm13(SymSrc2,Instr), %% Throws exception...
272
Src2 = hipe_sparc:imm_value(SymSrc2),
274
'+' -> hipe_sparc_op:addi(Src1,Src2,Dst);
275
'-' -> hipe_sparc_op:subi(Src1,Src2,Dst);
276
'+c' -> hipe_sparc_op:addci(Src1,Src2,Dst);
277
'-c' -> hipe_sparc_op:subci(Src1,Src2,Dst);
278
'and' -> hipe_sparc_op:andi(Src1,Src2,Dst);
279
'andn' -> hipe_sparc_op:andni(Src1,Src2,Dst);
280
'or' -> hipe_sparc_op:ori(Src1,Src2,Dst);
281
'xor' -> hipe_sparc_op:xori(Src1,Src2,Dst);
282
'xnor' -> hipe_sparc_op:xnori(Src1,Src2,Dst);
283
'>>' -> hipe_sparc_op:srli(Src1,Src2,Dst);
284
'>>64' -> hipe_sparc_op:srlix(Src1,Src2,Dst);
285
'>>?' -> hipe_sparc_op:srai(Src1,Src2,Dst);
286
'>>?64' -> hipe_sparc_op:sraix(Src1,Src2,Dst);
287
'<<' -> hipe_sparc_op:slli(Src1,Src2,Dst);
288
'<<64' -> hipe_sparc_op:sllix(Src1,Src2,Dst);
289
'smul' -> hipe_sparc_op:smuli(Src1,Src2,Dst);
290
_ -> exit([{problem,{not_handled,{aluop,AluOp}}},{at,Instr}])
292
false -> %% Not reg or imm
293
exit([{problem,{not_handled_operand,SymSrc2}},{at,Instr}])
297
Src2 = hipe_sparc:reg_nr(SymSrc2),
299
'+' -> hipe_sparc_op:add(Src1,Src2,Dst);
300
'-' -> hipe_sparc_op:sub(Src1,Src2,Dst);
301
'+c' -> hipe_sparc_op:addc(Src1,Src2,Dst);
302
'-c' -> hipe_sparc_op:subc(Src1,Src2,Dst);
303
'and' -> hipe_sparc_op:and_op(Src1,Src2,Dst);
304
'andn' -> hipe_sparc_op:andn(Src1,Src2,Dst);
305
'or' -> hipe_sparc_op:or_op(Src1,Src2,Dst);
306
'xor' -> hipe_sparc_op:xor_op(Src1,Src2,Dst);
307
'xnor' -> hipe_sparc_op:xnor_op(Src1,Src2,Dst);
308
'>>' -> hipe_sparc_op:srl(Src1,Src2,Dst);
309
'>>?' -> hipe_sparc_op:sra(Src1,Src2,Dst);
310
'<<' -> hipe_sparc_op:sll(Src1,Src2,Dst);
311
'>>64' -> hipe_sparc_op:srlx(Src1,Src2,Dst);
312
'>>?64' -> hipe_sparc_op:srax(Src1,Src2,Dst);
313
'<<64' -> hipe_sparc_op:sllx(Src1,Src2,Dst);
314
'smul' -> hipe_sparc_op:smul(Src1,Src2,Dst);
315
_ -> exit([{problem,{not_handled,{aluop,AluOp}}},{at,Instr}])
319
%% Dst Src1 AluOp Src2
320
%% alu reg reg op reg
321
%% alu reg reg op imm
322
assemble_alu_cc(Instr) ->
323
Dst = hipe_sparc:reg_nr(hipe_sparc:alu_cc_dest(Instr)),
324
Src1 = hipe_sparc:reg_nr(hipe_sparc:alu_cc_src1(Instr)),
325
SymSrc2 = hipe_sparc:alu_cc_src2(Instr),
326
AluOp = hipe_sparc:alu_cc_operator(Instr),
327
case hipe_sparc:is_reg(hipe_sparc:alu_cc_src2(Instr)) of
329
case hipe_sparc:is_imm(SymSrc2) of
331
check_simm13(SymSrc2,Instr), %% Throws exception...
332
Src2 = hipe_sparc:imm_value(SymSrc2),
334
'+' -> hipe_sparc_op:addicc(Src1,Src2,Dst);
335
'-' -> hipe_sparc_op:subicc(Src1,Src2,Dst);
336
'and' -> hipe_sparc_op:andicc(Src1,Src2,Dst);
337
'andn' -> hipe_sparc_op:andnicc(Src1,Src2,Dst);
338
'or' -> hipe_sparc_op:oricc(Src1,Src2,Dst);
339
'xor' -> hipe_sparc_op:xoricc(Src1,Src2,Dst);
340
_ -> exit([{problem,{not_handled,{aluccop,AluOp}}},
343
false -> %% Not reg or imm
344
exit([{problem,{not_handled_operand,SymSrc2}},{at,Instr}])
348
Src2 = hipe_sparc:reg_nr(SymSrc2),
350
'+' -> hipe_sparc_op:addcc(Src1,Src2,Dst);
351
'-' -> hipe_sparc_op:subcc(Src1,Src2,Dst);
352
'and' -> hipe_sparc_op:andcc(Src1,Src2,Dst);
353
'andn' -> hipe_sparc_op:andncc(Src1,Src2,Dst);
354
'or' -> hipe_sparc_op:orcc(Src1,Src2,Dst);
355
'xor' -> hipe_sparc_op:xorcc(Src1,Src2,Dst);
356
_ -> exit([{problem,{not_handled,{aluccop,AluOp}}},{at,Instr}])
363
assemble_store(Store) ->
364
Dst = hipe_sparc:reg_nr(hipe_sparc:store_dest(Store)),
365
Off = hipe_sparc:store_off(Store),
366
Type = hipe_sparc:store_type(Store),
367
Src = hipe_sparc:reg_nr(hipe_sparc:store_src(Store)),
368
case hipe_sparc:is_reg(Off) of
370
case hipe_sparc:is_imm(Off) of
372
check_simm13(Off,Store), %% Throws exception...
373
ImmOff = hipe_sparc:imm_value(Off),
375
w -> hipe_sparc_op:stwi(Src,Dst,ImmOff);
376
b -> hipe_sparc_op:stbi(Src,Dst,ImmOff);
377
h -> hipe_sparc_op:sthi(Src,Dst,ImmOff);
378
x -> hipe_sparc_op:stxi(Src,Dst,ImmOff)
380
false -> %% Not register or immediate
381
exit([{problem,{not_handled_offset,Off}},{at,Store}])
385
w -> hipe_sparc_op:stw(Src,Dst,hipe_sparc:reg_nr(Off));
386
b -> hipe_sparc_op:stb(Src,Dst,hipe_sparc:reg_nr(Off));
387
h -> hipe_sparc_op:sth(Src,Dst,hipe_sparc:reg_nr(Off));
388
x -> hipe_sparc_op:stx(Src,Dst,hipe_sparc:reg_nr(Off))
395
assemble_load(Load) ->
396
case hipe_sparc:is_reg(hipe_sparc:load_dest(Load)) of
398
case hipe_sparc:is_reg(hipe_sparc:load_src(Load)) of
400
Dst = hipe_sparc:reg_nr(hipe_sparc:load_dest(Load)),
401
Src = hipe_sparc:reg_nr(hipe_sparc:load_src(Load)),
402
Off = hipe_sparc:load_off(Load),
403
Type = hipe_sparc:load_type(Load),
404
case hipe_sparc:is_reg(Off) of
406
case hipe_sparc:is_imm(Off) of
408
check_simm13(Off,Load), %% Throws exception...
409
ImmOff = hipe_sparc:imm_value(Off),
411
uw -> hipe_sparc_op:ldi(Src,ImmOff,Dst);
412
sb -> hipe_sparc_op:ldsbi(Src,ImmOff,Dst);
413
sh -> hipe_sparc_op:ldshi(Src,ImmOff,Dst);
414
sw -> hipe_sparc_op:ldswi(Src,ImmOff,Dst);
415
ub -> hipe_sparc_op:ldubi(Src,ImmOff,Dst);
416
uh -> hipe_sparc_op:lduhi(Src,ImmOff,Dst);
417
x -> hipe_sparc_op:ldxi(Src,ImmOff,Dst)
419
false -> %% Not register or immediate
420
exit([{problem,{not_handled_offset,Off}},{at,Load}])
423
OffReg = hipe_sparc:reg_nr(Off),
425
uw -> hipe_sparc_op:ld(Src,OffReg,Dst);
426
sb -> hipe_sparc_op:ldsb(Src,OffReg,Dst);
427
sh -> hipe_sparc_op:ldsh(Src,OffReg,Dst);
428
sw -> hipe_sparc_op:ldsw(Src,OffReg,Dst);
429
ub -> hipe_sparc_op:ldub(Src,OffReg,Dst);
430
uh -> hipe_sparc_op:lduh(Src,OffReg,Dst);
431
x -> hipe_sparc_op:ldx(Src,OffReg,Dst)
435
exit([{problem,load_src_not_reg},{at,Load}])
438
exit([{problem,load_dst_not_reg},{at,Load}])
441
%% goto is a synthetic instruction implemented with ba
442
%% we're only doing SPARC V9 now, so replace "ba" with "ba,pt"
443
assemble_goto(Goto) ->
444
Disp = hipe_sparc:goto_label(Goto),
445
Cond = hipe_sparc_op:cc_bits('a'),
446
Pred = hipe_sparc_op:predicate_bit(true),
447
Annul = hipe_sparc_op:annul_bit('na'),
448
hipe_sparc_op:bpcc(Cond, Annul, Pred, Disp).
453
Disp = hipe_sparc:b_label(B),
454
Cond = hipe_sparc_op:cc_bits(hipe_sparc:b_cond(B)),
455
Pred = hipe_sparc_op:predicate_bit(hipe_sparc:b_taken(B)),
456
Annul = hipe_sparc_op:annul_bit(hipe_sparc:b_annul(B)),
457
hipe_sparc_op:bpcc(Cond, Annul, Pred, Disp).
459
%% assemble_br(BR) ->
460
%% Disp = hipe_sparc:br_label(BR),
461
%% Reg = hipe_sparc:reg_nr(hipe_sparc:br_reg(BR)),
462
%% RCond = hipe_sparc_op:rcc_bits(hipe_sparc:br_regcond(BR)),
463
%% Pred = hipe_sparc_op:predicate_bit(hipe_sparc:br_taken(BR)),
464
%% Annul = hipe_sparc_op:annul_bit(hipe_sparc:br_annul(BR)),
465
%% hipe_sparc_op:bpr(RCond, Annul, Pred, Reg, Disp).
467
assemble_call_link(Call_link) ->
469
hipe_sparc:reg_nr(hipe_sparc:call_link_link(Call_link)) =/=
470
hipe_sparc_registers:return_address() of
472
exit([{problem,{call_link_not_to_CP}},{at,Call_link}]);
474
hipe_sparc_op:call(hipe_sparc:call_link_target(Call_link))
477
assemble_jmp_link(Jmp_link) ->
478
Target = hipe_sparc:reg_nr(hipe_sparc:jmp_link_target(Jmp_link)),
479
Off = hipe_sparc:jmp_link_off(Jmp_link),
480
Link = hipe_sparc:reg_nr(hipe_sparc:jmp_link_link(Jmp_link)),
481
assemble_jlink(Jmp_link, Target, Off, Link).
483
assemble_jlink(I, Target, Off, Link) ->
484
case hipe_sparc:is_reg(Off) of
486
exit([{problem,{not_handled,{jmp_link,reg_reg_reg}}},{at,I}]);
488
case hipe_sparc:is_imm(Off) of
490
check_simm13(Off,I), %% Throws exception...
491
ImmOff = hipe_sparc:imm_value(Off),
492
hipe_sparc_op:jumpli(Target,ImmOff,Link);
493
false -> %% Not reg or imm
494
exit([{problem,{not_handled_offset,Off}},{at,I}])
499
Target = hipe_sparc:reg_nr(hipe_sparc:jmp_target(Jmp)),
500
Link = hipe_sparc_registers:zero(),
501
Off = hipe_sparc:jmp_off(Jmp),
502
assemble_jlink(Jmp, Target, Off, Link).
504
assemble_rdy(Instr) ->
505
Dest = hipe_sparc:reg_nr(hipe_sparc:rdy_dest(Instr)),
506
hipe_sparc_op:rdy(Dest).
508
assemble_sethi(Instr)->
509
Dest = hipe_sparc:reg_nr(hipe_sparc:sethi_dest(Instr)),
510
Val = hipe_sparc:sethi_const(Instr),
511
case hipe_sparc:is_imm(Val) of
513
check_imm22(Val,Instr), %% Throws exception...
514
ImmVal = hipe_sparc:imm_value(Val),
515
hipe_sparc_op:sethi(ImmVal,Dest);
517
exit([{problem,{not_an_integer,Val}},{at,Instr}])
520
assemble_nop(_Instr) ->
523
%%---------------------------------------------------------------------
525
%%---------------------------------------------------------------------
528
%% load_fp reg reg fpreg
529
%% load_fp reg imm fpreg
530
assemble_load_fp(Load) ->
531
case hipe_sparc:is_fpreg(hipe_sparc:load_fp_dest(Load)) of
533
case hipe_sparc:is_reg(hipe_sparc:load_fp_src(Load)) of
535
Type = hipe_sparc:load_fp_type(Load),
536
Dst = encode_5bit_fpreg(hipe_sparc:fpreg_nr(hipe_sparc:load_fp_dest(Load)),
538
Src = hipe_sparc:reg_nr(hipe_sparc:load_fp_src(Load)),
539
Off = hipe_sparc:load_fp_off(Load),
540
case hipe_sparc:is_reg(Off) of
542
case hipe_sparc:is_imm(Off) of
544
check_simm13(Off,Load), %% Throws exception...
545
ImmOff = hipe_sparc:imm_value(Off),
547
single -> hipe_sparc_op:ldfi(Dst,Src,ImmOff);
548
double -> hipe_sparc_op:lddfi(Dst,Src,ImmOff);
549
quad -> hipe_sparc_op:ldqfi(Dst,Src,ImmOff)
551
false -> %% Not reg or imm
552
exit([{problem,{not_handled_offset,Off}},{at,Load}])
556
single -> hipe_sparc_op:ldf(Dst,Src,hipe_sparc:reg_nr(Off));
557
double -> hipe_sparc_op:lddf(Dst,Src,hipe_sparc:reg_nr(Off));
558
quad -> hipe_sparc_op:ldqf(Dst,Src,hipe_sparc:reg_nr(Off))
562
exit([{problem,load_fp_src_not_reg},{at,Load}])
565
exit([{problem,load_fp_dst_not_fpreg},{at,Load}])
569
%% store_fp fpreg reg reg
570
%% store_fp reg imm reg
571
assemble_store_fp(Store) ->
572
Dst = hipe_sparc:reg_nr(hipe_sparc:store_fp_dest(Store)),
573
Off = hipe_sparc:store_fp_off(Store),
574
Type = hipe_sparc:store_fp_type(Store),
575
Src = encode_5bit_fpreg(hipe_sparc:fpreg_nr(hipe_sparc:store_fp_src(Store)),
577
case hipe_sparc:is_reg(Off) of
579
case hipe_sparc:is_imm(Off) of
581
check_simm13(Off,Store), %% Throws exception...
582
ImmOff = hipe_sparc:imm_value(Off),
584
single -> hipe_sparc_op:stfi(Src,Dst,ImmOff);
585
double -> hipe_sparc_op:stdfi(Src,Dst,ImmOff);
586
quad -> hipe_sparc_op:stqfi(Src,Dst,ImmOff)
588
false -> %% Not reg or imm
589
exit([{problem,{not_handled_offset,Off}},{at,Store}])
593
single -> hipe_sparc_op:stf(Src,Dst,hipe_sparc:reg_nr(Off));
594
double -> hipe_sparc_op:stdf(Src,Dst,hipe_sparc:reg_nr(Off));
595
quad -> hipe_sparc_op:stqf(Src,Dst,hipe_sparc:reg_nr(Off))
599
%% %% fb<Cond>[,a][,pt] <%fccN>,<L>
602
%% Disp = hipe_sparc:fb_label(B),
603
%% Cond = hipe_sparc_op:fcc_bits(hipe_sparc:fb_cond(B)),
604
%% Pred = hipe_sparc_op:predicate_bit(hipe_sparc:fb_taken(B)),
605
%% Annul = hipe_sparc_op:annul_bit(hipe_sparc:fb_annul(B)),
606
%% Fcc = hipe_sparc:fb_fcc_reg(B),
607
%% hipe_sparc_op:fbpfcc(Fcc, Cond, Annul, Pred, Disp).
611
%% fpreg fpreg op fpreg
612
assemble_fop(Instr) ->
613
D = hipe_sparc:fpreg_nr(hipe_sparc:fop_dest(Instr)),
614
S1 = hipe_sparc:fpreg_nr(hipe_sparc:fop_src1(Instr)),
615
S2 = hipe_sparc:fpreg_nr(hipe_sparc:fop_src2(Instr)),
616
Type = hipe_sparc:fop_type(Instr),
617
Src1 = encode_5bit_fpreg(S1, Type),
618
Src2 = encode_5bit_fpreg(S2, Type),
619
Dst = encode_5bit_fpreg(D, Type),
621
FOp = hipe_sparc:fop_operator(Instr),
626
'+' -> hipe_sparc_op:faddd(Src1,Src2,Dst);
627
'-' -> hipe_sparc_op:fsubd(Src1,Src2,Dst);
628
'*' -> hipe_sparc_op:fmuld(Src1,Src2,Dst);
629
'/' -> hipe_sparc_op:fdivd(Src1,Src2,Dst);
630
_ -> ?EXIT([{problem,{not_handled,{fop,FOp}}},
635
'+' -> hipe_sparc_op:fadds(Src1,Src2,Dst);
636
'-' -> hipe_sparc_op:fsubs(Src1,Src2,Dst);
637
'*' -> hipe_sparc_op:fmuls(Src1,Src2,Dst);
638
'/' -> hipe_sparc_op:fdivs(Src1,Src2,Dst);
639
_ -> ?EXIT([{problem,{not_handled,{fop,FOp}}},
644
'+' -> hipe_sparc_op:faddq(Src1,Src2,Dst);
645
'-' -> hipe_sparc_op:fsubq(Src1,Src2,Dst);
646
'*' -> hipe_sparc_op:fmulq(Src1,Src2,Dst);
647
'/' -> hipe_sparc_op:fdivq(Src1,Src2,Dst);
648
_ -> ?EXIT([{problem,{not_handled,{fop,FOp}}},
654
%% %% fccN fpreg fpreg
655
%% assemble_fcmp(Instr) ->
656
%% Fcc = hipe_sparc:fcmp_fcc_reg(Instr),
657
%% Src1 = hipe_sparc:fpreg_nr(hipe_sparc:fcmp_src1(Instr)),
658
%% Src2 = hipe_sparc:fpreg_nr(hipe_sparc:fcmp_src2(Instr)),
659
%% Exception = hipe_sparc:fcmp_exception(Instr),
660
%% Type = hipe_sparc:fcmp_type(Instr),
661
%% %% XXX: Is this the right way to code the regs?
662
%% RS1 = encode_5bit_fpreg(Src1, Type),
663
%% RS2 = encode_5bit_fpreg(Src2, Type),
667
%% true -> hipe_sparc_op:fcmped(Fcc,RS1,RS2);
668
%% false -> hipe_sparc_op:fcmpd(Fcc,RS1,RS2)
672
%% true -> hipe_sparc_op:fcmpes(Fcc,RS1,RS2);
673
%% false -> hipe_sparc_op:fcmps(Fcc,RS1,RS2)
677
%% true -> hipe_sparc_op:fcmpeq(Fcc,RS1,RS2);
678
%% false -> hipe_sparc_op:fcmpq(Fcc,RS1,RS2)
684
assemble_fmove(Instr) ->
685
D = hipe_sparc:fpreg_nr(hipe_sparc:fmove_dest(Instr)),
686
S = hipe_sparc:fpreg_nr(hipe_sparc:fmove_src(Instr)),
687
Type = hipe_sparc:fmove_type(Instr),
688
Neg = hipe_sparc:fmove_negate(Instr),
689
Abs = hipe_sparc:fmove_abs(Instr),
690
Src = encode_5bit_fpreg(S, Type),
691
Dst = encode_5bit_fpreg(D, Type),
696
{true, false} -> hipe_sparc_op:fabsd(Src,Dst);
697
{false, true} -> hipe_sparc_op:fnegd(Src,Dst);
698
{false, false} -> hipe_sparc_op:fmovd(Src,Dst);
699
_ -> ?EXIT([{problem,{not_handled,{negate, absolute_value}}},
704
{true, false} -> hipe_sparc_op:fabss(Src,Dst);
705
{false, true} -> hipe_sparc_op:fnegs(Src,Dst);
706
{false, false} -> hipe_sparc_op:fmovs(Src,Dst);
707
_ -> ?EXIT([{problem,{not_handled,{negate,Neg,absolute_value,Abs}}},
712
{true, false} -> hipe_sparc_op:fabsq(Src,Dst);
713
{false, true} -> hipe_sparc_op:fnegq(Src,Dst);
714
{false, false} -> hipe_sparc_op:fmovq(Src,Dst);
715
_ -> ?EXIT([{problem,{not_handled,{negate, absolute_value}}},
722
assemble_conv_fp(Instr) ->
723
D = hipe_sparc:fpreg_nr(hipe_sparc:conv_fp_dest(Instr)),
724
S = hipe_sparc:fpreg_nr(hipe_sparc:conv_fp_src(Instr)),
725
DestType = hipe_sparc:conv_fp_dest_type(Instr),
726
Dst = encode_5bit_fpreg(D, DestType),
727
Src = encode_5bit_fpreg(S, single),
731
hipe_sparc_op:fitos(Src, Dst);
733
hipe_sparc_op:fitod(Src, Dst);
735
hipe_sparc_op:fitoq(Src, Dst)
738
%%---------------------------------------------------------------------
740
encode_5bit_fpreg(Reg, Type) ->
747
?ASSERT(Reg band 2#1 =:= 0),
748
((Reg bsr 5) bor (Reg band 2#11110));
751
?ASSERT(Reg band 2#11 =:= 0),
752
((Reg bsr 5) bor (Reg band 2#11110))
755
%% TODO: implement if needed:
756
%% encode_6bit_fpreg(Reg, Type)
758
%%=====================================================================
759
%% A linker for SPARC code appears below
760
%%=====================================================================
762
linker(Code, Map, ConstMap) ->
764
init_export_map(Map), %% Convert to more efficient
765
init_const_map(ConstMap), %% data structures.
768
link9([{MFA,Hot}|Rest], HAddr, Map, ConstMap,
769
AccHCode, AccHRefs) ->
770
%% io:format("Assembling ~w\n",[MFA]),
771
{HCode,NewHAddr,HRefs} =
772
link8(Hot , MFA, HAddr, local_labels(MFA,Map), ConstMap, AccHRefs, []),
773
link9(Rest, NewHAddr, Map, ConstMap, AccHCode++HCode, HRefs);
774
link9([],_HAddr,_Map,_ConstMap,AccHCode,AccHRefs) ->
777
link8([I|Is],MFA,Addr,Map,ConstMap,Refs,Code) ->
780
#call_link{} -> resolve_call_link(I,Addr,Refs,Map);
781
#b{} -> resolve_b(I,Addr,Refs,Map);
782
#goto{} -> resolve_goto(I,Addr,Refs,Map);
783
#load_address{} -> resolve_load_address(I,Addr,Refs,MFA,Map,ConstMap);
784
#load_atom{} -> resolve_load_atom(I,Addr,Refs);
785
%% #load_word_index{} -> resolve_load_word_index(I,Addr,Refs,MFA,Map,ConstMap);
786
#alu{} -> {assemble_alu(I),Addr+4,Refs};
787
#alu_cc{} -> {assemble_alu_cc(I),Addr+4,Refs};
788
#store{} -> {assemble_store(I),Addr+4,Refs};
789
#move{} -> {assemble_move(I),Addr+4,Refs};
790
#load{} -> {assemble_load(I),Addr+4,Refs};
791
#store_fp{} -> {assemble_store_fp(I),Addr+4,Refs};
792
#load_fp{} -> {assemble_load_fp(I),Addr+4,Refs};
793
%% #fb{} -> {assemble_fb(I),Addr+4,Refs};
794
#fop{} -> {assemble_fop(I),Addr+4,Refs};
795
%% #fcmp{} -> {assemble_fcmp(I),Addr+4,Refs};
796
#fmove{} -> {assemble_fmove(I),Addr+4,Refs};
797
#conv_fp{} -> {assemble_conv_fp(I),Addr+4,Refs};
798
#jmp{} -> {assemble_jmp(I),Addr+4,Refs};
799
#nop{} -> {assemble_nop(I),Addr+4,Refs};
800
#rdy{} -> {assemble_rdy(I),Addr+4,Refs};
801
#sethi{} -> {assemble_sethi(I),Addr+4,Refs};
802
Other -> exit({bad_sparc_instruction,Other})
804
{[I1,I2],NewAddr,NewRefs} ->
805
link8(Is,MFA,NewAddr,Map,ConstMap,NewRefs,[I1,I2|Code]);
806
{C,NewAddr,NewRefs} ->
807
link8(Is,MFA,NewAddr,Map,ConstMap,NewRefs,[C|Code])
809
link8([],_MFA,Addr,_Map,_ConstMap,Refs,Code) ->
810
{lists:reverse(Code),Addr,Refs}.
812
resolve_load_address(Instr,Addr,Refs,MFA,_Map,ConstMap)->
813
Dest = hipe_sparc:load_address_dest(Instr),
814
Address = hipe_sparc:load_address_addr(Instr),
816
case hipe_sparc:load_address_type(Instr) of
818
%% {hot,Offset} = find(Address, Map),
819
%% [{?LOAD_ADDRESS,Addr,{label,Offset}}];
821
[{?LOAD_ADDRESS,Addr,{local_function,Address}}];
823
[{?LOAD_ADDRESS,Addr,{remote_function,Address}}];
825
ConstNo = find_const({MFA,Address},ConstMap),
826
[{?LOAD_ADDRESS,Addr,{constant,ConstNo}}];
828
[{?LOAD_ADDRESS,Addr,{closure,Address}}];
830
[{?LOAD_ADDRESS,Addr,{c_const,Address}}];
832
exit([{problem,{not_handled,{address,Type}}},{at,Instr}])
834
Hi = hipe_sparc:mk_imm(0),
835
Lo = hipe_sparc:mk_imm(0),
836
I1 = hipe_sparc:sethi_create(Dest,Hi),
837
I2 = hipe_sparc:alu_create(Dest,Dest,'or',Lo),
838
{[assemble_instr(I2),assemble_instr(I1)],Addr+8,Ref++Refs}.
840
resolve_goto(I,Addr,Refs,Map) ->
841
Dest = hipe_sparc:goto_label(I),
842
{hot,Address} = find(Dest,Map),
843
RelDest = (Address - Addr) div 4,
844
case valid_branch_length(RelDest) of
846
false -> exit({too_long_branch,{address,Addr}})
848
NewI = hipe_sparc:goto_label_update(I,RelDest),
849
Code = assemble_instr(NewI),
852
resolve_b(I,Addr,Refs,Map) ->
853
Dest = hipe_sparc:b_label(I),
854
{hot,Address} = find(Dest,Map),
855
RelDest = (Address - Addr) div 4,
856
case valid_branch_length(RelDest) of
858
false -> exit({too_long_branch,{address,Addr}})
860
NewI = hipe_sparc:b_label_update(I,RelDest),
861
Code = assemble_instr(NewI),
864
resolve_load_atom(Instr,Addr,Refs)->
865
Atom = hipe_sparc:load_atom_atom(Instr),
866
Dest = hipe_sparc:load_atom_dest(Instr),
867
I1 = hipe_sparc:sethi_create(Dest, hipe_sparc:mk_imm(0)),
868
I2 = hipe_sparc:alu_create(Dest, Dest, 'or', hipe_sparc:mk_imm(0)),
869
{[assemble_instr(I2),assemble_instr(I1)],
870
Addr+8,[{?LOAD_ATOM, Addr, Atom}|Refs]}.
872
%%resolve_load_word_index(_Instr,_Addr,_Refs,_MFA,_Map,_ConstMap) ->
873
%% ?EXIT({nyi,resolve_load_word_index}).
874
%% Index =hipe_sparc:load_word_index_index(Instr),
875
%% Block =hipe_sparc:load_word_index_block(Instr),
876
%% Dest = hipe_sparc:load_word_index_dest(Instr),
877
%% ConstNo = find_const({MFA,Block},ConstMap),
878
%% I1 = hipe_sparc:sethi_create(Dest, hipe_sparc:mk_imm(0)),
879
%% I2 = hipe_sparc:alu_create(Dest,Dest, 'or', hipe_sparc:mk_imm(0)),
880
%% {[assemble_instr(I2),assemble_instr(I1)],
881
%% Addr+8,[{?PATCH_TYPE2EXT(load_word_index),Addr, {word_index, ConstNo, Index}}|Refs]}.
883
resolve_call_link(Instr,Addr,OldRefs,Map)->
884
Target = hipe_sparc:call_link_target(Instr),
885
ExnLab = hipe_sparc:call_link_fail(Instr),
886
%% Get the stack descriptor information
887
SD = hipe_sparc:call_link_stack_desc(Instr),
888
FSize = hipe_sparc:sdesc_size(SD),
889
Live = list_to_tuple(hipe_sparc:sdesc_live_slots(SD)),
890
Arity = case hipe_sparc:sdesc_arity(SD) of
891
N when N > ?SPARC_NR_ARG_REGS -> N - ?SPARC_NR_ARG_REGS;
894
ExnRA = case ExnLab of
895
[] -> []; % don't cons up a new one
896
_ -> {hot,V} = find(ExnLab,Map), V
898
%% The stack descriptor needs to be inserted into the system at load-time.
901
?STACK_DESC(ExnRA, FSize, Arity, Live)} | OldRefs],
902
case hipe_sparc:call_link_is_known(Instr) of
904
NewI = hipe_sparc:jmp_link_create(
905
hipe_sparc:call_link_target(Instr),
906
hipe_sparc:mk_imm(0),
907
hipe_sparc:mk_reg(hipe_sparc_registers:return_address()),
908
hipe_sparc:call_link_args(Instr)),
909
Code = assemble_instr(NewI),
913
case hipe_sparc:call_link_type(Instr) of
914
remote -> ?CALL_REMOTE;
915
not_remote -> ?CALL_LOCAL
917
NewRefs = [{Patch,Addr,Target} | Refs],
918
NewI = hipe_sparc:call_link_target_update(Instr,0),
919
Code = assemble_instr(NewI),
920
{Code,Addr+4,NewRefs}
923
%% ------------------------------------------------------------------
925
get_code(CompiledCode) -> % -> {CodeSize,ExportMap,NewCode}
926
get_code(CompiledCode, 0, [], []).
928
get_code([{MFA,Insns,_Data}|Rest], Address, Map, AccCode) ->
929
{NewInsns,NewAddress,NewMap} = preprocess(Insns,MFA,Address,Map),
930
get_code(Rest, NewAddress, NewMap, [{MFA,NewInsns}|AccCode]);
931
get_code([], Address, Map, AccCode) ->
932
{Address,Map,lists:reverse(AccCode)}.
934
preprocess(Entry, MFA, Address, Map) ->
935
%% io:format("~w at ~w ~w\n",[MFA,Address]),
936
process_instr(Entry, Address,
937
[{{MFA,entry},hot,Address}|Map],
940
process_instr([I|Is], Address, Map, MFA, AccCode) ->
943
process_instr(Is, Address,
944
[{{MFA,hipe_sparc:label_name(I)},hot,Address}|Map],
947
process_instr(Is, Address, Map, MFA, AccCode);
949
process_instr(Is, Address+8, Map, MFA, [I|AccCode]);
951
process_instr(Is, Address+8, Map, MFA, [I|AccCode]);
952
#load_word_index{} ->
953
process_instr(Is, Address+8, Map, MFA, [I|AccCode]);
955
process_instr(Is, Address+4, Map, MFA, [I|AccCode])
957
process_instr([], Address, Map, _MFA, AccCode) ->
958
{lists:reverse(AccCode),Address,Map}.
960
%% ------------------------------------------------------------------
965
find_const(Name, Tree) ->
966
case gb_trees:lookup(Name,Tree) of
968
none -> ?EXIT({could_not_find_constant, Name, Tree})
971
init_const_map(List) ->
972
init_const_map(List, gb_trees:empty()).
973
init_const_map([{pcm_entry,MFA,Label,ConstNo,_,_,_} | List], Tree) ->
974
init_const_map(List,gb_trees:insert({MFA,Label}, ConstNo ,Tree));
975
init_const_map([], Tree) ->
978
%% ------------------------------------------------------------------
980
%% Label map: represented with double gbtrees.
983
local_labels(MFA, Map) ->
984
case gb_trees:lookup(MFA, Map) of
986
none -> ?EXIT({mfa_not_in_map,MFA,Map})
990
case gb_trees:lookup(L, Tree) of
992
none -> ?EXIT({label_not_in_map,L,Tree})
995
init_export_map(List) ->
996
init_export_map(List, gb_trees:empty()).
998
init_export_map([{{M,L},Seg,Addr}|List], Tree) ->
999
init_export_map(List, init_m(M, L, {Seg,Addr}, Tree));
1000
init_export_map([], Tree) -> Tree.
1002
init_m(M, L, Data, Tree) ->
1003
case gb_trees:lookup(M, Tree) of
1005
gb_trees:update(M, gb_trees:insert(L, Data, T2), Tree);
1007
gb_trees:insert(M, gb_trees:insert(L, Data, gb_trees:empty()), Tree)
1010
%% %%--------------------------------------------------------------------
1012
%% %% check_immediates asserts that all immediates are less than 13 bits
1013
%% %% Returns true if the code is ok.
1014
%% %% Exception: {'EXIT',{immediate_too_large, [{Instr1,[Imm1,Imm2]},{Instr2,[Imm3|...]}|...]}}
1015
%% %% if Imm1 and Imm2 are too large.
1017
%% check_immediates(Instrs) -> check_immediates(Instrs,[]).
1019
%% check_immediates([],[]) -> true;
1020
%% check_immediates([],Problems) -> exit({immediate_too_large,Problems});
1021
%% check_immediates([Instr|Rest],Problems) ->
1022
%% case hipe_sparc:is_sethi(Instr) of
1023
%% true -> check_immediates(Rest,Problems);
1025
%% case check_imm(hipe_sparc:imm_uses(Instr),[]) of
1027
%% check_immediates(Rest,Problems);
1029
%% check_immediates(Rest,[{Instr,MoreProblems}|Problems])
1033
%% check_imm([],[]) -> true;
1034
%% check_imm([],Problems) -> Problems;
1035
%% check_imm([Use|Rest],Problems) ->
1036
%% case hipe_sparc:is_imm(Use) of
1038
%% Val = hipe_sparc:imm_value(Use),
1040
%% Val > 4095 -> %% Largest possible immediate.
1041
%% check_imm(Rest,[Val|Problems]);
1043
%% check_imm(Rest,Problems)
1046
%% check_imm(Rest,Problems)
1049
%% ------------------------------------------------------------------
1050
%% valid_branch_length(relativeDestination)
1051
%% Validates that the destination is within reach.
1053
%% XXX: this only works for disp19-type branches.
1054
%% XXX: update for disp16 (BPr) and disp22 (Bicc) type branches
1057
valid_branch_length(Dest) ->
1058
if (abs(Dest) band (16#FFF80000)) > 0 ->