[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