[m-rev.] for review: MVM->x86_64 register mapping.
Fransiska Nathania HANDOKO
fhandoko at students.csse.unimelb.edu.au
Mon Feb 19 22:10:26 AEDT 2007
Estimated hours taken: 40
Branches: main
Defines the mapping of MVM registers to x86_64 registers needed by the asm
code generator.
compiler/ll_backend.m:
Includes the x86_64_regs module.
compiler/llds_to_x86_64.m:
Applies the register mapping in the code generator.
compiler/mercury_compile.m:
Imports x86_64_regs and x86_64_out modules.
compiler/x86_64_instrs.m:
Adds discriminated union types and fixes some predicates to make the code
easier for modification.
compiler/x86_64_out.m:
Fixes some predicates to output asm codes to conform with the changes
in x86_64_instrs.m.
compiler/x86_64_regs.m:
Defines the mapping of MVM registers to x86_64 registers.
Index: compiler/ll_backend.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ll_backend.m,v
retrieving revision 1.19
diff -u -r1.19 ll_backend.m
--- compiler/ll_backend.m 5 Feb 2007 22:30:32 -0000 1.19
+++ compiler/ll_backend.m 9 Feb 2007 04:57:45 -0000
@@ -97,6 +97,7 @@
:- include_module llds_to_x86_64_out.
:- include_module x86_64_instrs.
:- include_module x86_64_out.
+:- include_module x86_64_regs.
:- implementation.
Index: compiler/llds_to_x86_64.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/llds_to_x86_64.m,v
retrieving revision 1.1
diff -u -r1.1 llds_to_x86_64.m
--- compiler/llds_to_x86_64.m 5 Feb 2007 22:30:32 -0000 1.1
+++ compiler/llds_to_x86_64.m 19 Feb 2007 06:10:47 -0000
@@ -10,7 +10,13 @@
% Main author: fhandoko.
%
% This module implements the LLDS->x86_64 asm code generator.
-%
+%
+% NOTE:
+% There are a number of placeholders. It appears as a string like this:
+% <<placeholder>>. The code generator places them as either x86_64_comment
+% or operand_label type. For example:
+% x86_64_comment("<<placeholder>>") or
+% operand_label("<<placeholder>>").
%-----------------------------------------------------------------------------%
:- module ll_backend.llds_to_x86_64.
@@ -37,6 +43,7 @@
:- import_module libs.compiler_util.
:- import_module ll_backend.llds_out.
:- import_module ll_backend.x86_64_out.
+:- import_module ll_backend.x86_64_regs.
:- import_module mdbcomp.prim_data.
:- import_module bool.
@@ -72,15 +79,17 @@
%
llds_to_x86_64_asm(_, CProcs, AsmProcs) :-
- transform_c_proc_list(CProcs, AsmProcs).
+ ll_backend.x86_64_regs.llds_reg_locn(RegLocnList),
+ RegMap = ll_backend.x86_64_regs.reg_map_init(RegLocnList),
+ transform_c_proc_list(RegMap, CProcs, AsmProcs).
% Transform a list of c procedures into a list of x86_64 procedures.
%
-:- pred transform_c_proc_list(list(c_procedure)::in,
+:- pred transform_c_proc_list(reg_map::in, list(c_procedure)::in,
list(x86_64_procedure)::out) is det.
-transform_c_proc_list([], []).
-transform_c_proc_list([CProc | CProcs], [AsmProc | AsmProcs]) :-
+transform_c_proc_list(_, [], []).
+transform_c_proc_list(RegMap, [CProc | CProcs], [AsmProc | AsmProcs]) :-
AsmProc0 = ll_backend.x86_64_instrs.init_x86_64_proc(CProc),
ProcInstr0 = ll_backend.x86_64_instrs.init_x86_64_instruction,
%
@@ -89,65 +98,64 @@
%
ProcStr = backend_libs.name_mangle.proc_label_to_c_string(
AsmProc0 ^ x86_64_proc_label, no),
- ProcName = x86_64_directive(x86_64_pseudo_type(ProcStr, "@function")),
+ ProcName = x86_64_directive(x86_64_pseudo_type(ProcStr, function)),
ProcInstr = ProcInstr0 ^ x86_64_inst := [ProcName],
- transform_c_instr_list(CProc ^ cproc_code, AsmInstr0),
+ transform_c_instr_list(RegMap, CProc ^ cproc_code, AsmInstr0),
list.append([ProcInstr], AsmInstr0, AsmInstr),
AsmProc = AsmProc0 ^ x86_64_code := AsmInstr,
- transform_c_proc_list(CProcs, AsmProcs).
+ transform_c_proc_list(RegMap, CProcs, AsmProcs).
% Transform a list of c instructions into a list of x86_64 instructions.
%
-:- pred transform_c_instr_list(list(instruction)::in,
+:- pred transform_c_instr_list(reg_map::in, list(instruction)::in,
list(x86_64_instruction)::out) is det.
-transform_c_instr_list([], []).
-transform_c_instr_list([CInstr0 | CInstr0s], [AsmInstr | AsmInstrs]) :-
+transform_c_instr_list(_, [], []).
+transform_c_instr_list(RegMap, [CInstr0 | CInstr0s], [AsmInstr | AsmInstrs]) :-
CInstr0 = llds_instr(CInstr1, Comment),
- instr_to_x86_64(CInstr1, AsmInstrList),
+ instr_to_x86_64(RegMap, CInstr1, RegMap1, AsmInstrList),
+ ll_backend.x86_64_regs.reg_map_reset_scratch_reg_info(RegMap1, RegMap2),
AsmInstr0 = ll_backend.x86_64_instrs.init_x86_64_instruction,
AsmInstr1 = AsmInstr0 ^ x86_64_inst := AsmInstrList,
AsmInstr = AsmInstr1 ^ x86_64_inst_comment := Comment,
- transform_c_instr_list(CInstr0s, AsmInstrs).
+ transform_c_instr_list(RegMap2, CInstr0s, AsmInstrs).
% Transform a block instruction of an llds instruction into a list of
% x86_64 instructions.
%
-:- pred transform_block_instr(list(instruction)::in, list(x86_64_instr)::out)
- is det.
+:- pred transform_block_instr(reg_map::in, list(instruction)::in,
+ list(x86_64_instr)::out) is det.
-transform_block_instr(CInstrs, Instrs) :-
- transform_block_instr_list(CInstrs, ListInstrs),
+transform_block_instr(RegMap, CInstrs, Instrs) :-
+ transform_block_instr_list(RegMap, CInstrs, ListInstrs),
list.condense(ListInstrs, Instrs).
-:- pred transform_block_instr_list(list(instruction)::in,
+:- pred transform_block_instr_list(reg_map::in, list(instruction)::in,
list(list(x86_64_instr))::out) is det.
-transform_block_instr_list([], []).
-transform_block_instr_list([CInstr0 | CInstr0s], [Instr0 | Instr0s]) :-
+transform_block_instr_list(_, [], []).
+transform_block_instr_list(RegMap, [CInstr0 | CInstr0s], [Instr0 | Instr0s]) :-
CInstr0 = llds_instr(CInstr, _),
- instr_to_x86_64(CInstr, Instr0),
- transform_block_instr_list(CInstr0s, Instr0s).
+ instr_to_x86_64(RegMap, CInstr, RegMap1, Instr0),
+ ll_backend.x86_64_regs.reg_map_reset_scratch_reg_info(RegMap1, RegMap2),
+ transform_block_instr_list(RegMap2, CInstr0s, Instr0s).
% Transform livevals of llds instruction into a list of x86_64 instructions.
%
-:- pred transform_livevals(list(lval)::in, list(x86_64_instr)::out) is det.
+:- pred transform_livevals(reg_map::in, list(lval)::in, list(x86_64_instr)::out)
+ is det.
-transform_livevals([], []).
-transform_livevals([Lval | Lvals], [Instr | Instrs]) :-
- transform_lval(Lval, Res0, Res1),
+transform_livevals(_, [], []).
+transform_livevals(RegMap, [Lval | Lvals], [Instr | Instrs]) :-
+ transform_lval(RegMap, Lval, RegMap1, Res0, Res1),
(
- Res0 = yes(LvalOp),
- Instr = x86_64_instr(mov(operand_label("<<livevals>>"), LvalOp)),
- transform_livevals(Lvals, Instrs)
+ Res0 = yes(LvalOp)
;
Res0 = no,
(
Res1 = yes(LvalInstrs),
( get_last_instr_opand(LvalInstrs, LastOp) ->
- Instr = x86_64_instr(mov(operand_label("<<livevals>>"),
- LastOp)),
- transform_livevals(Lvals, Instrs)
+ LvalOp = LastOp
;
unexpected(this_file, "transform_livevals: unexpected:"
++ " get_last_instr_opand failed")
@@ -157,22 +165,25 @@
unexpected(this_file, "transform_livevals: unexpected:"
++ " get_last_instr_opand failed")
)
- ).
+ ),
+ Instr = x86_64_instr(mov(operand_label("<<liveval>>"), LvalOp)),
+ transform_livevals(RegMap1, Lvals, Instrs).
% Given an llds instruction, transform it into equivalent x86_64
% instructions.
%
-:- pred instr_to_x86_64(instr::in, list(x86_64_instr)::out) is det.
+:- pred instr_to_x86_64(reg_map::in, instr::in, reg_map::out,
+ list(x86_64_instr)::out) is det.
-instr_to_x86_64(comment(Comment), [x86_64_comment(Comment)]).
-instr_to_x86_64(livevals(RegsAndStackLocs), Instrs) :-
+instr_to_x86_64(RegMap, comment(Comment), RegMap, [x86_64_comment(Comment)]).
+instr_to_x86_64(RegMap, livevals(RegsAndStackLocs), RegMap, Instrs) :-
set.to_sorted_list(RegsAndStackLocs, List),
- transform_livevals(List, Instrs).
-instr_to_x86_64(block(_, _, CInstrs), Instrs) :-
- transform_block_instr(CInstrs, Instrs).
-instr_to_x86_64(assign(Lval, Rval), Instrs) :-
- transform_lval(Lval, Res0, Res1),
- transform_rval(Rval, Res2, Res3),
+ transform_livevals(RegMap, List, Instrs).
+instr_to_x86_64(RegMap, block(_, _, CInstrs), RegMap, Instrs) :-
+ transform_block_instr(RegMap, CInstrs, Instrs).
+instr_to_x86_64(RegMap0, assign(Lval, Rval), RegMap, Instrs) :-
+ transform_lval(RegMap0, Lval, RegMap1, Res0, Res1),
+ transform_rval(RegMap1, Rval, RegMap, Res2, Res3),
(
Res0 = yes(LvalOp),
(
@@ -184,7 +195,7 @@
Res3 = yes(RvalInstrs),
( get_last_instr_opand(RvalInstrs, LastOp) ->
LastInstr = x86_64_instr(mov(LastOp, LvalOp)),
- list.append(RvalInstrs, [LastInstr], Instrs)
+ Instrs = RvalInstrs ++ [LastInstr]
;
unexpected(this_file, "instr_to_x86_64: assign: unexpected:"
++ " get_last_instr_opand failed")
@@ -202,16 +213,15 @@
( get_last_instr_opand(LvalInstrs, LvalLastOp) ->
(
Res2 = yes(RvalOp),
- Instr0 = x86_64_instr(mov(RvalOp, LvalLastOp)),
- list.append(LvalInstrs, [Instr0], Instrs)
-
+ Instr1 = x86_64_instr(mov(RvalOp, LvalLastOp)),
+ Instrs = LvalInstrs ++ [Instr1]
;
Res2 = no,
(
Res3 = yes(RvalInstrs),
( get_last_instr_opand(RvalInstrs, RvalLastOp) ->
- Instr0 = x86_64_instr(mov(RvalLastOp, LvalLastOp)),
- Instrs = LvalInstrs ++ [Instr0] ++ RvalInstrs
+ Instr1 = x86_64_instr(mov(RvalLastOp, LvalLastOp)),
+ Instrs = LvalInstrs ++ RvalInstrs ++ [Instr1]
;
unexpected(this_file, "instr_to_x86_64: assign:"
++ " unexpected:get_last_instr_opand failed")
@@ -232,22 +242,42 @@
++ "Lval")
)
).
-instr_to_x86_64(llcall(Target0, Continuation0, _, _, _, _), Instrs) :-
+instr_to_x86_64(RegMap0, llcall(Target0, Continuation0, _, _, _, _), RegMap,
+ Instrs) :-
code_addr_type(Target0, Target1),
code_addr_type(Continuation0, Continuation1),
- Instr1 = x86_64_instr(mov(operand_label(Continuation1),
- operand_label("<<succip>>"))),
+ lval_reg_locn(RegMap0, succip, Op0, Instr0),
+ ll_backend.x86_64_regs.reg_map_remove_scratch_reg(RegMap0, RegMap),
+ (
+ Op0 = yes(Op)
+ ;
+ Op0 = no,
+ (
+ Instr0 = yes(Instr),
+ ( get_last_instr_opand(Instr, LastOpand) ->
+ Op = LastOpand
+ ;
+ unexpected(this_file, "instr_to_x86_64: llcall: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Instr0 = no,
+ unexpected(this_file, "instr_to_x86_64: llcall: unexpected:" ++
+ " lval_reg_locn failed")
+ )
+ ),
+ Instr1 = x86_64_instr(mov(operand_label(Continuation1), Op)),
Instr2 = x86_64_instr(jmp(operand_label(Target1))),
Instrs = [Instr1, Instr2].
-instr_to_x86_64(mkframe(_, _), [x86_64_comment("<<mkframe>>")]).
-instr_to_x86_64(label(Label), Instrs) :-
+instr_to_x86_64(RegMap, mkframe(_, _), RegMap, [x86_64_comment("<<mkframe>>")]).
+instr_to_x86_64(RegMap, label(Label), RegMap, Instrs) :-
LabelStr = ll_backend.llds_out.label_to_c_string(Label, no),
Instrs = [x86_64_label(LabelStr)].
-instr_to_x86_64(goto(CodeAddr), Instrs) :-
+instr_to_x86_64(RegMap, goto(CodeAddr), RegMap, Instrs) :-
code_addr_type(CodeAddr, Label),
Instrs = [x86_64_instr(jmp(operand_label(Label)))].
-instr_to_x86_64(computed_goto(Rval, Labels), Instrs) :-
- transform_rval(Rval, Res0, Res1),
+instr_to_x86_64(RegMap0, computed_goto(Rval, Labels), RegMap, Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap1, Res0, Res1),
(
Res0 = yes(RvalOp),
RvalInstrs = []
@@ -268,17 +298,19 @@
)
),
labels_to_string(Labels, "", LabelStr),
- TempReg = operand_reg(gp_reg(13)),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap1),
+ ll_backend.x86_64_regs.reg_map_remove_scratch_reg(RegMap1, RegMap),
+ TempReg = operand_reg(ScratchReg),
Instr0 = x86_64_instr(mov(operand_mem_ref(mem_abs(base_expr(LabelStr))),
TempReg)),
Instr1 = x86_64_instr(add(RvalOp, TempReg)),
Instr2 = x86_64_instr(jmp(TempReg)),
Instrs = RvalInstrs ++ [Instr0] ++ [Instr1] ++ [Instr2].
-instr_to_x86_64(arbitrary_c_code(_, _, _), Instrs) :-
+instr_to_x86_64(RegMap, arbitrary_c_code(_, _, _), RegMap, Instrs) :-
Instrs = [x86_64_comment("<<arbitrary_c_code>>")].
-instr_to_x86_64(if_val(Rval, CodeAddr), Instrs) :-
+instr_to_x86_64(RegMap0, if_val(Rval, CodeAddr), RegMap, Instrs) :-
code_addr_type(CodeAddr, Target),
- transform_rval(Rval, Res0, Res1),
+ transform_rval(RegMap0, Rval, RegMap, Res0, Res1),
(
Res0 = yes(RvalOp)
;
@@ -297,14 +329,17 @@
++ " Rval")
)
),
- ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ ll_backend.x86_64_out.operand_to_string(RvalOp, RvalStr),
Instrs = [x86_64_directive(x86_64_pseudo_if(RvalStr)), x86_64_instr(j(
operand_label(Target), e)), x86_64_directive(endif)].
-instr_to_x86_64(save_maxfr(_), [x86_64_comment("<<save_maxfr>>")]).
-instr_to_x86_64(restore_maxfr(_), [x86_64_comment("<<restore_maxfr>>")]).
-instr_to_x86_64(incr_hp(Lval, Tag0, Words0, Rval, _, _), Instrs) :-
- transform_rval(Rval, Res0, Res1),
- transform_lval(Lval, Res2, Res3),
+instr_to_x86_64(RegMap, save_maxfr(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<save_maxfr>>")].
+instr_to_x86_64(RegMap, restore_maxfr(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<restore_maxfr>>")].
+instr_to_x86_64(RegMap0, incr_hp(Lval, Tag0, Words0, Rval, _, _), RegMap,
+ Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap1, Res0, Res1),
+ transform_lval(RegMap1, Lval, RegMap2, Res2, Res3),
(
Res0 = yes(RvalOp)
;
@@ -344,14 +379,17 @@
(
Words0 = yes(Words),
IncrVal = operand_imm(imm32(int32(Words))),
- TempReg = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ ScratchReg0 = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap2),
+ reg_map_remove_scratch_reg(RegMap2, RegMap3),
+ TempReg1 = operand_reg(ScratchReg0),
+ ll_backend.x86_64_out.operand_to_string(RvalOp, RvalStr),
MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
- LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
- IncrAddInstr = x86_64_instr(add(IncrVal, TempReg)),
+ LoadAddr = x86_64_instr(lea(MemRef, TempReg1)),
+ IncrAddInstr = x86_64_instr(add(IncrVal, TempReg1)),
list.append([LoadAddr], [IncrAddInstr], IncrAddrInstrs)
;
Words0 = no,
+ RegMap3 = RegMap2,
IncrAddrInstrs = []
),
(
@@ -360,86 +398,141 @@
Tag0 = no,
Tag = 0
),
- TempReg = operand_reg(gp_reg(13)),
- ImmToReg = x86_64_instr(mov(RvalOp, TempReg)),
- SetTag = x86_64_instr(or(operand_imm(imm32(int32(Tag))), TempReg)),
- Instr0 = x86_64_instr(mov(TempReg, LvalOp)),
- Instrs = IncrAddrInstrs ++ [ImmToReg] ++ [SetTag] ++ [Instr0].
-instr_to_x86_64(mark_hp(_), [x86_64_comment("<<mark_hp>>")]).
-instr_to_x86_64(restore_hp(_), [x86_64_comment("<<restore_hp>>")]).
-instr_to_x86_64(free_heap(_), [x86_64_comment("<<free_heap>>")]).
-instr_to_x86_64(store_ticket(_), [x86_64_comment("<<store_ticket>>")]).
-instr_to_x86_64(reset_ticket(_, _), [x86_64_comment("<<reset_ticket>>")]).
-instr_to_x86_64(prune_ticket, [x86_64_comment("<<prune_ticket>>")]).
-instr_to_x86_64(discard_ticket, [x86_64_comment("<<discard_ticket>>")]).
-instr_to_x86_64(mark_ticket_stack(_), [x86_64_comment("<<mark_ticket_stack>>")]).
-instr_to_x86_64(prune_tickets_to(_), [x86_64_comment("<<prune_tickets_to>>")]).
-instr_to_x86_64(incr_sp(NumSlots, ProcName, _), Instrs) :-
+ ScratchReg1 = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap3),
+ reg_map_remove_scratch_reg(RegMap3, RegMap),
+ TempReg2 = operand_reg(ScratchReg1),
+ ImmToReg = x86_64_instr(mov(RvalOp, TempReg2)),
+ SetTag = x86_64_instr(or(operand_imm(imm32(int32(Tag))), TempReg2)),
+ Instr1 = x86_64_instr(mov(TempReg2, LvalOp)),
+ Instrs = IncrAddrInstrs ++ [ImmToReg] ++ [SetTag] ++ [Instr1].
+instr_to_x86_64(RegMap, mark_hp(_), RegMap, [x86_64_comment("<<mark_hp>>")]).
+instr_to_x86_64(RegMap, restore_hp(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<restore_hp>>")].
+instr_to_x86_64(RegMap, free_heap(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<free_heap>>")].
+instr_to_x86_64(RegMap, store_ticket(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<store_ticket>>")].
+instr_to_x86_64(RegMap, reset_ticket(_, _), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<reset_ticket>>")].
+instr_to_x86_64(RegMap, prune_ticket, RegMap, Instr) :-
+ Instr = [x86_64_comment("<<prune_ticket>>")].
+instr_to_x86_64(RegMap, discard_ticket, RegMap, Instr) :-
+ Instr = [x86_64_comment("<<discard_ticket>>")].
+instr_to_x86_64(RegMap, mark_ticket_stack(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<mark_ticket_stack>>")].
+instr_to_x86_64(RegMap, prune_tickets_to(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<prune_tickets_to>>")].
+instr_to_x86_64(RegMap, incr_sp(NumSlots, ProcName, _), RegMap, Instrs) :-
Instr1 = x86_64_comment("<<incr_sp>> " ++ ProcName),
Instr2 = x86_64_instr(enter(uint16(NumSlots), uint8(0))),
Instrs = [Instr1, Instr2].
-instr_to_x86_64(decr_sp(NumSlots), Instrs) :-
+instr_to_x86_64(RegMap0, decr_sp(NumSlots), RegMap, Instrs) :-
DecrOp = operand_imm(imm32(int32(NumSlots))),
- Instr = x86_64_instr(sub(DecrOp, operand_reg(gp_reg(13)))),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap0),
+ ll_backend.x86_64_regs.reg_map_remove_scratch_reg(RegMap0, RegMap),
+ Instr = x86_64_instr(sub(DecrOp, operand_reg(ScratchReg))),
list.append([x86_64_comment("<<decr_sp>> ")], [Instr], Instrs).
-instr_to_x86_64(decr_sp_and_return(NumSlots), Instrs) :-
+instr_to_x86_64(RegMap, decr_sp_and_return(NumSlots), RegMap, Instrs) :-
Instrs = [x86_64_comment("<<decr_sp_and_return>> " ++
string.int_to_string(NumSlots))].
-instr_to_x86_64(foreign_proc_code(_, _, _, _, _, _, _, _, _),
- [x86_64_comment("<<foreign_proc_code>>")]).
-instr_to_x86_64(init_sync_term(_, _), [x86_64_comment("<<init_sync_term>>")]).
-instr_to_x86_64(fork(_), [x86_64_comment("<<fork>>")]).
-instr_to_x86_64(join_and_continue(_, _), [x86_64_comment("<<join_and_continue>>")]).
-
+instr_to_x86_64(RegMap, foreign_proc_code(_, _, _, _, _, _, _, _, _), RegMap,
+ Instr) :-
+ Instr = [x86_64_comment("<<foreign_proc_code>>")].
+instr_to_x86_64(RegMap, init_sync_term(_, _), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<init_sync_term>>")].
+instr_to_x86_64(RegMap, fork(_), RegMap, [x86_64_comment("<<fork>>")]).
+instr_to_x86_64(RegMap, join_and_continue(_, _), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<join_and_continue>>")].
% Transform lval into either an x86_64 operand or x86_64 instructions.
%
-:- pred transform_lval(lval::in, maybe(operand)::out,
+:- pred transform_lval(reg_map::in, lval::in, reg_map::out, maybe(operand)::out,
maybe(list(x86_64_instr))::out) is det.
-transform_lval(reg(CReg, CRegNum), Op, no) :-
- (
+transform_lval(RegMap0, reg(CReg, CRegNum), RegMap, Op, Instr) :-
+ (
CReg = reg_r,
- Op = yes(operand_reg(gp_reg(CRegNum)))
+ lval_reg_locn(RegMap, reg(CReg, CRegNum), Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap)
;
CReg = reg_f,
- Op = no
+ unexpected(this_file, "transform_lval: unexpected: llds reg_f")
).
-transform_lval(succip, yes(operand_label("<<succip>>")), no).
-transform_lval(maxfr, yes(operand_label("<<maxfr>>")), no).
-transform_lval(curfr, yes(operand_label("<<curfr>>")), no).
-transform_lval(hp, yes(operand_label("<<hp>>")), no).
-transform_lval(sp, yes(operand_label("<<sp>>")), no).
-transform_lval(parent_sp, yes(operand_label("<<parent_sp>>")), no).
-transform_lval(temp(CReg, CRegNum), Op, no) :-
- (
- CReg = reg_r,
- Op = yes(operand_reg(gp_reg(CRegNum)))
+transform_lval(RegMap0, succip, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, succip, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, maxfr, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, maxfr, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, curfr, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, curfr, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, hp, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, hp, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, sp, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, sp, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap, parent_sp, RegMap, Op, no) :-
+ Op = yes(operand_label("<<parent_sp>>")).
+transform_lval(RegMap, temp(CReg, CRegNum), RegMap1, Op, Instr) :-
+ transform_lval(RegMap, reg(CReg, CRegNum), RegMap1, Op, Instr).
+transform_lval(RegMap0, stackvar(Offset), RegMap, Op, Instr) :-
+ RegLocn = reg_map_lookup_reg_locn(RegMap, sp),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap0),
+ reg_map_remove_scratch_reg(RegMap0, RegMap),
+ (
+ RegLocn = actual(Reg),
+ Op = no,
+ Instr = yes([x86_64_instr(mov(operand_mem_ref(
+ mem_abs(base_reg(Offset, Reg))), operand_reg(ScratchReg) ))])
;
- CReg = reg_f,
- Op = no
+ RegLocn = virtual(SlotNum),
+ Op = no,
+ FakeRegVal = "$" ++ "virtual_reg(" ++ string.int_to_string(SlotNum)
+ ++ ") + " ++ string.int_to_string(Offset),
+ Instr = yes([x86_64_instr(mov(
+ operand_label(FakeRegVal), operand_reg(ScratchReg)))])
).
-transform_lval(stackvar(Offset), Op, no) :-
- Op = yes(operand_label(string.int_to_string(Offset) ++ "(<<stackvar>>)")).
-transform_lval(parent_stackvar(_), yes(operand_label("<<parent_stackvar>>")), no).
-transform_lval(framevar(_), yes(operand_label("<<framevar>>")), no).
-transform_lval(succip_slot(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(redoip_slot(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(redofr_slot(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(succfr_slot(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(prevfr_slot(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(mem_ref(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(global_var_ref(env_var_ref(Name)), yes(operand_label(Name)), no).
-transform_lval(lvar(_), yes(operand_label("<<lvar>>")), no).
-transform_lval(field(Tag0, Rval1, Rval2), no, Instrs) :-
- transform_rval(Rval1, Res0, Res1),
- transform_rval(Rval2, Res2, Res3),
+transform_lval(RegMap, parent_stackvar(_), RegMap, Op, no) :-
+ Op = yes(operand_label("<<parent_stackvar>>")).
+transform_lval(RegMap0, framevar(Offset), RegMap, Op, Instr) :-
+ ScratchReg= ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap),
+ reg_map_remove_scratch_reg(RegMap0, RegMap),
+ RegLocn = reg_map_lookup_reg_locn(RegMap, curfr),
+ % framevar(Int) refers to an offset Int relative to the current value of
+ % 'curfr'
+ (
+ RegLocn = actual(Reg),
+ Op = no,
+ Instr = yes([x86_64_instr(mov(operand_mem_ref(
+ mem_abs(base_reg(Offset, Reg))), operand_reg(ScratchReg) ))])
+ ;
+ RegLocn = virtual(SlotNum),
+ Op = no,
+ FakeRegVal = "$" ++ "virtual_reg(" ++ string.int_to_string(SlotNum)
+ ++ ") + " ++ string.int_to_string(Offset),
+ Instr = yes([x86_64_instr(mov(
+ operand_label(FakeRegVal), operand_reg(ScratchReg)))])
+ ).
+transform_lval(RegMap0, succip_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, redoip_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, redofr_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, succfr_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, prevfr_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, mem_ref(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap, global_var_ref(env_var_ref(Name)), RegMap, Op, no) :-
+ Op = yes(operand_label(Name)).
+transform_lval(RegMap, lvar(_), RegMap, yes(operand_label("<<lvar>>")), no).
+transform_lval(RegMap0, field(Tag0, Rval1, Rval2), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval1, RegMap1, Res0, Res1),
+ transform_rval(RegMap1, Rval2, RegMap2, Res2, Res3),
(
Res0 = yes(RvalOp1),
Instrs1 = []
@@ -478,8 +571,10 @@
unexpected(this_file, "lval_instrs: field: unexpected: Rval2")
)
),
- TempReg1 = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(RvalOp1, RvalStr1),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap2),
+ reg_map_remove_scratch_reg(RegMap2, RegMap),
+ TempReg1 = operand_reg(ScratchReg),
+ ll_backend.x86_64_out.operand_to_string(RvalOp1, RvalStr1),
MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr1))),
LoadAddr = x86_64_instr(lea(MemRef, TempReg1)),
FieldNum = x86_64_instr(add(RvalOp2, TempReg1)),
@@ -495,14 +590,14 @@
% Translates rval into its corresponding x86_64 operand.
%
-:- pred transform_rval(rval::in, maybe(operand)::out, maybe(list(x86_64_instr))
- ::out) is det.
+:- pred transform_rval(reg_map::in, rval::in, reg_map::out, maybe(operand)::out,
+ maybe(list(x86_64_instr)) ::out) is det.
-transform_rval(lval(Lval0), Op, Instrs) :-
- transform_lval(Lval0, Op, Instrs).
-transform_rval(var(_), yes(operand_label("<<var>>")), no).
-transform_rval(mkword(Tag, Rval), no, Instrs) :-
- transform_rval(Rval, Res0, Res1),
+transform_rval(RegMap0, lval(Lval0), RegMap, Op, Instrs) :-
+ transform_lval(RegMap0, Lval0, RegMap, Op, Instrs).
+transform_rval(RegMap, var(_), RegMap, yes(operand_label("<<var>>")), no).
+transform_rval(RegMap0, mkword(Tag, Rval), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap1, Res0, Res1),
(
Res0 = yes(RvalOp),
list.append([x86_64_comment("<<mkword>>")], [], Instr0)
@@ -522,27 +617,33 @@
unexpected(this_file, "transform_rval: mkword unexpected: Rval")
)
),
- TempReg = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap1),
+ reg_map_remove_scratch_reg(RegMap1, RegMap),
+ TempReg = operand_reg(ScratchReg),
+ ll_backend.x86_64_out.operand_to_string(RvalOp, RvalStr),
MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
SetTag = x86_64_instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
Instrs = yes(Instr0 ++ [LoadAddr] ++ [SetTag]).
-transform_rval(const(llconst_true), yes(operand_label("<<llconst_true>>")), no).
-transform_rval(const(llconst_false), yes(operand_label("<<llconst_false>>")), no).
-transform_rval(const(llconst_int(Val)), yes(operand_imm(imm32(int32(Val)))), no).
-transform_rval(const(llconst_float(_)), yes(operand_label("<<llconst_float>>")), no).
-transform_rval(const(llconst_string(String)), no, yes(Op)) :-
+transform_rval(RegMap, const(llconst_true), RegMap, Op, no) :-
+ Op = yes(operand_label("<<llconst_true>>")).
+transform_rval(RegMap, const(llconst_false), RegMap, Op, no) :-
+ Op = yes(operand_label("<<llconst_false>>")).
+transform_rval(RegMap, const(llconst_int(Val)), RegMap, Op, no) :-
+ Op = yes(operand_imm(imm32(int32(Val)))).
+transform_rval(RegMap, const(llconst_float(_)), RegMap, Op, no) :-
+ Op = yes(operand_label("<<llconst_float>>")).
+transform_rval(RegMap, const(llconst_string(String)), RegMap, no, yes(Op)) :-
Op = [x86_64_directive(string([String]))].
-transform_rval(const(llconst_multi_string(_, _)), Op, no) :-
+transform_rval(RegMap, const(llconst_multi_string(_, _)), RegMap, Op, no) :-
Op = yes(operand_label("<<llconst_multi_string>>")).
-transform_rval(const(llconst_code_addr(CodeAddr)), Op, no) :-
+transform_rval(RegMap, const(llconst_code_addr(CodeAddr)), RegMap, Op, no) :-
code_addr_type(CodeAddr, CodeAddrType),
- Op = yes(operand_label("<<llconst_code_addr>>" ++ CodeAddrType)).
-transform_rval(const(llconst_data_addr(_, _)), Op, no) :-
+ Op = yes(operand_label(CodeAddrType)).
+transform_rval(RegMap, const(llconst_data_addr(_, _)), RegMap, Op, no) :-
Op = yes(operand_label("<<llconst_data_addr>>")).
-transform_rval(unop(Op, Rval), no, Instrs) :-
- transform_rval(Rval, Res0, Res1),
+transform_rval(RegMap0, unop(Op, Rval), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap, Res0, Res1),
(
Res0 = yes(_),
unop_instrs(Op, Res0, no, Instrs0),
@@ -558,9 +659,9 @@
unexpected(this_file, "transform_rval: unop: unexpected: Rval")
)
).
-transform_rval(binop(Op, Rval1, Rval2), no, Instrs) :-
- transform_rval(Rval1, Res1, Res2),
- transform_rval(Rval2, Res3, Res4),
+transform_rval(RegMap0, binop(Op, Rval1, Rval2), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval1, RegMap1, Res1, Res2),
+ transform_rval(RegMap1, Rval2, RegMap, Res3, Res4),
(
Res1 = yes(Val1),
(
@@ -606,13 +707,14 @@
unexpected(this_file, "rval_instrs: binop: unexpected: Rval1")
)
).
-transform_rval(mem_addr(stackvar_ref(Rval)), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_rval(mem_addr(framevar_ref(Rval)), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_rval(mem_addr(heap_ref(Rval1, Tag, Rval2)), no, Instrs) :-
- transform_rval(Rval1, Res0, Res1),
- transform_rval(Rval2, Res2, Res3),
+transform_rval(RegMap0, mem_addr(stackvar_ref(Rval)), RegMap, Op, no) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, _).
+transform_rval(RegMap0, mem_addr(framevar_ref(Rval)), RegMap, Op, no) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, _).
+transform_rval(RegMap0, mem_addr(heap_ref(Rval1, Tag, Rval2)), RegMap,
+ no, Instrs) :-
+ transform_rval(RegMap0, Rval1, RegMap1, Res0, Res1),
+ transform_rval(RegMap1, Rval2, RegMap2, Res2, Res3),
(
Res0 = yes(Rval1Op),
(
@@ -672,14 +774,42 @@
++ " unexpected: Rval1")
)
),
- TempReg = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(Rval1Op, Rval1Str),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap2),
+ reg_map_remove_scratch_reg(RegMap2, RegMap),
+ TempReg = operand_reg(ScratchReg),
+ ll_backend.x86_64_out.operand_to_string(Rval1Op, Rval1Str),
MemRef = operand_mem_ref(mem_abs(base_expr(Rval1Str))),
LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
Instr0 = x86_64_instr(sub(Rval2Op, TempReg)),
Instr1 = x86_64_instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
Instrs = yes(Instrs0 ++ [LoadAddr] ++ [Instr0] ++ [Instr1]).
+
+ % Given an llds-lval, returns either an operand or instructions (actually,
+ % it only a single move instruction. It returns a list so that the calling
+ % predicate won't have to do any rearrangements for the return value). If
+ % lval is located in an actual register, returns the actual register which
+ % corresponds to that lval. Otherwise, move lval from the fake-reg array
+ % to a temporary register.
+ %
+:- pred lval_reg_locn(reg_map::in, lval::in, maybe(operand)::out,
+ maybe(list(x86_64_instr))::out) is det.
+
+lval_reg_locn(RegMap, Lval, Op, Instr) :-
+ RegLocn = reg_map_lookup_reg_locn(RegMap, Lval),
+ (
+ RegLocn = actual(Reg),
+ Op = yes(operand_reg(Reg)),
+ Instr = no
+ ;
+ RegLocn = virtual(SlotNum),
+ Op = no,
+ FakeRegVal = "fake_reg(" ++ string.int_to_string(SlotNum) ++ ")",
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap),
+ Instr = yes([x86_64_instr(mov(operand_mem_ref(mem_abs(
+ base_expr(FakeRegVal))), operand_reg(ScratchReg)))])
+ ).
+
% x86_64 instructions for binary operation with either an operand or an
% expression (given as a list of x86_64 instructions) or a combination of
% both.
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.429
diff -u -r1.429 mercury_compile.m
--- compiler/mercury_compile.m 9 Feb 2007 04:05:16 -0000 1.429
+++ compiler/mercury_compile.m 12 Feb 2007 22:47:47 -0000
@@ -127,6 +127,8 @@
:- import_module ll_backend.llds_to_x86_64.
:- import_module ll_backend.llds_to_x86_64_out.
:- import_module ll_backend.x86_64_instrs.
+:- import_module ll_backend.x86_64_out.
+:- import_module ll_backend.x86_64_regs.
% the MLDS back-end
:- import_module ml_backend.add_trail_ops. % HLDS -> HLDS
Index: compiler/x86_64_instrs.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/x86_64_instrs.m,v
retrieving revision 1.2
diff -u -r1.2 x86_64_instrs.m
--- compiler/x86_64_instrs.m 5 Feb 2007 22:30:34 -0000 1.2
+++ compiler/x86_64_instrs.m 19 Feb 2007 05:57:50 -0000
@@ -11,6 +11,9 @@
%
% This module contains the representations of the x86_64 instructions.
%
+% NOTE:
+% Instructions that make use of segment registers and string operations
+% (such as compare_strings) have not been implemented.
%-----------------------------------------------------------------------------%
:- module ll_backend.x86_64_instrs.
@@ -146,6 +149,27 @@
; nle % Not Less or Equal (ZF = 0 and SF = OF).
; g. % Greater (ZF = 0 and SF = OF).
+ % Optional flags argument of .section pseudo_op.
+ %
+:- type pseudo_section_flag
+ ---> a % section is allocatable.
+ ; w % section is writable.
+ ; x % section is executable.
+ ; m % section is mergeable.
+ ; s. % section contains zero terminated string.
+
+ % An optional type of '.section' pseudo-op.
+ %
+:- type pseudo_section_type
+ ---> progbits % section contains data.
+ ; nobits. % section does not contain data.
+
+ % type_desc field of .section pseudo-op.
+ %
+:- type pseudo_section_type_desc
+ ---> function
+ ; object.
+
%-----------------------------------------------------------------------------%
%
% x86_64 pseudo-ops.
@@ -530,8 +554,8 @@
; section(
section_name :: string,
- section_flags :: maybe(string),
- section_type :: maybe(string),
+ section_flags :: maybe(list(pseudo_section_flag)),
+ section_type :: maybe(pseudo_section_type),
section_entsize :: maybe(int)
)
% ELF section stack manipulation directive.
@@ -618,7 +642,7 @@
; x86_64_pseudo_type(
type_name :: string,
- type_desc :: string
+ type_desc :: pseudo_section_type_desc
)
% Set the type of symbol'type_name' to be either a function or an
% object symbol.
@@ -666,8 +690,26 @@
% General purpose registers on the x86_64.
% Details on amd64-prog-man-vol1 manual p27.
%
-:- type gp_reg
- ---> gp_reg(int).
+
+:- type offset == int.
+
+:- type x86_64_reg
+ ---> rax
+ ; rbx
+ ; rcx
+ ; rdx
+ ; rbp
+ ; rsi
+ ; rdi
+ ; rsp
+ ; r8
+ ; r9
+ ; r10
+ ; r11
+ ; r12(offset) % offset(r12) in x86_64 = offset(sp) in llds.
+ ; r13
+ ; r14
+ ; r15.
% 64-bit instruction pointer register on the x86_64. Instruction pointer
% RIP is used as a base register for relative addressing. x86_64
@@ -719,7 +761,7 @@
:- type base_address
---> base_reg(
base_offset :: int,
- base_reg :: gp_reg
+ base_reg :: x86_64_reg
)
; base_expr(
@@ -729,7 +771,7 @@
% All operands for the x86_64 instructions.
%
:- type operand
- ---> operand_reg(gp_reg)
+ ---> operand_reg(x86_64_reg)
; operand_imm(imm_operand)
; operand_mem_ref(x86_64_mem_ref)
; operand_rel_offset(rel_offset)
@@ -751,7 +793,7 @@
% signed relative offset or a label.
%
:- type rmrol
- ---> rmrol_reg(gp_reg)
+ ---> rmrol_reg(x86_64_reg)
; rmrol_mem_ref(x86_64_mem_ref)
; rmrol_rel_offset(rel_offset)
; rmrol_label(
@@ -1277,6 +1319,12 @@
% Details on amd64-prog-man-vol3 manual p272.
%-----------------------------------------------------------------------------%
+
+ % Returns the number of x86_64 general-purpose registers.
+ %
+:- func num_x86_64_regs = int.
+
+%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
@@ -1291,4 +1339,8 @@
init_x86_64_instruction = x86_64_instr([], "").
+num_x86_64_regs = 16.
+
%-----------------------------------------------------------------------------%
+:- end_module ll_backend.x86_64_instrs.
+%----------------------------------------------------------------------------%
Index: compiler/x86_64_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/x86_64_out.m,v
retrieving revision 1.3
diff -u -r1.3 x86_64_out.m
--- compiler/x86_64_out.m 8 Feb 2007 01:02:53 -0000 1.3
+++ compiler/x86_64_out.m 19 Feb 2007 06:06:56 -0000
@@ -13,6 +13,11 @@
% to string writer streams that are attached to the I/O state.
% (There's no particularly good reason for this latter restriction so
% it can safely be dropped if necessary.)
+%
+% NOTE:
+% The module calls unexpected/2 if there is an instruction which expects
+% a different type of operand (For example: an instruction expecting a
+% register operand but supplied with an immediate operand type).
%
%-----------------------------------------------------------------------------%
@@ -31,9 +36,7 @@
:- pred output_x86_64_instruction(Stream::in, x86_64_instruction::in,
io::di, io::uo) is det <= stream.writer(Stream, string, io).
- % XXX this is misnamed: it should be operand_to_string.
- %
-:- pred operand_type(operand::in, string::out) is det.
+:- pred operand_to_string(operand::in, string::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -41,6 +44,7 @@
:- implementation.
:- import_module libs.compiler_util.
+:- import_module ll_backend.x86_64_regs.
:- import_module bool.
:- import_module char.
@@ -233,13 +237,10 @@
Result0 = yes,
Type0 = yes(Type1)
->
- put(Stream, ",\"" ++ Flags1 ++ "\"", !IO),
- ( check_pseudo_section_type(Type1) ->
- put(Stream, "," ++ Type1, !IO)
- ;
- unexpected(this_file, "output_x86_64_pseudo_op: section:"
- ++ " check_section_type unexpected")
- )
+ pseudo_section_flags_to_string(Flags1, "", FlagsStr),
+ put(Stream, ",\"" ++ FlagsStr ++ "\"", !IO),
+ check_pseudo_section_type(Type1, Type1Str),
+ put(Stream, "," ++ Type1Str, !IO)
;
unexpected(this_file, "output_x86_64_pseudo_op: section:"
++ " check_section_flags_and_type unexpected")
@@ -291,12 +292,8 @@
output_x86_64_pseudo_op(Stream, title(Heading), !IO) :-
put(Stream, "\t.title\t" ++ Heading ++ "\n", !IO).
output_x86_64_pseudo_op(Stream, x86_64_pseudo_type(Name, Desc), !IO) :-
- ( check_pseudo_type_desc(Desc) ->
- put(Stream, "\t.type\t" ++ Name ++ "," ++ Desc ++ "\n", !IO)
- ;
- unexpected(this_file, "output_x86_64_pseudo_op: x86_64_pseudo_type:"
- ++ " unexpected: check_pseudo_type_desc failed")
- ).
+ check_pseudo_type_desc(Desc, DescType),
+ put(Stream, "\t.type\t" ++ Name ++ "," ++ DescType ++ "\n", !IO).
output_x86_64_pseudo_op(Stream, uleb128(ExprList), !IO) :-
output_pseudo_op_str_args(Stream, ".uleb128", ExprList, !IO).
output_x86_64_pseudo_op(Stream, val(Addr), !IO) :-
@@ -394,74 +391,96 @@
% Check if the FLAGS and TYPE argumentis of '.section' pseudo-op
% are valid.
%
-:- pred check_section_flags_and_type(string::in, maybe(string)::in,
- bool::out) is det.
+:- pred check_section_flags_and_type(list(pseudo_section_flag)::in,
+ maybe(pseudo_section_type)::in, bool::out) is det.
check_section_flags_and_type(Flags, Type0, Result) :-
- ( string.contains_char(Flags, 'M') ->
+ check_pseudo_section_m_flag(Flags, Result0),
+ (
+ Result0 = yes,
(
Type0 = yes(Type1),
- string.length(Type1) > 0
+ check_pseudo_section_type(Type1, _)
->
true
;
unexpected(this_file, "check_section_flags_and_type:"
- ++ " unexpected: flag")
+ ++ " unexpected: flag 'm' has to have 'type' arguments")
)
;
+ Result0 = no,
true
),
- string.to_char_list(Flags, CharList),
- check_pseudo_section_flags(CharList, Result0),
+ check_pseudo_section_flags(Flags, Result1),
(
- Result0 = yes,
+ Result1 = yes,
Result = yes
;
- Result0 = no,
+ Result1 = no,
Result = no
).
% Check if the FLAGS argument of '.section' pseudo-op is valid.
%
-:- pred check_pseudo_section_flags(list(char)::in, bool::out) is det.
+:- pred check_pseudo_section_flags(list(pseudo_section_flag)::in, bool::out)
+ is det.
check_pseudo_section_flags([], yes).
-check_pseudo_section_flags([Char | Chars], Result) :-
- ( string.contains_char(section_pseudo_op_flags, Char) ->
- check_pseudo_section_flags(Chars, Result)
- ;
- Result = no
- ).
+check_pseudo_section_flags([Flag | Flags], Result) :-
+ pseudo_section_flag(Flag, _),
+ check_pseudo_section_flags(Flags, Result).
- % The optional FLAGS argument of '.section' pseudo-op contains any
- % combination of:
- % 'a' - section is allocatable
- % 'w' - section is writable
- % 'x' - section is executable
- % 'M' - section is mergeable
- % 'S' - section contains zero terminated string
+ % Returns a string representation of optional flag arguments of
+ % .section pseudo instruction.
%
-:- func section_pseudo_op_flags = string.
+:- pred pseudo_section_flags_to_string(list(pseudo_section_flag)::in,
+ string::in, string::out) is det.
+
+pseudo_section_flags_to_string([], Result, Result).
+pseudo_section_flags_to_string([Flag | Flags], Result0, Result) :-
+ pseudo_section_flag(Flag, FlagString),
+ pseudo_section_flags_to_string(Flags, FlagString ++ Result0, Result).
+
+ % Returns a string representation of a .section pseudo-instruction flag.
+ %
+:- pred pseudo_section_flag(pseudo_section_flag::in, string::out) is det.
+
+pseudo_section_flag(a, "a").
+pseudo_section_flag(w, "w").
+pseudo_section_flag(x, "x").
+pseudo_section_flag(m, "m").
+pseudo_section_flag(s, "s").
-section_pseudo_op_flags = "awxMS".
+ % If a .section pseudo-instruction has 'm' flag, there has to be
+ % 'type' argument as its second argument.
+ %
+:- pred check_pseudo_section_m_flag(list(pseudo_section_flag)::in,
+ bool::out) is det.
+
+check_pseudo_section_m_flag([], no).
+check_pseudo_section_m_flag([Flag | Flags], Result) :-
+ pseudo_section_flag(Flag, FlagType),
+ ( FlagType = "m" ->
+ Result = yes
+ ;
+ check_pseudo_section_m_flag(Flags, Result)
+ ).
- % The optional type of '.section' pseudo-op may contain:
- % @progbits - section contains data
- % @nobits - section does not contain data
+ % Checks if .type argument of .section pseudo-instruction is valid.
%
-:- pred check_pseudo_section_type(string::in) is semidet.
+:- pred check_pseudo_section_type(pseudo_section_type::in, string::out)
+ is det.
-check_pseudo_section_type("@progbits").
-check_pseudo_section_type("@nobits").
+check_pseudo_section_type(progbits, "@progbits").
+check_pseudo_section_type(nobits, "@nobits").
- % Two valid values of 'type_desc' field in pseudo-op '.type':
- % @function
- % @object
+ % Checks if type_desc argument of .section pseudo-instruction is valid.
%
-:- pred check_pseudo_type_desc(string::in) is semidet.
+:- pred check_pseudo_type_desc(pseudo_section_type_desc::in, string::out)
+ is det.
-check_pseudo_type_desc("@function").
-check_pseudo_type_desc("@function").
+check_pseudo_type_desc(function, "@function").
+check_pseudo_type_desc(object, "@object").
:- func comment_length = int.
@@ -532,7 +551,7 @@
check_operand_not_immediate(Src, Result1),
(
Result1 = yes,
- operand_type(Src, SrcType),
+ operand_to_string(Src, SrcType),
check_operand_register(Dest, DestRes),
(
DestRes = yes,
@@ -546,7 +565,7 @@
++ " invalid condition third operand")
),
put(Stream, "\t" ++ Instr ++ "\t", !IO),
- operand_type(Dest, DestType),
+ operand_to_string(Dest, DestType),
put(Stream, SrcType ++ ", " ++ DestType ++ "\t", !IO)
;
DestRes = no,
@@ -562,7 +581,7 @@
check_operand_register(Op, Result),
(
Result = yes,
- operand_type(Op, RegType),
+ operand_to_string(Op, RegType),
put(Stream, "\tbswap\t" ++ RegType ++ "\t\t", !IO)
;
Result = no,
@@ -581,7 +600,7 @@
check_operand_not_immediate(Target, Result),
(
Result = yes,
- operand_type(Target, TargetType),
+ operand_to_string(Target, TargetType),
put(Stream, "\tcall\t" ++ TargetType ++ "\t\t", !IO)
;
Result = no,
@@ -617,8 +636,8 @@
check_operand_register(Dest, Result2),
(
Result2 = yes,
- operand_type(Src, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Src, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tcmp\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -634,7 +653,7 @@
check_operand_not_mem_ref(Op, Result),
(
Result = no,
- operand_type(Op, OpType),
+ operand_to_string(Op, OpType),
put(Stream, "\tcmpxchg8b" ++ OpType, !IO)
;
Result = yes,
@@ -666,23 +685,23 @@
output_x86_64_inst(Stream, idiv(Operand), !IO) :-
output_instr_not_imm_dest(Stream, "idiv", Operand, no, !IO).
output_x86_64_inst(Stream, imul(Src, Dest, Mult), !IO) :-
- operand_type(Src, SrcType),
+ operand_to_string(Src, SrcType),
put(Stream, "\timul\t" ++ SrcType, !IO),
(
Dest = yes(DestRes),
check_operand_register(DestRes, Result1),
(
Result1 = yes,
- operand_type(DestRes, DestType)
+ operand_to_string(DestRes, DestType)
;
Result1 = no,
- TempReg = operand_reg(gp_reg(13)),
- operand_type(TempReg, DestType)
+ TempReg = operand_reg(get_scratch_reg),
+ operand_to_string(TempReg, DestType)
),
put(Stream, ", " ++ DestType, !IO),
(
Mult = yes(MultRes),
- operand_type(MultRes, Op3),
+ operand_to_string(MultRes, Op3),
put(Stream, ", " ++ Op3 ++ " ", !IO)
;
Mult = no,
@@ -699,7 +718,7 @@
output_x86_64_inst(Stream, jrcxz(RelOffset), !IO) :-
output_instr_8bit_rel_offset(Stream, "jrcxz", RelOffset, !IO).
output_x86_64_inst(Stream, jmp(Target), !IO) :-
- operand_type(Target, Op),
+ operand_to_string(Target, Op),
put(Stream, "\tjmp\t" ++ Op ++ "\t\t", !IO).
output_x86_64_inst(Stream, lea(Src, Dest), !IO) :-
check_operand_not_mem_ref(Src, Result1),
@@ -708,8 +727,8 @@
check_operand_register(Dest, Result2),
(
Result2 = yes,
- operand_type(Src, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Src, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tlea\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -751,7 +770,7 @@
put(Stream, "\tpopfq\t", !IO).
output_x86_64_inst(Stream, push(Operand), !IO) :-
put(Stream, "\tpush\t", !IO),
- operand_type(Operand, OperandType),
+ operand_to_string(Operand, OperandType),
put(Stream, OperandType ++ "\t", !IO).
output_x86_64_inst(Stream, pushfq, !IO) :-
put(Stream, "\tpushfq\t", !IO).
@@ -762,8 +781,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\trc\t" ++ Cond, !IO),
put(Stream, Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
@@ -807,8 +826,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tro" ++ Dir ++ "\t", !IO),
put(Stream, Op1 ++ ", " ++ Op2 ++ "\t\t", !IO)
;
@@ -828,8 +847,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tsal\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -848,8 +867,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tshl\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -868,8 +887,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tsar\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -903,9 +922,9 @@
check_operand_register(Reg, Result3),
(
Result3 = yes,
- operand_type(Amnt, Op1),
- operand_type(Amnt, Op2),
- operand_type(Amnt, Op3),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Amnt, Op2),
+ operand_to_string(Amnt, Op3),
put(Stream, "\tshld\t" ++ Op1 ++ ", ", !IO),
put(Stream, Op2 ++ ", " ++ Op3 ++ "\t", !IO)
;
@@ -930,8 +949,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tshr\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -953,9 +972,9 @@
check_operand_register(Reg, Result3),
(
Result3 = yes,
- operand_type(Amnt, Op1),
- operand_type(Amnt, Op2),
- operand_type(Amnt, Op3),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Amnt, Op2),
+ operand_to_string(Amnt, Op3),
put(Stream, "\tshrd\t" ++ Op1 ++ ", ", !IO),
put(Stream, Op2 ++ ", " ++ Op3 ++ "\t", !IO)
;
@@ -986,8 +1005,8 @@
check_operand_not_immediate(Src2, Result2),
(
Result2 = yes,
- operand_type(Src1, Op1),
- operand_type(Src2, Op2),
+ operand_to_string(Src1, Op1),
+ operand_to_string(Src2, Op2),
put(Stream, "\ttest\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -1006,8 +1025,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Src, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Src, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\txadd\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -1026,8 +1045,8 @@
check_operand_reg_or_mem(Src2, Result2),
(
Result2 = yes,
- operand_type(Src1, Op1),
- operand_type(Src2, Op2),
+ operand_to_string(Src1, Op1),
+ operand_to_string(Src2, Op2),
put(Stream, "\txchg\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -1062,26 +1081,46 @@
% Output a string representation of an immediate value.
%
-:- pred imm_op_type(imm_operand::in, string::out) is det.
+:- pred imm_op_to_string(imm_operand::in, string::out) is det.
-imm_op_type(imm8(int8(Val)), ImmVal) :-
+imm_op_to_string(imm8(int8(Val)), ImmVal) :-
ImmVal = "$" ++ string.int_to_string(Val).
-imm_op_type(imm16(int16(Val)), ImmVal) :-
+imm_op_to_string(imm16(int16(Val)), ImmVal) :-
ImmVal = "$" ++ string.int_to_string(Val).
-imm_op_type(imm32(int32(Val)), ImmVal) :-
+imm_op_to_string(imm32(int32(Val)), ImmVal) :-
ImmVal = "$" ++ string.int_to_string(Val).
-:- func reg_type(gp_reg) = string.
+:- pred reg_to_string(x86_64_reg::in, string::out) is det.
-reg_type(gp_reg(RegNum)) = "%r" ++ string.int_to_string(RegNum).
+reg_to_string(rax, "%rax").
+reg_to_string(rbx, "%rbx").
+reg_to_string(rcx, "%rcx").
+reg_to_string(rdx, "%rdx").
+reg_to_string(rbp, "%rbp").
+reg_to_string(rsi, "%rsi").
+reg_to_string(rdi, "%rdi").
+reg_to_string(rsp, "%rsp").
+reg_to_string(r8, "%r8").
+reg_to_string(r9, "%r9").
+reg_to_string(r10, "%r10").
+reg_to_string(r11, "%11").
+reg_to_string(r12(Offset), RegStr) :-
+ ( Offset > 0 ->
+ RegStr = string.int_to_string(Offset) ++ "(%r12)"
+ ;
+ RegStr = "%r12"
+ ).
+reg_to_string(r13, "%r13").
+reg_to_string(r14, "%r14").
+reg_to_string(r15, "%r15").
% Output a string representation of a memory reference.
%
-:- pred mem_ref_type(x86_64_mem_ref::in, string::out) is det.
+:- pred mem_ref_to_string(x86_64_mem_ref::in, string::out) is det.
-mem_ref_type(mem_abs(DirectMemRef), MemRefVal) :-
+mem_ref_to_string(mem_abs(DirectMemRef), MemRefVal) :-
base_address_type(DirectMemRef, MemRefVal).
-mem_ref_type(mem_rip(InstrPtr), MemRefVal) :-
+mem_ref_to_string(mem_rip(InstrPtr), MemRefVal) :-
instr_ptr_type(InstrPtr, MemRefVal).
% Output a string representation of a base address in a memory reference.
@@ -1089,11 +1128,12 @@
:- pred base_address_type(base_address::in, string::out) is det.
base_address_type(base_reg(Offset, Reg), BaseAddress) :-
+ reg_to_string(Reg, RegStr),
( Offset = 0 ->
- BaseAddress = "(" ++ reg_type(Reg) ++ ")"
+ BaseAddress = "(" ++ RegStr ++ ")"
;
BaseAddress = string.int_to_string(Offset) ++
- "(" ++ reg_type(Reg) ++ ")"
+ "(" ++ RegStr ++ ")"
).
base_address_type(base_expr(Expr), DispType) :-
DispType = "$" ++ Expr.
@@ -1117,9 +1157,9 @@
% Output a string representation of a relative offset.
%
-:- pred rel_offset_type(rel_offset::in, string::out) is det.
+:- pred rel_offset_to_string(rel_offset::in, string::out) is det.
-rel_offset_type(ro8(int8(Val)), RelOffsetVal) :-
+rel_offset_to_string(ro8(int8(Val)), RelOffsetVal) :-
check_signed_int_size(8, Val, Result),
(
Result = yes,
@@ -1130,10 +1170,10 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro8(int8): unexpected:"
+ unexpected(this_file, "rel_offset_to_string: ro8(int8): unexpected:"
++ " check_signed_int_size failed")
).
-rel_offset_type(ro16(int16(Val)), RelOffsetVal) :-
+rel_offset_to_string(ro16(int16(Val)), RelOffsetVal) :-
check_signed_int_size(16, Val, Result),
(
Result = yes,
@@ -1144,10 +1184,10 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro16(int16): unexpected"
+ unexpected(this_file, "rel_offset_to_string: ro16(int16): unexpected"
++ " check_signed_int_size failed")
).
-rel_offset_type(ro32(int32(Val)), RelOffsetVal) :-
+rel_offset_to_string(ro32(int32(Val)), RelOffsetVal) :-
check_signed_int_size(32, Val, Result),
(
Result = yes,
@@ -1158,20 +1198,20 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro32(int32): unexpected"
+ unexpected(this_file, "rel_offset_to_string: ro32(int32): unexpected"
++ " check_signed_int_size failed")
).
-operand_type(operand_reg(Reg), RegType) :-
- RegType = reg_type(Reg).
-operand_type(operand_imm(Imm), ImmVal) :-
- imm_op_type(Imm, ImmVal).
-operand_type(operand_mem_ref(MemRef), MemRefVal) :-
- mem_ref_type(MemRef, MemRefVal).
-operand_type(operand_rel_offset(RelOffset), RelOffsetType) :-
- rel_offset_type(RelOffset, RelOffsetType).
-operand_type(operand_label(Label), (Label)).
+operand_to_string(operand_reg(Reg), RegType) :-
+ reg_to_string(Reg, RegType).
+operand_to_string(operand_imm(Imm), ImmVal) :-
+ imm_op_to_string(Imm, ImmVal).
+operand_to_string(operand_mem_ref(MemRef), MemRefVal) :-
+ mem_ref_to_string(MemRef, MemRefVal).
+operand_to_string(operand_rel_offset(RelOffset), RelOffsetType) :-
+ rel_offset_to_string(RelOffset, RelOffsetType).
+operand_to_string(operand_label(Label), (Label)).
%-----------------------------------------------------------------------------%
%
@@ -1186,13 +1226,13 @@
is det <= stream.writer(Stream, string, io).
output_instr_not_imm_dest(Stream, Instr, Op1, Op2, !IO) :-
- operand_type(Op1, Op1Type),
+ operand_to_string(Op1, Op1Type),
(
Op2 = yes(Op2Result),
check_not_both_memory_ops(Op1, Op2Result, Result1),
(
Result1 = yes,
- operand_type(Op2Result, Op2Type),
+ operand_to_string(Op2Result, Op2Type),
check_operand_not_immediate(Op2Result, Result2),
(
Result2 = yes,
@@ -1225,7 +1265,7 @@
check_operand_rel_offset(RelOffset, Result1),
(
Result1 = yes,
- operand_type(RelOffset, RelOffsetType),
+ operand_to_string(RelOffset, RelOffsetType),
( string.to_int(RelOffsetType, Val) ->
check_signed_int_size(8, Val, Result2),
(
@@ -1255,11 +1295,11 @@
check_operand_not_immediate(Src, Result1),
(
Result1 = yes,
- operand_type(Src, Op1),
+ operand_to_string(Src, Op1),
check_operand_not_mem_ref(Idx, Result2),
(
Result2 = yes,
- operand_type(Idx, Op2),
+ operand_to_string(Idx, Op2),
( string.to_int(Op2, IdxInt) ->
check_signed_int_size(8, IdxInt, Result3),
(
@@ -1297,14 +1337,14 @@
instr_condition(Cond, CondRes),
put(Stream, "\t" ++ Instr, !IO),
put(Stream, CondRes ++ "\t", !IO),
- operand_type(Op1, Op1Type),
+ operand_to_string(Op1, Op1Type),
put(Stream, Op1Type, !IO),
(
Op2 = yes(Op2Res),
check_operand_register(Op2Res, Result3),
(
Result3 = yes,
- operand_type(Op2Res, Op2Type),
+ operand_to_string(Op2Res, Op2Type),
put(Stream, ", " ++ Op2Type, !IO)
;
Result3 = no,
@@ -1327,7 +1367,7 @@
check_rc_first_operand(Op, Result) :-
( Op = operand_imm(_) ->
- operand_type(Op, OpType),
+ operand_to_string(Op, OpType),
( string.to_int(OpType, OpInt) ->
check_unsigned_int_size(8, OpInt, Result1),
(
@@ -1393,7 +1433,7 @@
check_operand_unsigned_imm_or_reg(Operand, Result) :-
( Operand = operand_imm(Imm) ->
- imm_op_type(Imm, ImmType),
+ imm_op_to_string(Imm, ImmType),
( string.to_int(ImmType, ImmInt) ->
(
check_unsigned_int_size(32, ImmInt, Result1),
Index: compiler/x86_64_regs.m
===================================================================
RCS file: compiler/x86_64_regs.m
diff -N compiler/x86_64_regs.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/x86_64_regs.m 19 Feb 2007 06:05:32 -0000
@@ -0,0 +1,258 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2007 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: x86_64_regs.m.
+% Main author: fhandoko.
+%
+% llds.lval ===> reg_locn
+%
+% NOTE:
+% The first field of reg_map type is a list of available scratch registers.
+% Although the reg_map is updated everytime a scratch register is used in an
+% instruction (updated here means that the new reg_map is equivalent to the
+% old reg_map with the first element (the used scratch register) being
+% removed), it does not seem to work well. It seems to always get the first
+% scratch register. So, there are instructions in which the next instruction
+% overrides the value in a scratch register being used by a previous
+% instruction.
+%-----------------------------------------------------------------------------%
+
+:- module ll_backend.x86_64_regs.
+:- interface.
+
+:- import_module ll_backend.llds.
+:- import_module ll_backend.x86_64_instrs.
+
+:- import_module assoc_list.
+
+%----------------------------------------------------------------------------%
+
+ % This type stores information about the mapping from MVM registers
+ % to x86_64 registers. MVM registers will correspond to either
+ % (1) a physical x86_64 register
+ % or (2) a slot in the fake_reg array (see runtime/mercury_engine.h).
+ %
+:- type reg_map.
+
+ % This type represents the location of an MVM register on x86_64
+ % hardware. `actual/1' is a phyical x86_64 register. `virtual/1'
+ % is the slot in the fake reg array given by the argument.
+ %
+:- type reg_locn
+ ---> actual(x86_64_reg)
+ ; virtual(int). % Index into fake reg array.
+
+ % Create an association list of lvals and reg_lcons.
+ %
+:- pred llds_reg_locn(assoc_list(llds.lval, reg_locn)::out) is det.
+
+ % Create a reg_map given an association list of lvals and reg_locns.
+ % Throws an exception if an l-value in the association list does not
+ % correspond to a MVM register.
+ %
+:- func reg_map_init(assoc_list(llds.lval, reg_locn)) = reg_map.
+
+ % Given an LLDS lval that corresponds to a virtual machine register
+ % look up it's actual location according to the current register mapping.
+ % Throws an exception for l-values that do not correspond to virtual
+ % machine registers.
+ %
+:- func reg_map_lookup_reg_locn(reg_map, llds.lval) = reg_locn.
+
+ % Reset the contents of scratch registers. As a result, all scratch
+ % registers will be available.
+ %
+:- pred reg_map_reset_scratch_reg_info(reg_map::in, reg_map::out) is det.
+
+ % Given a reg_map, get the first available scratch register.
+ %
+:- func reg_map_get_scratch_reg(reg_map) = x86_64_reg.
+
+ % Get an x86_64_register.
+ %
+:- func get_scratch_reg = x86_64_reg.
+
+ % Remove the first index of scratch register list (which is the first
+ % field of reg_map).
+ %
+:- pred reg_map_remove_scratch_reg(reg_map::in, reg_map::out) is det.
+
+%----------------------------------------------------------------------------%
+%----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module libs.compiler_util.
+
+:- import_module bool.
+:- import_module list.
+:- import_module map.
+:- import_module pair.
+:- import_module string.
+
+:- import_module io.
+
+%----------------------------------------------------------------------------%
+%
+% LLDS -> x86_64 register mapping.
+%
+
+:- type reg_map
+ ---> reg_map(
+ scratch_reg_info :: list(x86_64_reg),
+ % A list of available scratch registers.
+ map(llds.lval, reg_locn)
+ % Mapping lval to an actual or virtual register.
+ ).
+
+%----------------------------------------------------------------------------%
+
+llds_reg_locn([
+ sp - actual(r12(0)), % The top of non-det stack frame.
+ succip - actual(r13),
+ reg(reg_r, 1) - actual(r14),
+ reg(reg_r, 2) - actual(r15),
+ reg(reg_r, 3) - virtual(4),
+ hp - virtual(5),
+ reg(reg_r, 4) - virtual(6),
+ reg(reg_r, 5) - virtual(7),
+ curfr - virtual(8),
+ maxfr - virtual(9),
+ reg(reg_r, 6) - virtual(10),
+ reg(reg_r, 7) - virtual(11),
+ reg(reg_r, 8) - virtual(12),
+ reg(reg_r, 9) - virtual(13),
+ reg(reg_r, 10) - virtual(14),
+ reg(reg_r, 11) - virtual(15),
+ reg(reg_r, 12) - virtual(16),
+ reg(reg_r, 13) - virtual(17),
+ reg(reg_r, 14) - virtual(18),
+ reg(reg_r, 15) - virtual(19),
+ reg(reg_r, 16) - virtual(20),
+ reg(reg_r, 17) - virtual(21),
+ reg(reg_r, 18) - virtual(22),
+ reg(reg_r, 19) - virtual(23),
+ reg(reg_r, 20) - virtual(24),
+ reg(reg_r, 21) - virtual(25),
+ reg(reg_r, 22) - virtual(26),
+ reg(reg_r, 23) - virtual(27),
+ reg(reg_r, 24) - virtual(28),
+ reg(reg_r, 25) - virtual(29),
+ reg(reg_r, 26) - virtual(30),
+ reg(reg_r, 27) - virtual(31),
+ reg(reg_r, 28) - virtual(32),
+ reg(reg_r, 29) - virtual(33),
+ reg(reg_r, 30) - virtual(34),
+ reg(reg_r, 31) - virtual(35),
+ reg(reg_r, 32) - virtual(36)
+ ]).
+
+reg_map_init(AssocRegMap) = RegMap :-
+ map.init(Map0),
+ assoc_list.keys(AssocRegMap, ListOfKeys),
+ check_if_all_mvm_registers(ListOfKeys, Result),
+ (
+ Result = yes,
+ map.det_insert_from_assoc_list(Map0, AssocRegMap, Map1),
+ RegMap = reg_map(init_scratch_regs, Map1)
+ ;
+ Result = no,
+ unexpected(this_file, "reg_map_init: unexpected: non-MVM register"
+ ++ " found in the association list")
+ ).
+
+reg_map_lookup_reg_locn(Map, Lval) = RegLocn :-
+ Map = reg_map(_, RegMap),
+ (
+ ( Lval = parent_stackvar(_)
+ ; Lval = succip_slot(_)
+ ; Lval = redoip_slot(_)
+ ; Lval = redofr_slot(_)
+ ; Lval = succfr_slot(_)
+ ; Lval = prevfr_slot(_)
+ ; Lval = mem_ref(_)
+ ; Lval = global_var_ref(_)
+ )
+ ->
+ unexpected(this_file, "reg_map_lookup_reg_locn: unexpected: "
+ ++ "lval is not a virtual machine register")
+ ;
+ Lval = lvar(_)
+ ->
+ unexpected(this_file, "reg_map_lookup_reg_locn: unexpected: "
+ ++ "lvar/1 during x86_64 code generation")
+ ;
+ map.lookup(RegMap, Lval, RegLocn)
+ ).
+
+reg_map_reset_scratch_reg_info(RegMap0, RegMap) :-
+ ScratchRegs = init_scratch_regs,
+ RegMap = RegMap0 ^ scratch_reg_info := ScratchRegs.
+
+reg_map_get_scratch_reg(RegMap) = ScratchReg :-
+ ScratchRegs = RegMap ^ scratch_reg_info,
+ ( list.index0(ScratchRegs, first_list_idx, ScratchReg0) ->
+ ScratchReg = ScratchReg0
+ ;
+ unexpected(this_file, "reg_map_get_scratch_reg: unexpected:"
+ ++ " scratch registers exhausted")
+ ).
+
+reg_map_remove_scratch_reg(RegMap0, RegMap) :-
+ ScratchRegs0 = RegMap0 ^ scratch_reg_info,
+ ( list.drop(first_list_idx, ScratchRegs0, ScratchRegs1) ->
+ RegMap = RegMap0 ^ scratch_reg_info := ScratchRegs1
+ ;
+ unexpected(this_file, "reg_map_remove_scratch_reg: unexpected:"
+ ++ " scratch registers exhausted")
+ ).
+
+ % Check if all l-values in the association list correspond to MVM
+ % registers.
+ %
+:- pred check_if_all_mvm_registers(list(llds.lval)::in, bool::out) is det.
+
+check_if_all_mvm_registers([], yes).
+check_if_all_mvm_registers([Lval | Lvals], Result) :-
+ (
+ ( Lval = reg(reg_r, _)
+ ; Lval = succip
+ ; Lval = maxfr
+ ; Lval = curfr
+ ; Lval = hp
+ ; Lval = sp
+ )
+ ->
+ check_if_all_mvm_registers(Lvals, Result)
+ ;
+ Result = no
+ ).
+
+ % Initialize scratch registers to be used in an instruction.
+ %
+:- func init_scratch_regs = list(x86_64_reg).
+
+init_scratch_regs = [r9, r10, r11].
+
+get_scratch_reg = r9.
+
+ % Returns the index of the first element in the list.
+ %
+:- func first_list_idx = int.
+
+first_list_idx = 0.
+
+%----------------------------------------------------------------------------%
+
+:- func this_file = string.
+
+this_file = "x86_64_regs.m".
+
+%----------------------------------------------------------------------------%
+:- end_module ll_backend.x86_64_regs.
+%----------------------------------------------------------------------------%
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list