[m-rev.] for review: MVM->x86_64 register mapping.

Julien Fischer juliensf at csse.unimelb.edu.au
Tue Feb 20 19:08:36 AEDT 2007


On Mon, 19 Feb 2007, Fransiska Nathania HANDOKO wrote:

> Estimated hours taken: 40 Branches: main
>
> Defines the mapping of MVM registers to x86_64 registers needed by the asm 
> code generator.

This log message is a bit too brief.

 	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 moment 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 register is not mapped to a physical register.

I believe that latter item is currently incomplete but I think that most
of the work had been done?

> compiler/ll_backend.m:
> 	Includes the x86_64_regs module.

Minor changes like the above should be listed last.

> compiler/llds_to_x86_64.m:
> 	Applies the register mapping in the code generator.

I suggest:

 	Apply the register mapping during code generation.

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

> 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.

s/the mapping/a mapping/


> 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>>").


The TODO list should be much more detailed - put yourself in the place
of someone trying to continue this work in 6-12 months time.

>From the looks of it some of the yet to be implemented items are:
 	- calls to arbitrary C code
 	- foreign procs
 	- nondet stack frames
 	- trailing ops
 	- heap ops
 	- parallism

(Although the last three aren't too important at the moment.)

...

> -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].

...

>     % 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>>")).

Just call sorry/2 whenever you see parent_sp, since the x86_64
backend doesn't support parallism yet.

> +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(RegMap, parent_stackvar(_), RegMap, Op, no) :-
> +    Op = yes(operand_label("<<parent_stackvar>>")).

As above.


> +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/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.

You shouldn't hardcode sp == r12 since that is liable to change.
We ought to be able to express an offset from any register.

> +    ;       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,
>

...

> -:- 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").

s/%11/%r11/

> +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

Delete that.

Add a description of what this module does.

> +%
> +% 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.

Put an XXX next to that.

> +
> +    % 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'

s/phyical/physical/

> +    % 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.

This would be better named something like `default_x86_64_reg_mapping'
which is what it is.  The comment should also mention that (for now)
it is indentical to the one defined in runtime/machdeps/x86_64_regs.h.

> +    % 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.
> +

...

> +% +% LLDS -> x86_64 register mapping. +%
> +
> +:- type reg_map
> +	--->	reg_map(
> +				scratch_reg_info        :: list(x86_64_reg), 
> +                % A list of available scratch registers.

What exactly does it mean for them to be available?  Does it mean that they
are currently unused?  If they are currently being used are they still
included in this list?

> +				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

s/non-det/det/

> frame. +        succip          - actual(r13),
> +        reg(reg_r, 1)   - actual(r14),
> +        reg(reg_r, 2)   - actual(r15),

...

> +
> +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")
> +    ).

You can go ahead and commit it after addressing the above points
(and after it passes a bootcheck).

Julien.
--------------------------------------------------------------------------
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