Files
mercury/compiler/ll_backend.m
Fransiska Nathania Handoko 8ad3d82efb Add a mechanism for mapping between MVM registers and x86_64 registers
Estimated hours taken: 40
Branches: main

Add a mechanism for mapping between MVM registers and x86_64 registers
or fake reg array slots. This is needed by the x86_64 asm code generator.
At the momment the mapping is the same as that used by (non .par) grades
that use global register variables on the x86_64.

Modify the x86_64 code generator to emit additional instructions to
perform loads and store to the fake ref array when a virtual machine
registers is not mapped to a physical register.

compiler/x86_64_regs.m:
	Defines a mapping of MVM registers to x86_64 registers.

compiler/x86_64_out.m:
	Fixes some predicates to output asm codes to conform with the changes
	in x86_64_instrs.m.

compiler/llds_to_x86_64.m:
	Applies the register mapping during the code generation.

	Add instructions to access values in the fake reg array.
	(XXX this is still incomplete).

compiler/x86_64_instrs.m:
	Adds discriminated union types and fixes some predicates to make the code
	easier for modification.

compiler/mercury_compile.m:
	Imports x86_64_regs and x86_64_out modules.

compiler/ll_backend.m:
	Includes the x86_64_regs module.


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.
+%----------------------------------------------------------------------------%
2007-02-27 20:36:29 +00:00

111 lines
3.4 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2002,2003-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.
%-----------------------------------------------------------------------------%
%
% This package contains the low-level back-end
% (a.k.a. the LLDS back-end).
%
:- module ll_backend.
:- interface.
:- import_module hlds.
:- import_module mdbcomp.
:- import_module parse_tree.
%-----------------------------------------------------------------------------%
% Pre-passes to transform or annotate the HLDS
:- include_module deep_profiling. % transform
:- include_module saved_vars. % transform
:- include_module stack_opt. % transform
:- include_module follow_code. % transform
:- include_module liveness. % annotate
:- include_module stack_alloc. % annotate
:- include_module live_vars. % annotate
:- include_module follow_vars. % annotate
:- include_module store_alloc. % annotate
% The llds data structure itself
:- include_module llds.
:- include_module code_util.
% The HLDS->LLDS code generator.
:- include_module proc_gen.
:- include_module code_gen.
:- include_module ite_gen.
:- include_module call_gen.
:- include_module disj_gen.
:- include_module unify_gen.
:- include_module commit_gen.
:- include_module switch_gen.
:- include_module dense_switch.
:- include_module lookup_switch.
:- include_module string_switch.
:- include_module tag_switch.
:- include_module pragma_c_gen.
:- include_module par_conj_gen.
:- include_module middle_rec.
:- include_module trace_gen.
:- include_module code_info.
:- include_module lookup_util.
:- include_module exprn_aux.
:- include_module continuation_info.
:- include_module var_locn.
% An alternative HLDS->LLDS code generator for fact tables.
:- include_module fact_table.
%:- module llds_data.
:- include_module ll_pseudo_type_info.
:- include_module layout.
:- include_module stack_layout.
:- include_module prog_rep.
:- include_module global_data.
%:- end_module llds_data.
% LLDS->LLDS optimization passes.
:- include_module optimize.
:- include_module jumpopt.
:- include_module dupelim.
:- include_module dupproc.
:- include_module frameopt.
:- include_module delay_slot.
:- include_module labelopt.
:- include_module stdlabel.
:- include_module peephole.
:- include_module use_local_vars.
:- include_module wrap_blocks.
:- include_module livemap.
:- include_module reassign.
:- include_module basic_block.
:- include_module opt_util.
:- include_module opt_debug.
% The LLDS->C output phase.
:- include_module transform_llds.
:- include_module llds_out.
:- include_module layout_out.
:- include_module rtti_out.
% The LLDS->x86_64 asm phase.
:- include_module llds_to_x86_64.
:- include_module llds_to_x86_64_out.
:- include_module x86_64_instrs.
:- include_module x86_64_out.
:- include_module x86_64_regs.
:- implementation.
:- import_module check_hlds. % needed for type_util, mode_util etc
:- import_module backend_libs.
:- import_module libs.
:- end_module ll_backend.
%-----------------------------------------------------------------------------%