[m-rev.] for review: llds->x86_64 asm generator modules

Ralph Becket rafe at csse.unimelb.edu.au
Mon Feb 5 11:18:51 AEDT 2007


This looks pretty good.  I have made a few comments below and you should
probably wait for a second review by Julien or Zoltan before committing.

-- Ralph

Fransiska Handoko, Monday,  5 February 2007:
> 
> Estimated hours taken: 60
> Branches: main
> 
> Updates the representation of several x86_64 instruction sets to make the
> llds->x86_64 generation simpler. Also adds the llds->x86_64 asm generator
> modules. There are still placeholders in several places in the modules.
> The modules are not working version yet.
> 
> compiler/ll_backend.m:
>     Includes new llds->x86_64 modules.
> 
> compiler/llds_to_x86_64.m:
>     The llds->x86_64 asm generator module.
> 
> compiler/llds_to_x86_64_out.m:
>     Outputs instructions produced by llds->x86_64 asm generator.
> 
> compiler/mercury_compile.m:
>     Imports llds->x86_64 modules.
>     Calls predicates from llds->x86_64 asm generator module.
> 
> compiler/x86_64_instrs.m:
>     Fixes some x86_64 operands and instructions.
> 
> compiler/x86_64_out.m:
>     Fixes some predicates to print out x86_64 instructions.
> 
> 
> index: compiler/ll_backend.m
> ===================================================================
> rCS file: 
> /home/mercury/mercury1/repository/mercury/compiler/ll_backend.m,v
> retrieving revision 1.18
> diff -u -r1.18 ll_backend.m
> --- compiler/ll_backend.m   15 Jan 2007 22:49:41 -0000  1.18
> +++ compiler/ll_backend.m   29 Jan 2007 00:45:30 -0000
> @@ -93,6 +93,8 @@
>  :- include_module rtti_out.
> 
>  % The LLDS->x86_64 asm phase.
> +:- include_module llds_to_x86_64.
> +:- include_module llds_to_x86_64_out.
>  :- include_module x86_64_instrs.
>  :- include_module x86_64_out.
> 
> Index: compiler/llds_to_x86_64.m
> ===================================================================
> RCS file: compiler/llds_to_x86_64.m
> diff -N compiler/llds_to_x86_64.m
> --- /dev/null   1 Jan 1970 00:00:00 -0000
> +++ compiler/llds_to_x86_64.m   2 Feb 2007 05:29:01 -0000
> @@ -0,0 +1,895 @@
>  :- include_module rtti_out.
> 
>  % The LLDS->x86_64 asm phase.
> +:- include_module llds_to_x86_64.
> +:- include_module llds_to_x86_64_out.
>  :- include_module x86_64_instrs.
>  :- include_module x86_64_out.
> 
> Index: compiler/llds_to_x86_64.m
> ===================================================================
> RCS file: compiler/llds_to_x86_64.m
> diff -N compiler/llds_to_x86_64.m
> --- /dev/null   1 Jan 1970 00:00:00 -0000
> +++ compiler/llds_to_x86_64.m   2 Feb 2007 05:29:01 -0000
> @@ -0,0 +1,895 @@
> +%-----------------------------------------------------------------------------%
> +% 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: llds_to_x86_64.m.
> +% Main author: fhandoko.
> +%
> +% This module implements the LLDS->x86_64 asm code generator.
> +%
> +%-----------------------------------------------------------------------------%
> +
> +:- module ll_backend.llds_to_x86_64.
> +:- interface.
> +
> +:- import_module hlds.hlds_module.
> +:- import_module ll_backend.llds.
> +:- import_module ll_backend.x86_64_instrs.
> +
> +:- import_module list.
> +
> +%----------------------------------------------------------------------------%
> +
> +:- pred llds_to_x86_64_asm(module_info::in, list(c_procedure)::in,
> +    list(x86_64_procedure)::out) is det.
> +
> +%----------------------------------------------------------------------------%
> +%----------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module backend_libs.builtin_ops.
> +:- import_module backend_libs.name_mangle.
> +:- import_module libs.compiler_util.
> +:- import_module ll_backend.llds_out.
> +:- import_module ll_backend.x86_64_out.
> +:- import_module mdbcomp.prim_data.
> +
> +:- import_module bool.
> +:- import_module int.
> +:- import_module io.
> +:- import_module maybe.
> +:- import_module set.
> +:- import_module string.
> +
> +%-----------------------------------------------------------------------------%
> +%
> +% binary operation type.
> +%
> +
> +    % A binary operation can consist of two simple operands, one operand
> +    % and one expression or two expressions.
> +    %
> +:- type binop
> +    --->    binop_two_ops(operand, operand)
> +    ;       binop_op_and_instr(operand, list(x86_64_instr))
> +    ;       binop_instr_and_op(list(x86_64_instr), operand)
> +    ;       binop_two_instrs(list(x86_64_instr), list(x86_64_instr)).

I don't understand from the comment what the data constructors mean.
Can you give a separate comment for each constructor?

Why are the instruction fields lists?

The word `op' is usually read as an abbreviation for `operator' rather
than `operand'.  Instead of `op', use something like `opand' or even
`arg' (for `argument').

> +%----------------------------------------------------------------------------%
> +%
> +% llds to x86_64.
> +%
> +
> +llds_to_x86_64_asm(_, CProcs, AsmProcs) :-
> +    transform_c_proc_list(CProcs, AsmProcs).
> +
> +    % Transform a list of c procedure into a list of x86_64 procedure.

s/procedure/procedures/g

> +    %
> +:- pred transform_c_proc_list(list(c_procedure)::in,
> +    list(x86_64_procedure)::out) is det.
> +
> +transform_c_proc_list([], []).
> +transform_c_proc_list([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,
> +

Delete this blank line.

> +    %
> +    % Get the procedure's label and append it as an x86_64 instruction
> +    % list before the output of the llds->x86_64 procedure transformation.
> +    %
> +    ProcStr = backend_libs.name_mangle.proc_label_to_c_string(
> +        AsmProc0 ^ x86_64_proc_label, no),
> +    ProcName = directive(x86_64_pseudo_type(ProcStr, "@function")),
> +    ProcInstr = ProcInstr0 ^ x86_64_inst := [ProcName],
> +    transform_c_instr_list(CProc ^ cproc_code, AsmInstr0),
> +    list.append([ProcInstr], AsmInstr0, AsmInstr),
> +    AsmProc = AsmProc0 ^ x86_64_code := AsmInstr,
> +    transform_c_proc_list(CProcs, AsmProcs).
> +
> +    % Transform a list of c instruction into a list of x86_64 instruction.
> +    %
> +:- pred transform_c_instr_list(list(instruction)::in,
> +    list(x86_64_instruction)::out) is det.
> +
> +transform_c_instr_list([], []).
> +transform_c_instr_list([CInstr0 | CInstr0s], [AsmInstr | AsmInstrs]) :-
> +    CInstr0 = llds_instr(CInstr1, Comment),
> +    instr_to_x86_64(CInstr1, AsmInstrList),
> +    AsmInstr0 = ll_backend.x86_64_instrs.init_x86_64_instruction,
> +    AsmInstr1 = AsmInstr0 ^ x86_64_inst := AsmInstrList,
> +    AsmInstr = AsmInstr1 ^ x86_64_comment := Comment,
> +    transform_c_instr_list(CInstr0s, AsmInstrs).
> +
> +    % Transform a block instruction of an llds instruction into a list of
> +    % x86_64 instruction.
> +    %
> +:- pred transform_block_instr(list(instruction)::in, 
> list(x86_64_instr)::out)
> +    is det.
> +
> +transform_block_instr(CInstrs, Instrs) :-
> +    transform_block_instr_list(CInstrs, ListInstrs),
> +    list.condense(ListInstrs, Instrs).
> +
> +:- pred transform_block_instr_list(list(instruction)::in,
> +    list(list(x86_64_instr))::out) is det.
> +
> +transform_block_instr_list([], []).
> +transform_block_instr_list([CInstr0 | CInstr0s], [Instr0 | Instr0s]) :-
> +    CInstr0 = llds_instr(CInstr, _),
> +    instr_to_x86_64(CInstr, Instr0),
> +    transform_block_instr_list(CInstr0s, Instr0s).
> +
> +    % Transform livevals of llds instruction into a list of x86_64 
> instruction.
> +    %
> +:- pred transform_livevals(list(lval)::in, list(x86_64_instr)::out) is det.
> +
> +transform_livevals([], []).
> +transform_livevals([Lval | Lvals], [Instr | Instrs]) :-
> +    transform_lval(Lval, Res0, Res1),
> +    (
> +        Res0 = yes(LvalOp),
> +        Instr = instr(mov(operand_label("<<livevals>>"), LvalOp)),
> +        transform_livevals(Lvals, Instrs)
> +    ;
> +        Res0 = no,
> +        (
> +            Res1 = yes(LvalInstrs),
> +            ( get_last_instr_op(LvalInstrs, LastOp) ->
> +                Instr = instr(mov(operand_label("<<livevals>>"), LastOp)),
> +                transform_livevals(Lvals, Instrs)
> +            ;
> +                unexpected(this_file, "transform_livevals: unexpected")

unexpected(ModuleName, Message) throws an error of the form
ModuleName ++ ": Unexpected: " ++ Message, so your Message should not
also say `unexpected', but rather give a hint as to what happened.  This
pattern occurs elsewhere in this module, too.

> +            )
> +        ;
> +            Res1 = no,
> +            unexpected(this_file, "transform_livevals: unexpected")
> +        )
> +    ).
> +
> +    % Given an llds instruction, transform it into equivalent x86_64
> +    % instruction.
> +    %
> +:- pred instr_to_x86_64(instr::in, list(x86_64_instr)::out) is det.
> +
> +instr_to_x86_64(comment(Comment), [comment(Comment)]).
> +instr_to_x86_64(livevals(RegsAndStackLocs), 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),
> +    (
> +        Res0 = yes(LvalOp),
> +        (
> +            Res2 = yes(RvalOp),
> +            Instrs = [instr(mov(RvalOp, LvalOp))]
> +        ;
> +            Res2 = no,
> +            (
> +                Res3 = yes(RvalInstrs),
> +                ( get_last_instr_op(RvalInstrs, LastOp) ->
> +                    LastInstr = instr(mov(LastOp, LvalOp)),
> +                    list.append(RvalInstrs, [LastInstr], Instrs)

Isn't appending going to make this O(n^2) in the number of instructions?
Or is that not an issue here?

> +                ;
> +                    unexpected(this_file, "instr_to_x86_64: assign 
> unexpected")
> +                )
> +            ;
> +                Res3 = no,
> +                unexpected(this_file, "instr_to_x86_64: assign Rval 
> unexpected")
> +            )
> +        )
> +    ;
> +        Res0 = no,
> +        (
> +            Res1 = yes(LvalInstrs),
> +            ( get_last_instr_op(LvalInstrs, LvalLastOp) ->
> +                (
> +                    Res2 = yes(RvalOp),
> +                    Instr0 = instr(mov(RvalOp, LvalLastOp)),
> +                    list.append(LvalInstrs, [Instr0], Instrs)
> +
> +                ;
> +                    Res2 = no,
> +                    (
> +                        Res3 = yes(RvalInstrs),
> +                        ( get_last_instr_op(RvalInstrs, RvalLastOp) ->
> +                            Instr0 = instr(mov(RvalLastOp, LvalLastOp)),
> +                            list.append(LvalInstrs, [Instr0], Instrs1),
> +                            list.append(RvalInstrs, Instrs1, Instrs)
> +                        ;
> +                            unexpected(this_file, "instr_to_x86_64: assign
> +                                unexpected")

Breaking strings like this will include the unwanted newline and
whitespace.  You should break up string constants using ++ from string.m
(the compiler will optimise the ++ away):

                            unexpected(this_file, "instr_to_x86_64: " ++
			    	"assign unexpected")

> +                        )
> +                    ;
> +                        Res3 = no,
> +                        unexpected(this_file, "instr_to_x86_64: assign Rval
> +                            unexpected")
> +                    )
> +                )
> +            ;
> +                unexpected(this_file, "instr_to_x86_64: assign unexpected")
> +            )
> +        ;
> +            Res1 = no,
> +            unexpected(this_file, "instr_to_x86_64: assign Lval 
> unexpected")
> +        )
> +    ).
> +instr_to_x86_64(llcall(Target0, Continuation0, _, _, _, _), Instrs) :-
> +    code_addr_type(Target0, Target1),
> +    code_addr_type(Continuation0, Continuation1),
> +    Instr1 = instr(mov(operand_label(Continuation1),
> +        operand_label("<<succip>>"))),
> +    Instr2 = instr(jmp(operand_label(Target1))),
> +    Instrs = [Instr1, Instr2].
> +instr_to_x86_64(mkframe(_, _), [comment("<<mkframe>>")]).
> +instr_to_x86_64(label(Label), Instrs) :-
> +    LabelStr = ll_backend.llds_out.label_to_c_string(Label, no),
> +    Instrs = [label(LabelStr)].
> +instr_to_x86_64(goto(CodeAddr), Instrs) :-
> +    code_addr_type(CodeAddr, Label),
> +    Instrs = [instr(jmp(operand_label(Label)))].
> +instr_to_x86_64(computed_goto(Rval, Labels), Instrs) :-
> +    transform_rval(Rval, Res0, Res1),
> +    (
> +        Res0 = yes(RvalOp),
> +        RvalInstrs = []
> +    ;
> +        Res0 = no,
> +        (
> +            Res1 = yes(RvalInstrs),
> +            ( get_last_instr_op(RvalInstrs, RvalOp0) ->
> +                RvalOp = RvalOp0
> +            ;
> +                unexpected(this_file, "instr_to_x86_64: computed_goto
> +                    unexpected")
> +            )
> +        ;
> +            Res1 = no,
> +            unexpected(this_file, "instr_to_x86_64: computed_goto 
> unexpected")
> +        )
> +    ),
> +    labels_to_string(Labels, "", LabelStr),
> +    TempReg = operand_reg(gp_reg(13)),
> +    Instr0 = instr(mov(operand_mem_ref(mem_abs(base_expr(LabelStr))), 
> TempReg)),
> +    Instr1 = instr(add(RvalOp, TempReg)),
> +    Instr2 = instr(jmp(TempReg)),
> +    list.append(RvalInstrs, [Instr0], Instr3),
> +    list.append(Instr3, [Instr1], Instr4),
> +    list.append(Instr4, [Instr2], Instrs).
> +instr_to_x86_64(arbitrary_c_code(_, _, _), 
> [comment("<<arbitrary_c_code>>")]).

Indent the overrunning head line by two tabs.

> +instr_to_x86_64(if_val(Rval, CodeAddr), Instrs) :-
> +    code_addr_type(CodeAddr, Target),
> +    transform_rval(Rval, Res0, Res1),
> +    (
> +        Res0 = yes(RvalOp)
> +    ;
> +        Res0 = no,
> +        (
> +            Res1 = yes(RvalInstrs),
> +            ( get_last_instr_op(RvalInstrs, LastOp) ->
> +                RvalOp = LastOp
> +            ;
> +                unexpected(this_file, "instr_to_x86_64: if_val unexpected")
> +            )
> +        ;
> +            Res1 = no,
> +            unexpected(this_file, "instr_to_x86_64: if_val unexpected")
> +        )
> +    ),
> +    ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
> +    Instrs = [directive(x86_64_pseudo_if(RvalStr)), instr(j(
> +        operand_label(Target), "E")), directive(endif)].
> +instr_to_x86_64(save_maxfr(_), [comment("<<save_maxfr>>")]).
> +instr_to_x86_64(restore_maxfr(_), [comment("<<restore_maxfr>>")]).
> +instr_to_x86_64(incr_hp(Lval, Tag0, Words0, Rval, _, _), Instrs) :-
> +    transform_rval(Rval, Res0, Res1),
> +    transform_lval(Lval, Res2, Res3),
> +    (
> +        Res0 = yes(RvalOp)
> +    ;
> +        Res0 = no,
> +        (
> +            Res1 = yes(RvalInstrs),
> +            ( get_last_instr_op(RvalInstrs, RvalLastOp) ->
> +                RvalOp = RvalLastOp
> +            ;
> +                unexpected(this_file, "instr_to_x86_64: incr hp 
> unexpected")
> +            )
> +        ;
> +            Res1 = no,
> +            unexpected(this_file, "instr_to_x86_64: incr hp: Rval 
> unexpected")
> +        )
> +    ),
> +    (
> +        Res2 = yes(LvalOp)
> +    ;
> +        Res2 = no,
> +        (
> +            Res3 = yes(LvalInstrs),
> +            ( get_last_instr_op(LvalInstrs, LvalLastOp) ->
> +                LvalOp = LvalLastOp
> +            ;
> +                unexpected(this_file, "instr_to_x86_64: incr_hp 
> unexpected")
> +            )
> +        ;
> +            Res3 = no,
> +            unexpected(this_file, "instr_to_x86_64: incr_hp Lval 
> unexpected")
> +        )
> +    ),
> +    (
> +        Words0 = yes(Words),
> +        IncrVal = operand_imm(imm32(int32(Words))),
> +        TempReg = operand_reg(gp_reg(13)),
> +        ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
> +        MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
> +        LoadAddr = instr(lea(MemRef, TempReg)),
> +        IncrAddInstr = instr(add(IncrVal, TempReg)),
> +        list.append([LoadAddr], [IncrAddInstr], IncrAddr)
> +    ;
> +        Words0 = no,
> +        IncrAddr = []
> +    ),
> +    (
> +        Tag0 = yes(Tag)
> +    ;
> +        Tag0 = no,
> +        Tag = 0
> +    ),
> +    TempReg = operand_reg(gp_reg(13)),
> +    ImmToReg = [instr(mov(RvalOp, TempReg))],
> +    SetTag = [instr(or(operand_imm(imm32(int32(Tag))), TempReg))],
> +    Instr0 = instr(mov(TempReg, LvalOp)),
> +    list.append(IncrAddr, ImmToReg, Instr1),
> +    list.append(Instr1, SetTag, Instr2),
> +    list.append(Instr2, [Instr0], Instrs).

You can replace sequences of appends with ++ from list.m:

	Instrs = IncrAddr ++ ImmToReg ++ SetTag ++ [Instr0].

This situation occurrs elsewhere, too.

> +instr_to_x86_64(mark_hp(_), [comment("<<mark_hp>>")]).
> +instr_to_x86_64(restore_hp(_), [comment("<<restore_hp>>")]).
> +instr_to_x86_64(free_heap(_), [comment("<<free_heap>>")]).
> +instr_to_x86_64(store_ticket(_), [comment("<<store_ticket>>")]).
> +instr_to_x86_64(reset_ticket(_, _), [comment("<<reset_ticket>>")]).
> +instr_to_x86_64(prune_ticket, [comment("<<prune_ticket>>")]).
> +instr_to_x86_64(discard_ticket, [comment("<<discard_ticket>>")]).
> +instr_to_x86_64(mark_ticket_stack(_), [comment("<<mark_ticket_stack>>")]).
> +instr_to_x86_64(prune_tickets_to(_), [comment("<<prune_tickets_to>>")]).
> +instr_to_x86_64(incr_sp(NumSlots, ProcName, _), Instrs) :-
> +    Instr1 = comment("<<incr_sp>> " ++ ProcName),
> +    Instr2 = instr(enter(uint16(NumSlots), uint8(0))),
> +    Instrs = [Instr1, Instr2].
> +instr_to_x86_64(decr_sp(NumSlots), Instrs) :-
> +    DecrOp = operand_imm(imm32(int32(NumSlots))),
> +    Instr = instr(sub(DecrOp, operand_reg(gp_reg(13)))),
> +    list.append([comment("<<decr_sp>> ")], [Instr], Instrs).
> +instr_to_x86_64(decr_sp_and_return(NumSlots), Instrs) :-
> +    Instrs = [comment("<<decr_sp_and_return>> " ++
> +        string.int_to_string(NumSlots))].
> +instr_to_x86_64(foreign_proc_code(_, _, _, _, _, _, _, _, _),
> +    [comment("<<foreign_proc_code>>")]).
> +instr_to_x86_64(init_sync_term(_, _), [comment("<<init_sync_term>>")]).
> +instr_to_x86_64(fork(_), [comment("<<fork>>")]).
> +instr_to_x86_64(join_and_continue(_, _), 
> [comment("<<join_and_continue>>")]).
> +
> +
> +    % Transform lval into either an x86_64 operand or x86_64 instructions.
> +    %
> +:- pred transform_lval(lval::in, maybe(operand)::out, 
> maybe(list(x86_64_instr))
> +    ::out) is det.

Formatting problem.

> +
> +transform_lval(reg(CReg, CRegNum), Op, no) :-
> +    (
> +        CReg = reg_r,
> +        Op = yes(operand_reg(gp_reg(CRegNum)))
> +    ;
> +        CReg = reg_f,
> +        Op = no
> +    ).
> +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)))
> +    ;
> +        CReg = reg_f,
> +        Op = no
> +    ).
> +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),
> +    (
> +        Res0 = yes(RvalOp1),
> +        Instrs1 = []
> +    ;
> +        Res0 = no,
> +        (
> +            Res1 = yes(RvalInstrs1),
> +            ( get_last_instr_op(RvalInstrs1, LastOp1) ->
> +                RvalOp1 = LastOp1,
> +                Instrs1 = RvalInstrs1
> +            ;
> +                unexpected(this_file, "lval_instrs: field unexpected")
> +            )
> +        ;
> +            Res1 = no,
> +            unexpected(this_file, "lval_instrs: field: Rval1 unexpected")
> +        )
> +    ),
> +    (
> +        Res2 = yes(RvalOp2),
> +        Instrs2 = []
> +    ;
> +        Res2 = no,
> +        (
> +            Res3 = yes(RvalInstrs2),
> +            ( get_last_instr_op(RvalInstrs2, LastOp2) ->
> +                RvalOp2 = LastOp2,
> +                Instrs2 = RvalInstrs2
> +            ;
> +                unexpected(this_file, "lval_instrs: field unexpected")
> +            )
> +        ;
> +            Res3 = no,
> +            unexpected(this_file, "lval_instrs: field: Rval2 unexpected")
> +        )
> +    ),
> +    TempReg1 = operand_reg(gp_reg(13)),
> +    ll_backend.x86_64_out.operand_type(RvalOp1, RvalStr1),
> +    MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr1))),
> +    LoadAddr = instr(lea(MemRef, TempReg1)),
> +    FieldNum = instr(add(RvalOp2, TempReg1)),
> +    list.append(Instrs1, Instrs2, Instr3),
> +    list.append(Instr3, [comment("<<field>>")], Instr4),
> +    list.append(Instr4, [LoadAddr], Instr5),
> +    (
> +        Tag0 = yes(Tag),
> +        Mrbody = instr(sub(operand_imm(imm32(int32(Tag))), TempReg1)),
> +        list.append(Instr5, [Mrbody], Instr6),
> +        list.append(Instr6, [FieldNum], Instr7),
> +        Instrs = yes(Instr7)
> +    ;
> +        Tag0 = no,
> +        list.append(Instr5, [FieldNum], Instr6),
> +        Instrs = yes(Instr6)
> +    ).
> +
> +    % Translates rval into its corresponding x86_64 operand.
> +    %
> +:- pred transform_rval(rval::in, 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),
> +    (
> +        Res0 = yes(RvalOp),
> +        list.append([comment("<<mkword>>")], [], Instr0)
> +    ;
> +        Res0 = no,
> +        (
> +            Res1 = yes(RvalInstrs),
> +            ( get_last_instr_op(RvalInstrs, LastOp) ->
> +                RvalOp = LastOp,
> +                list.append(RvalInstrs, [comment("<<mkword>>")], Instr0)
> +            ;
> +                unexpected(this_file, "transform_rval: mkword unexpected")
> +            )
> +        ;
> +            Res1 = no,
> +            unexpected(this_file, "transform_rval: mkword Rval unexpected")
> +        )
> +    ),
> +    TempReg = operand_reg(gp_reg(13)),
> +    ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
> +    MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
> +    LoadAddr = instr(lea(MemRef, TempReg)),
> +    SetTag = instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
> +    list.append(Instr0, [LoadAddr], Instr1),
> +    list.append(Instr1, [SetTag], Instr2),
> +    Instrs = yes(Instr2).
> +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)) :-
> +    Op = [directive(string([String]))].
> +transform_rval(const(llconst_multi_string(_, _)), Op, no) :-
> +    Op = yes(operand_label("<<llconst_multi_string>>")).
> +transform_rval(const(llconst_code_addr(CodeAddr)), 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("<<llconst_data_addr>>")).
> +transform_rval(unop(Op, Rval), no, Instrs) :-
> +    transform_rval(Rval, Res0, Res1),
> +    (
> +        Res0 = yes(_),
> +        unop_instrs(Op, Res0, no, Instr0),
> +        Instrs = yes(Instr0)
> +    ;
> +        Res0 = no,
> +        (
> +            Res1 = yes(_),
> +            unop_instrs(Op, no, Res1, Instr0),
> +            Instrs = yes(Instr0)
> +        ;
> +            Res1 = no,
> +            unexpected(this_file, "transform_rval: unop Rval unexpected")
> +        )
> +    ).
> +transform_rval(binop(Op, Rval1, Rval2), no, Instrs) :-
> +    transform_rval(Rval1, Res1, Res2),
> +    transform_rval(Rval2, Res3, Res4),
> +    (
> +        Res1 = yes(Val1),
> +        (
> +            Res3 = yes(Val2),
> +            binop_instrs(binop_two_ops(Val1, Val2), Op, Instr0),
> +            Instrs = yes(Instr0)
> +        ;
> +            Res3 = no,
> +            (
> +                Res4 = yes(RvalInstr2),
> +                binop_instrs(binop_op_and_instr(Val1, RvalInstr2), Op, 
> Instr0),
> +                Instrs = yes(Instr0)
> +            ;
> +                Res4 = no,
> +                Instrs = no
> +            )
> +        )
> +    ;
> +        Res1 = no,
> +        (
> +            Res2 = yes(RvalInstr1),
> +            (
> +                Res3 = yes(Val2),
> +                binop_instrs(binop_instr_and_op(RvalInstr1, Val2), Op, 
> Instr0),
> +                Instrs = yes(Instr0)
> +            ;
> +                Res3 = no,
> +                (
> +                    Res4 = yes(RvalInstr2),
> +                    binop_instrs(binop_two_instrs(RvalInstr1, RvalInstr2),
> +                        Op, Instr0),
> +                    Instrs = yes(Instr0)
> +                ;
> +                    Res4 = no,
> +                    unexpected(this_file, "rval_instrs: binop: Rval2
> +                        unexpected")
> +                )
> +            )
> +        ;
> +            Res2 = no,
> +            unexpected(this_file, "rval_instrs: binop: Rval1 unexpected")
> +        )
> +    ).
> +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),
> +    (
> +        Res0 = yes(Rval1Op),
> +        (
> +            Res2 = yes(Rval2Op),
> +            Instr2 = []
> +        ;
> +            Res2 = no,
> +            (
> +                Res3 = yes(Rval2Instr),
> +                Instr2 = [],
> +                ( get_last_instr_op(Rval2Instr, LastOp) ->
> +                     Rval2Op = LastOp
> +                ;
> +                    unexpected(this_file, "transform_rval: 
> mem_addr(heap_ref)
> +                        unexpected")
> +                )
> +            ;
> +                Res3 = no,
> +                unexpected(this_file, "transform_rval: mem_addr(heap_ref)
> +                    unexpected")
> +            )
> +        )
> +    ;
> +        Res0 = no,
> +        (
> +            Res1 = yes(Rval1Instr),
> +            ( get_last_instr_op(Rval1Instr, LastOp) ->
> +                Rval1Op = LastOp,
> +                (
> +                    Res2 = yes(Rval2Op),
> +                    Instr2 = Rval1Instr
> +                ;
> +                    Res2 = no,
> +                    (
> +                        Res3 = yes(Rval2Instr),
> +                        ( get_last_instr_op(Rval2Instr, LastOp) ->
> +                            Rval2Op = LastOp,
> +                            list.append(Rval1Instr, Rval2Instr, Instr2)
> +                        ;
> +                            unexpected(this_file, "transform_rval: 
> mem_addr(heap_ref)
> +                                unexpected")
> +                        )
> +                    ;
> +                        Res3 = no,
> +                        unexpected(this_file, "transform_rval: 
> mem_addr(heap_ref)
> +                            unexpected")
> +                    )
> +                )
> +            ;
> +                unexpected(this_file, "transform_rval: mem_addr(heap_ref)
> +                    unexpected")
> +            )
> +       ;
> +            Res1 = no,
> +            unexpected(this_file, "transform_rval: mem_addr(heap_ref)
> +                unexpected")
> +       )
> +    ),
> +    TempReg = operand_reg(gp_reg(13)),
> +    ll_backend.x86_64_out.operand_type(Rval1Op, Rval1Str),
> +    MemRef = operand_mem_ref(mem_abs(base_expr(Rval1Str))),
> +    LoadAddr = instr(lea(MemRef, TempReg)),
> +    Instr0 = instr(sub(Rval2Op, TempReg)),
> +    Instr1 = instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
> +    list.append(Instr2, [LoadAddr], Instr3),
> +    list.append(Instr3, [Instr0], Instr4),
> +    list.append(Instr4, [Instr1], Instr5),
> +    Instrs = yes(Instr5).
> +
> +    % 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.
> +    %
> +:- pred binop_instrs(binop::in, binary_op::in, list(x86_64_instr)::out) is 
> det.
> +
> +binop_instrs(binop_two_ops(Op1, Op2), Op, Instrs) :-
> +    binop_instr(Op, Op1, Op2, Instrs).
> +binop_instrs(binop_op_and_instr(Op1, InstrsOp), Op, Instrs) :-
> +    ( get_last_instr_op(InstrsOp, LastOp) ->
> +        binop_instr(Op, Op1, LastOp, Instr0),
> +        list.append(InstrsOp, Instr0, Instrs)
> +    ;
> +        unexpected(this_file, "binop_instrs: binop_op_and_instr 
> unexpected")
> +    ).
> +binop_instrs(binop_instr_and_op(InstrsOp, Op2), Op, Instrs) :-
> +    ( get_last_instr_op(InstrsOp, LastOp) ->
> +        binop_instr(Op, LastOp, Op2, Instr0),
> +        list.append(InstrsOp, Instr0, Instrs)
> +    ;
> +        unexpected(this_file, "binop_instrs: binop_instr_and_op: 
> unexpected")
> +    ).
> +binop_instrs(binop_two_instrs(InstrsOp1, InstrsOp2), Op, Instrs) :-
> +    (
> +        get_last_instr_op(InstrsOp1, LastOp1),
> +        get_last_instr_op(InstrsOp2, LastOp2)
> +    ->
> +        binop_instr(Op, LastOp1, LastOp2, Instr0),
> +        list.append(InstrsOp1, InstrsOp2, Instr1),
> +        list.append(Instr1, Instr0, Instrs)
> +    ;
> +        unexpected(this_file, "binop_instrs: binop_two_instrs: unexpected")
> +    ).
> +
> +    % Equivalent x86_64 instructions for a unary operation. A unary 
> operation
> +    % may consist of an operand or an expression (as a list of x86_64
> +    % instructions).
> +    %
> +:- pred unop_instrs(backend_libs.builtin_ops.unary_op::in, 
> maybe(operand)::in,
> +    maybe(list(x86_64_instr))::in, list(x86_64_instr)::out) is det.
> +
> +unop_instrs(mktag, _, _, [comment("<<mktag>>")]).
> +unop_instrs(tag, _, _, [comment("<<tag>>")]).
> +unop_instrs(unmktag, _, _, [comment("<<unmktag>>")]).
> +unop_instrs(strip_tag, _, _, [comment("<<strip_tag>>")]).
> +unop_instrs(mkbody, _, _, [comment("<<mkbody>>")]).
> +unop_instrs(unmkbody, _, _, [comment("<<unmkbody>>")]).
> +unop_instrs(hash_string, _, _, [comment("<<hash_string>>")]).
> +unop_instrs(bitwise_complement, Op, Instrs0, Instrs) :-
> +    (
> +        Op = yes(OpRes),
> +        Instrs = [instr(x86_64_instr_not(OpRes))]
> +    ;
> +        Op = no,
> +        (
> +            Instrs0 = yes(InsRes),
> +            ( get_last_instr_op(InsRes, LastOp) ->
> +                list.append(InsRes, [instr(x86_64_instr_not(LastOp))], 
> Instrs)
> +            ;
> +                unexpected(this_file, "unop_instrs: bitwise_complement
> +                    unexpected")
> +            )
> +        ;
> +            Instrs0 = no,
> +            unexpected(this_file, "unop_instrs: bitwise_complement 
> unexpected")
> +        )
> +    ).
> +unop_instrs(logical_not, _, _, [comment("<<logical_not>>")]).
> +
> +    % Equivalent x86_64 instructions for a binary operation.
> +    %
> +:- pred binop_instr(backend_libs.builtin_ops.binary_op::in, operand::in,
> +    operand::in, list(x86_64_instr)::out) is det.
> +
> +binop_instr(int_add, Op1, Op2, [instr(add(Op1, Op2))]).
> +binop_instr(int_sub, Op1, Op2, [instr(sub(Op1, Op2))]).
> +binop_instr(int_mul, Op1, Op2, [instr(imul(Op1, yes(Op2), no))]).
> +binop_instr(int_mod, _, _, [comment("<<int_mod>>")]).
> +binop_instr(int_div, Op1, Op2, Instrs) :-
> +    LoadDividend = instr(mov(Op2, operand_label("<<int_div>>"))),
> +    list.cons(LoadDividend, [instr(idiv(Op1))], Instrs).
> +binop_instr(unchecked_left_shift, Op1, Op2, [instr(shl(Op1, Op2))]).
> +binop_instr(unchecked_right_shift, Op1, Op2, [instr(shr(Op1, Op2))]).
> +binop_instr(bitwise_and, Op1, Op2, [instr(and(Op1, Op2))]).
> +binop_instr(bitwise_or, _, _, [comment("<<bitwise_or>>")]).
> +binop_instr(bitwise_xor, Op1, Op2, [instr(xor(Op1, Op2))]).
> +binop_instr(logical_and, _, _, [comment("<<logical_and>>")]).
> +binop_instr(logical_or, _, _, [comment("<<logical_or>>")]).
> +binop_instr(eq, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(ne, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(body, _, _, [comment("<<body>>")]).
> +binop_instr(array_index(_), _, _, [comment("<<array_index>>")]).
> +binop_instr(str_eq, _, _, [comment("<<str_eq>>")]).
> +binop_instr(str_ne, _, _, [comment("<<str_ne>>")]).
> +binop_instr(str_lt, _, _, [comment("<<str_lt>>")]).
> +binop_instr(str_gt, _, _, [comment("<<str_gt>>")]).
> +binop_instr(str_le, _, _, [comment("<<str_le>>")]).
> +binop_instr(str_ge, _, _, [comment("<<str_ge>>")]).
> +binop_instr(int_lt, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(int_gt, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(int_le, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(int_ge, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(unsigned_le, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(float_plus, _, _, [comment("<<float_plus>>")]).
> +binop_instr(float_minus, _, _, [comment("<<float_minus>>")]).
> +binop_instr(float_times, _, _, [comment("<<float_times>>")]).
> +binop_instr(float_divide, _, _, [comment("<<float_divide>>")]).
> +binop_instr(float_eq, _, _, [comment("<<float_eq>>")]).
> +binop_instr(float_ne, _, _, [comment("<<float_ne>>")]).
> +binop_instr(float_lt, _, _, [comment("<<float_lt>>")]).
> +binop_instr(float_gt, _, _, [comment("<<float_gt>>")]).
> +binop_instr(float_le, _, _, [comment("<<float_le>>")]).
> +binop_instr(float_ge, _, _, [comment("<<float_ge>>")]).
> +
> +    % Get a string representation of code address types.
> +    %
> +:- pred code_addr_type(code_addr::in, string::out) is det.
> +
> +code_addr_type(code_label(Label), CodeAddr) :-
> +    CodeAddr = "$" ++  ll_backend.llds_out.label_to_c_string(Label, no).
> +code_addr_type(code_imported_proc(ProcLabel), CodeAddr) :-
> +    CodeAddr = "$" ++
> +        backend_libs.name_mangle.proc_label_to_c_string(ProcLabel, no).
> +code_addr_type(code_succip, CodeAddr) :-
> +    CodeAddr = "<<code_succip>>".
> +code_addr_type(do_succeed(_), CodeAddr) :-
> +    CodeAddr = "<<do_succeed>>".
> +code_addr_type(do_redo, CodeAddr) :-
> +    CodeAddr = "<<do_redo>>".
> +code_addr_type(do_fail, CodeAddr) :-
> +    CodeAddr = "<<do_fail>>".
> +code_addr_type(do_trace_redo_fail_shallow, CodeAddr) :-
> +    CodeAddr = "<<do_trace_redo_fail_shallow>>".
> +code_addr_type(do_trace_redo_fail_deep, CodeAddr) :-
> +    CodeAddr = "<<do_trace_redo_fail_deep>>".
> +code_addr_type(do_call_closure(_), CodeAddr) :-
> +    CodeAddr = "<<do_call_closure>>".
> +code_addr_type(do_call_class_method(_), CodeAddr) :-
> +    CodeAddr = "<<do_call_class_method>>".
> +code_addr_type(do_not_reached, CodeAddr) :-
> +    CodeAddr = "<<do_not_reached>>".
> +
> +    % Given a list of x86_64 instructions, figure out the operand of the 
> last
> +    % instruction in the list.
> +    %
> +:- pred get_last_instr_op(list(x86_64_instr)::in, operand::out) is semidet.
> +
> +get_last_instr_op(Instrs, Op) :-
> +    list.last_det(Instrs, LastInstr),

It's preferable to use a function rather than a predicate where
possible:

	LastInstr = list.last_det(Instrs),

> +    (
> +       LastInstr = comment(Comment),
> +       Op = operand_label(Comment)
> +    ;
> +       LastInstr = label(Label),
> +       Op = operand_label(Label)
> +    ;
> +       LastInstr = instr(Instr),
> +       last_instr_dest(Instr, Op)
> +    ;
> +       LastInstr = directive(_),
> +       Op = operand_label("<<directive>>")
> +     ).
> +
> +    % Destination operand of an x86_64_instruction.
> +    %
> +:- pred last_instr_dest(x86_64_inst::in, operand::out) is semidet.
> +
> +last_instr_dest(adc(_, Dest), Dest).
> +last_instr_dest(add(_, Dest), Dest).
> +last_instr_dest(and(_, Dest), Dest).
> +last_instr_dest(bs(_, Dest, _), Dest).
> +last_instr_dest(bswap(Dest), Dest).
> +last_instr_dest(cmov(_, Dest, _), Dest).
> +last_instr_dest(cmp(_, Dest), Dest).
> +last_instr_dest(cmpxchg(_, Dest), Dest).
> +last_instr_dest(cmpxchg8b(Dest), Dest).
> +last_instr_dest(dec(Dest), Dest).
> +last_instr_dest(div(Dest), Dest).
> +last_instr_dest(idiv(Dest), Dest).
> +last_instr_dest(imul(_, yes(Dest), _), Dest).
> +last_instr_dest(inc(Dest), Dest).
> +last_instr_dest(jrcxz(Dest), Dest).
> +last_instr_dest(jmp(Dest), Dest).
> +last_instr_dest(lea(_, Dest), Dest).
> +last_instr_dest(loop(Dest), Dest).
> +last_instr_dest(loope(Dest), Dest).
> +last_instr_dest(loopne(Dest), Dest).
> +last_instr_dest(loopnz(Dest), Dest).
> +last_instr_dest(loopz(Dest), Dest).
> +last_instr_dest(mov(_, Dest), Dest).
> +last_instr_dest(mul(Dest), Dest).
> +last_instr_dest(x86_64_instr_not(Dest), Dest).
> +last_instr_dest(or(_, Dest), Dest).
> +last_instr_dest(pop(Dest), Dest).
> +last_instr_dest(push(Dest), Dest).
> +last_instr_dest(rc(_, Dest, _), Dest).
> +last_instr_dest(ro(_, Dest, _), Dest).
> +last_instr_dest(sal(_, Dest), Dest).
> +last_instr_dest(shl(_, Dest), Dest).
> +last_instr_dest(sar(_, Dest), Dest).
> +last_instr_dest(sbb(_, Dest), Dest).
> +last_instr_dest(set(Dest, _), Dest).
> +last_instr_dest(shr(_, Dest), Dest).
> +last_instr_dest(sub(_, Dest), Dest).
> +last_instr_dest(xadd(_, Dest), Dest).
> +last_instr_dest(xor(_, Dest), Dest).
> +
> +    % Get a string representation of llds labels.
> +    %
> +:- pred labels_to_string(list(label)::in, string::in, string::out) is det.
> +
> +labels_to_string([], Str, Str).
> +labels_to_string([Label | Labels], Str0, Str) :-
> +    LabelStr = ll_backend.llds_out.label_to_c_string(Label, no),
> +    labels_to_string(Labels, Str0 ++ LabelStr, Str).
> +
> +%----------------------------------------------------------------------------%
> +
> +:- func this_file = string.
> +
> +this_file = "llds_to_x86_64.m".
> +
> +%----------------------------------------------------------------------------%
> +:- end_module llds_to_x86_64.
> +%----------------------------------------------------------------------------%
> Index: compiler/llds_to_x86_64_out.m
> ===================================================================
> RCS file: compiler/llds_to_x86_64_out.m
> diff -N compiler/llds_to_x86_64_out.m
> --- /dev/null   1 Jan 1970 00:00:00 -0000
> +++ compiler/llds_to_x86_64_out.m   2 Feb 2007 02:20:46 -0000
> @@ -0,0 +1,58 @@
> +%-----------------------------------------------------------------------------%
> +% 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: llds_to_x86_64_out.m.
> +% Main author: fhandoko.
> +%
> +% This module defines the routines for printing out instructions produced 
> by
> +% llds->x86_64 asm generator.
> +%
> +%-----------------------------------------------------------------------------%
> +
> +:- module ll_backend.llds_to_x86_64_out.
> +:- interface.
> +
> +:- import_module ll_backend.x86_64_instrs.
> +
> +:- import_module io.
> +:- import_module list.
> +
> +%-----------------------------------------------------------------------------%
> +
> +:- pred output_x86_64_asm(list(x86_64_procedure)::in, io::di, io::uo) is 
> det.
> +
> +%-----------------------------------------------------------------------------%
> +%-----------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module ll_backend.llds_to_x86_64.
> +:- import_module ll_backend.x86_64_out.
> +
> +output_x86_64_asm(AsmProcs, !IO) :-
> +   output_asm_proc_list(AsmProcs, !IO).
> +
> +
> +:- pred output_asm_proc_list(list(x86_64_procedure)::in, io::di, io::uo) 
> is det.
> +
> +output_asm_proc_list([], !IO).
> +output_asm_proc_list([AsmProc | AsmProcs], !IO) :-
> +   output_asm_instr_list(AsmProc ^ x86_64_code, !IO),
> +   output_asm_proc_list(AsmProcs, !IO).
> +
> +:- pred output_asm_instr_list(list(x86_64_instruction)::in, io::di, io::uo)
> +   is det.
> +
> +output_asm_instr_list([], !IO).
> +output_asm_instr_list([AsmInstr | AsmInstrs], !IO) :-
> +   output_x86_64_instruction(AsmInstr, !IO),
> +   output_asm_instr_list(AsmInstrs, !IO).
> +
> +%----------------------------------------------------------------------------%
> +:- end_module llds_to_x86_64_out.
> +%----------------------------------------------------------------------------%
> Index: compiler/mercury_compile.m
> ===================================================================
> RCS file: 
> /home/mercury/mercury1/repository/mercury/compiler/mercury_compile.m,v
> retrieving revision 1.426
> diff -u -r1.426 mercury_compile.m
> --- compiler/mercury_compile.m  23 Jan 2007 03:45:34 -0000  1.426
> +++ compiler/mercury_compile.m  31 Jan 2007 23:46:04 -0000
> @@ -122,6 +122,12 @@
>  :- import_module bytecode_backend.bytecode_gen.
>  :- import_module bytecode_backend.bytecode.
> 
> +    % The x86_64 asm back-end.
> +    %
> +:- import_module ll_backend.llds_to_x86_64.
> +:- import_module ll_backend.llds_to_x86_64_out.
> +:- import_module ll_backend.x86_64_instrs.
> +
>      % the MLDS back-end
>  :- import_module ml_backend.add_trail_ops.         % HLDS -> HLDS
>  :- import_module ml_backend.add_heap_ops.          % HLDS -> HLDS
> @@ -1639,12 +1645,16 @@
>              )
>          ;
>              Target = target_x86_64,
> -            backend_pass(!HLDS, GlobalData, LLDS, !DumpInfo, !IO),
> +%             backend_pass(!HLDS, GlobalData, LLDS, !DumpInfo, !IO),
> +            backend_pass(!HLDS, _, LLDS, !DumpInfo, !IO),
>              % XXX Eventually we will call the LLDS->x86_64 asm code
>              % generator here and then output the assembler.  At the moment
>              % we just output the LLDS as C code.
> -            output_pass(!.HLDS, GlobalData, LLDS, ModuleName,
> -                _CompileErrors, _, !IO),
> +            llds_to_x86_64_asm(!.HLDS, LLDS, X86_64_Asm),
> +            output_x86_64_asm(X86_64_Asm, !IO),
> +            % need to output x86_64_Asm
> +            %output_pass(!.HLDS, GlobalData, LLDS, ModuleName,
> +            %    _CompileErrors, _, !IO),
>              FactTableBaseFiles = []
>          ),
>          recompilation.usage.write_usage_file(!.HLDS, NestedSubModules,
> Index: compiler/x86_64_instrs.m
> ===================================================================
> RCS file: 
> /home/mercury/mercury1/repository/mercury/compiler/x86_64_instrs.m,v
> retrieving revision 1.1
> diff -u -r1.1 x86_64_instrs.m
> --- compiler/x86_64_instrs.m    15 Jan 2007 22:49:41 -0000  1.1
> +++ compiler/x86_64_instrs.m    30 Jan 2007 23:33:36 -0000
> @@ -16,14 +16,69 @@
>  :- module ll_backend.x86_64_instrs.
>  :- interface.
> 
> +:- import_module hlds.hlds_pred.
> +:- import_module hlds.code_model.
> +:- import_module ll_backend.llds.
> +:- import_module mdbcomp.prim_data.
> +
> +:- import_module counter.
>  :- import_module list.
>  :- import_module maybe.
> +:- import_module set.
> +
> +%-----------------------------------------------------------------------------%
> +
> +    % We turn a llds.c_file into this.
> +    %
> +:- type x86_64_module
> +    --->    x86_64_module(
> +                x86_64_modulename :: module_name,
> +                                  % The name of this x86_64 module.
> +                x86_64_procs      :: list(list(x86_64_procedure))
> +                                  % The code.
> +            ).
> +
> +:- func init_x86_64_module(module_name) = x86_64_module.
> +
> +:- func init_x86_64_proc(c_procedure) =  x86_64_procedure.
> +
> +:- func init_x86_64_instruction =  x86_64_instruction.
> +
> +%-----------------------------------------------------------------------------%
> +
> +    % We turn an llds.c_procedure into one of these.
> +    % XXX Do we really need to replicate all these fields from the llds?
> +    %
> +:- type x86_64_procedure
> +    --->    x86_64_procedure(
> +                x86_64_name             :: string,
> +                                        % Predicate name.
> +                x86_64_arity            :: int,
> +                                        % Original arity.
> +                x86_64_id               :: pred_proc_id,
> +                                        % The pred_proc_id of this code.
> +                x86_64_code_model       :: code_model,
> +                                        % The code model of the procedure.
> +                x86_64_code             :: list(x86_64_instruction),
> +                                        % The code for this procedure.
> +                x86_64_proc_label       :: proc_label,
> +                                        % Proc_label of this procedure.
> +                x86_64_label_nums       :: counter,
> +                x86_64_may_alter_rtti   :: may_alter_rtti,
> +                                        % The compiler is allowed to 
> perform
> +                                        % optimizations on this procedure
> +                                        % that could alter RTTI information
> +                                        % (e.g. the set of variables live 
> at
> +                                        % a label) only if this field is 
> set
> +                                        % to `may_alter_rtti'.
> +                x86_64_c_global_vars    :: set(string)
> +    ).
> 
> 
> %-----------------------------------------------------------------------------%
> 
>  :- type x86_64_instruction
>      --->    x86_64_instr(
> -                x86_64_instr_name   :: x86_64_op,
> +                x86_64_inst         :: list(x86_64_instr),
>                  x86_64_comment      :: string
>              ).
> 
> @@ -32,8 +87,8 @@
>  :- type x86_64_instr
>      --->    comment(string)
>      ;       label(label_name)
> -    ;       directives(list(pseudo_op))
> -    ;       instrs(list(x86_64_instruction)).
> +    ;       directive(pseudo_op)
> +    ;       instr(x86_64_inst).
> 
> 
> %-----------------------------------------------------------------------------%
> 
> @@ -136,7 +191,7 @@
>      ;       eject
>              % Force a page break.
> 
> -    ;       else_
> +    ;       x86_64_pseudo_else
>              % As in 'if-then-else' conditional expression.
> 
>      ;       elseif
> @@ -239,7 +294,7 @@
>      ;       ident
>              % To place tags in object files.
> 
> -    ;       if_(
> +    ;       x86_64_pseudo_if(
>                  if_expr             :: string
>              )
>              % Mark the beginning of a conditional section.
> @@ -520,7 +575,7 @@
>              )
>              % Use 'title_heading' as the title when generating assembly 
> listing.
> 
> -    ;       type_(
> +    ;       x86_64_pseudo_type(
>                  type_name           :: string,
>                  type_desc           :: string
>              )
> @@ -571,22 +626,7 @@
>      % Details on amd64-prog-man-vol1 manual p27.
>      %
>  :- type gp_reg
> -    --->    rax
> -    ;       rbx
> -    ;       rcx
> -    ;       rdx
> -    ;       rbp
> -    ;       rsi
> -    ;       rdi
> -    ;       rsp
> -    ;       r8
> -    ;       r9
> -    ;       r10
> -    ;       r11
> -    ;       r12
> -    ;       r13
> -    ;       r14
> -    ;       r15.
> +    ---> gp_reg(int).
> 
>      % 64-bit instruction pointer register on the x86_64. Instruction 
>      pointer
>      % RIP is used as a base register for relative addressing. x86_64
> @@ -622,7 +662,7 @@
>      % or an instruction-relative address.
>      % Details on amd64-prog-man-vol1 p19.
>      %
> -:- type mem_ref
> +:- type x86_64_mem_ref
>      --->    mem_abs(
>                  mem_abs_address         :: base_address
>              )
> @@ -650,35 +690,14 @@
>  :- type operand
>      --->    operand_reg(gp_reg)
>      ;       operand_imm(imm_operand)
> -    ;       operand_mem_ref(mem_ref).
> -
> +    ;       operand_mem_ref(x86_64_mem_ref)
> +    ;       operand_rel_offset(rel_offset)
> +    ;       operand_label(string).
> 
>  %
>  % Subtypes of the operand type.
>  % XXX maybe we should use inst-subtyping for these?
>  %
> -
> -    % x86_64_instruction's operand is either the content a general-purpose
> -    % register or the content of a memory reference.
> -    %
> -:- type reg_or_mem_ref_op
> -    --->    rmro_reg(gp_reg)
> -    ;       rmro_mem_ref(mem_ref).
> -
> -    % x86_64_instruction's operand is either the contents of a 
> general-purpose
> -    % register or the value of an immediate operand.
> -    %
> -:- type reg_or_imm_op
> -    --->    rio_reg(gp_reg)
> -    ;       rio_imm(imm_operand).
> -
> -    % x86_64_instruction's operand is either the content of CL register 
> (the
> -    % bottom 16 bits of RCX register) or an 8-bit immediate value.
> -    %
> -:- type cl_reg_or_imm_op
> -    --->    crio_reg_cl(gp_reg)
> -    ;       crio_imm8(int8).
> -
>      % x86_64 instruction's operand is an offset relative to the instruction
>      % pointer.
>      %
> @@ -692,7 +711,7 @@
>      %
>  :- type rmrol
>      --->    rmrol_reg(gp_reg)
> -    ;       rmrol_mem_ref(mem_ref)
> +    ;       rmrol_mem_ref(x86_64_mem_ref)
>      ;       rmrol_rel_offset(rel_offset)
>      ;       rmrol_label(
>                  rmrol_label_name    :: string
> @@ -706,83 +725,101 @@
>      % We use At&T style instructions where the source comes before the
>      % destination.
>      %
> -:- type x86_64_op
> +:- type x86_64_inst
>      --->    adc(
>                  adc_src     :: operand,
> -                adc_dst     :: reg_or_mem_ref_op
> +                            % immediate, register or memory location
> +                adc_dst     :: operand
> +                            % register or memory location
>              )
>              % Add with carry. Add 'adc_src' to 'adc_dst' + carry flag (CF).
> +            % Cannot add two memory operands.
>              % Details on amd64-prog-man-vol3 manual p65.
> 
>      ;       add(
>                  add_src     :: operand,
> -                add_dst     :: reg_or_mem_ref_op
> +                            % immediate, register or memory location
> +                add_dst     :: operand
> +                            % register or memory location
>              )
>              % Signed or unsigned add. Add 'adc_src' to 'adc_dst'.
> +            % Cannot add two memory operands.
>              % Details on amd64-prog-man-vol3 manual p67.
> 
>      ;       and(
>                  and_src     :: operand,
> -                and_dst     :: reg_or_mem_ref_op
> +                            % immediate, register or memory location
> +                and_dst     :: operand
> +                            % register or memory location
>              )
>              % Performs a bitwise AND operation on both operands.
> +            % Cannot and two memory operands.
>              % Details on amd64-prog-man-vol3 manual p69.
> 
> -    ;       bsf(
> -                bsf_src     :: reg_or_mem_ref_op,
> -                bsf_dst     :: gp_reg
> -            )
> -            % Bit scan forward. Searches the value in 'bsf_src' for the 
> least
> -            % significant set bit.
> -            % Details on amd64-prog-man-vol3 manual p74.
> -
> -    ;        bsr(
> -                bsr_src     :: reg_or_mem_ref_op,
> -                bsr_dst     :: gp_reg
> -            )
> -            % Bit scan reverse. Searches the value in 'bsf_src' for the 
> most
> -            % significant set bit.
> -            % Details on amd64-prog-man-vol3 manual p75.
> +    ;       bs(
> +                bs_src      :: operand,
> +                            % register or memory location
> +                bs_dst      :: operand,
> +                            % register
> +                bs_cond     :: string
> +                            % "F" for forward, "R" for reverse"

Using strings like this is usually bad.  Why not use a discriminated
union type?

> +            )
> +            % Bit scan. Searches the value in 'bs_src' for the least
> +            % significant set bit  if 'bs_cond' is "F". Searches
> +            % for the most significant set bit if 'bs_cond' is "R".
> +            % Details on amd64-prog-man-vol3 manual p(74-75).
> 
> -    ;       bswap(gp_reg)
> -            % Byte swap. Reverses the byte order of the specified 'gp_reg'.
> +    ;       bswap(
> +                bswap_reg   :: operand
> +            )
> +            % Byte swap. Reverses the byte order of the specified 
> 'operand'.
>              % Details on amd64-prog-man-vol3 manual p76.
> 
>      ;       bt(
> -                bt_src      :: reg_or_mem_ref_op,
> -                bt_idx      :: reg_or_imm_op
> +                bt_src      :: operand,
> +                            % register or memory reference
> +                bt_idx      :: operand
> +                            % register or 8-bit immediate value
>              )
>              % Bit test. Copies a bit specified by 'bt_idx' from a bit 
>              string in
>              % 'bt_src' to the carry flag (CF) or RFLAGS register.
>              % Details on amd64-prog-man-vol3 manual p77.
>      ;       btc(
> -                btc_src     :: reg_or_mem_ref_op,
> -                btc_idx     :: reg_or_imm_op
> +                btc_src     :: operand,
> +                            % register or memory reference
> +                btc_idx     :: operand
> +                            % register or 8-bit immediate value
>              )
>              % Bit test and complement. Complements 'btc_src' after 
>              performing
>              % 'bt' operation.
>              % Details on amd64-prog-man-vol3 manual p79.
> 
>      ;       btr(
> -                btr_src     :: reg_or_mem_ref_op,
> -                btr_idx     :: reg_or_imm_op
> +                btr_src     :: operand,
> +                            % register or memory reference
> +                btr_idx     :: operand
> +                            % register or 8-bit immediate value
>              )
>              % Bit test and reverse. Clears 'btr_src' to 0 after performing 
>              'bt'
>              % operation.
>              % Details on amd64-prog-man-vol3 manual p81.
> 
>      ;       bts(
> -                bts_src     :: reg_or_mem_ref_op,
> -                bts_idx     :: reg_or_imm_op
> +                bts_src     :: operand,
> +                            % register or memory reference
> +                bts_idx     :: operand
> +                            % register or 8-bit immediate value
>              )
>              % Bit test and set. Sets 'bts_src' to 1 after performing 'bt'
>              % operation.
>              % Details on amd64-prog-man-vol3 manual p83.
> 
> -    ;       call(rmrol)
> -            % Call with target specified by 'rmrol': register, memory 
> location,
> -            % relative offset or a label.
> +    ;       call(
> +                call_target :: operand
> +                            % label, register, memory reference or rel 
> offset
> +            )
> +            % Call with target specified by call_target
>              % Details on amd64-prog-man-vol3 manual p85.
> 
>      ;       cbw
> @@ -821,241 +858,85 @@
>              % Complements the carry flag bit (CF) bit in the rFLAGS 
>              register.
>              % Details on amd64-prog-man-vol3 manual p100.
> 
> -    ;       cmovo(
> -                cmovo_src       :: reg_or_mem_ref_op,
> -                cmovo_dest      :: gp_reg
> -            )
> -            % Moves if overflow (OF = 1).
> -            % Details on amd64-prog-man-vol3 manual p101.
> -
> -    ;       cmovno(
> -                cmovno_src      :: reg_or_mem_ref_op,
> -                cmovno_dest     :: gp_reg
> -            )
> -            % Moves if not overflow (OF = 0).
> -            % Details on amd64-prog-man-vol3 manual p101.
> -
> -    ;       cmovb(
> -                cmovb_src       :: reg_or_mem_ref_op,
> -                cmovb_dest      :: gp_reg
> -            )
> -            % Moves if below (CF = 1).
> -            % Details on amd64-prog-man-vol3 manual p101.
> -
> -    ;       cmovc(
> -                cmovc_src       :: reg_or_mem_ref_op,
> -                cmovc_dest      :: gp_reg
> -            )
> -            % Moves if carry (CF = 1).
> -            % Details on amd64-prog-man-vol3 manual p101.
> -
> -    ;       cmovnae(
> -                cmovnae_src     :: reg_or_mem_ref_op,
> -                cmovnae_dest    :: gp_reg
> -            )
> -            % Moves if not above or equal (CF = 1).
> -            % Details on amd64-prog-man-vol3 manual p101.
> -
> -    ;       cmovnb(
> -                cmovnb_src      :: reg_or_mem_ref_op,
> -                cmovnb_dest     :: gp_reg
> -            )
> -            % Moves if not below (CF = 0).
> -            % Details on amd64-prog-man-vol3 manual p101.
> -
> -    ;       cmovnc(
> -                cmovnc_src      :: reg_or_mem_ref_op,
> -                cmovnc_dest     :: gp_reg
> -            )
> -            % Moves if not carry (CF = 0).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -     ;      cmovae(
> -                cmovae_src      :: reg_or_mem_ref_op,
> -                cmovae_dest     :: gp_reg
> -            )
> -            % Moves if above or equal (CF = 0).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -     ;      cmovz(
> -                cmovz_src       :: reg_or_mem_ref_op,
> -                cmovz_dest      :: gp_reg
> -            )
> -            % Moves if zero (ZF = 1).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -     ;      cmove(
> -                cmove_src       :: reg_or_mem_ref_op,
> -                cmove_dest      :: gp_reg
> -            )
> -            % Moves if equal (ZF = 1).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -     ;      cmovnz(
> -                cmovnz_src      :: reg_or_mem_ref_op,
> -                cmovnz_dest     :: gp_reg
> -            )
> -            % Moves if not zero (ZF = 0).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -    ;      cmovne(
> -                cmovne_src      :: reg_or_mem_ref_op,
> -                cmovne_dest     :: gp_reg
> -            )
> -            % Moves if not equal (ZF = 0).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -    ;      cmovbe(
> -                cmovbe_src      :: reg_or_mem_ref_op,
> -                cmovbe_dest     :: gp_reg
> -            )
> -            % Moves if below or equal (CF = 1 or ZF = 1).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -    ;       cmovna(
> -                cmovna_src      :: reg_or_mem_ref_op,
> -                cmovna_dest     :: gp_reg
> -            )
> -            % Moves if not above (CF = 1 or ZF = 1).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -    ;       cmovnbe(
> -                cmovnbe_src     :: reg_or_mem_ref_op,
> -                cmovnbe_dest    :: gp_reg
> -            )
> -            % Moves if not below or equal (CF = 0 or ZF = 0).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -    ;       cmova(
> -                cmova_src       :: reg_or_mem_ref_op,
> -                cmova_dest      :: gp_reg
> -            )
> -            % Moves if above (CF = 1 or ZF = 0).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -    ;       cmovs(
> -                cmovs_src       :: reg_or_mem_ref_op,
> -                cmovs_dest      :: gp_reg
> -            )
> -            % Moves if sign (SF = 1).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -    ;       cmovns(
> -                cmovns_src      :: reg_or_mem_ref_op,
> -                cmovns_dest     :: gp_reg
> -            )
> -            % Moves if not sign (SF = 0).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -    ;       cmovp(
> -                cmovp_src       :: reg_or_mem_ref_op,
> -                cmovp_dest      :: gp_reg
> -            )
> -            % Moves if parity (PF = 1).
> -            % Details on amd64-prog-man-vol3 manual p102.
> -
> -    ;       cmovpe(
> -                cmovpe_src      :: reg_or_mem_ref_op,
> -                cmovpe_dest     :: gp_reg
> -            )
> -            % Moves if parity even (PF = 1).
> -            % Details on amd64-prog-man-vol3 manual p103.
> -
> -    ;       cmovnp(
> -                cmovnp_src      :: reg_or_mem_ref_op,
> -                cmovnp_dest     :: gp_reg
> -            )
> -            % Moves if not parity (PF = 0).
> -            % Details on amd64-prog-man-vol3 manual p103.
> -
> -    ;       cmovpo(
> -                cmovpo_src      :: reg_or_mem_ref_op,
> -                cmovpo_dest     :: gp_reg
> -            )
> -            % Moves if parity odd (PF = 0).
> -            % Details on amd64-prog-man-vol3 manual p103.
> -
> -    ;       cmovl(
> -                cmovl_src       :: reg_or_mem_ref_op,
> -                cmovl_dest      :: gp_reg
> -            )
> -            % Moves if less (SF <> OF).
> -            % Details on amd64-prog-man-vol3 manual p103.
> -
> -    ;       cmovnge(
> -                cmovnge_src     :: reg_or_mem_ref_op,
> -                cmovnge_dest    :: gp_reg
> -            )
> -            % Moves if not greater or equal (SF <> OF).
> -            % Details on amd64-prog-man-vol3 manual p103.
> -
> -    ;       cmovnl(
> -                cmovnl_src      :: reg_or_mem_ref_op,
> -                cmovnl_dest     :: gp_reg
> -            )
> -            % Moves if not less (SF = OF).
> -            % Details on amd64-prog-man-vol3 manual p103.
> -
> -    ;       cmovge(
> -                cmovge_src      :: reg_or_mem_ref_op,
> -                cmovge_dest     :: gp_reg
> -            )
> -            % Moves if greater or equal (SF = OF).
> -            % Details on amd64-prog-man-vol3 manual p103.
> -
> -    ;       cmovle(
> -                cmovle_src      :: reg_or_mem_ref_op,
> -                cmovle_dest     :: gp_reg
> -            )
> -            % Moves if less or equal (ZF = 1 or SF <> OF).
> -            % Details on amd64-prog-man-vol3 manual p103.
> -
> -    ;       cmovng(
> -                cmovng_src      :: reg_or_mem_ref_op,
> -                cmovng_dest     :: gp_reg
> -            )
> -            % Moves if not greater (ZF = 1 or SF <> OF).
> -            % Details on amd64-prog-man-vol3 manual p103.
> -
> -    ;       cmovnle(
> -                cmovnle_src     :: reg_or_mem_ref_op,
> -                cmovnle_dest    :: gp_reg
> -            )
> -            % Moves if not less or equal (ZF = 0 or SF = OF).
> -            % Details on amd64-prog-man-vol3 manual p103.
> -
> -    ;       cmovg(
> -                cmovg_src       :: reg_or_mem_ref_op,
> -                cmovg_dest      :: gp_reg
> -            )
> -            % Moves if greater (ZF = 0 or SF = OF).
> -            % Details on amd64-prog-man-vol3 manual p103.
> +    ;       cmov(
> +                cmov_src        :: operand,
> +                                % memory or register
> +                cmov_dest       :: operand,
> +                                % register
> +                cmov_cmp_op     :: string
> +            )
> +            % Moves with comparison operation defined in 'cmov_cmp_op'.
> +            % Valid values of 'cmov_cmp_op' are:
> +            %   O   -> moves if overflow (OF = 1)
> +            %   NO  -> moves if not overflow (OF = 0)
> +            %   B   -> moves if below (CF = 1)
> +            %   C   -> moves if carry (CF = 1)
> +            %   NAE -> moves if not above or equal (CF = 1)
> +            %   NB  -> moves if not below (CF = 0)
> +            %   NC  -> moves if not carry (CF = 0)
> +            %   AE  -> moves if above or equal (CF = 0)
> +            %   Z   -> moves if zero (ZF = 1)
> +            %   E   -> moves if equal (ZF = 1)
> +            %   NZ  -> moves if not zero (ZF = 0)
> +            %   NE  -> moves if not equal (ZF = 0)
> +            %   BE  -> moves if below or  equal (CF = 1 or ZF = 1)
> +            %   NA  -> moves if not above (CF = 1 or ZF = 1)
> +            %   NBE -> moves if not below or equal (CF = 0 or ZF = 0)
> +            %   A   -> moves if above (CF = 1 or ZF = 0)
> +            %   S   -> moves if sign (SF = 1)
> +            %   NS  -> moves if not sign (SF = 0)
> +            %   P   -> moves if parity (PF = 1)
> +            %   PE  -> moves if parity even (PF = 1)
> +            %   NP  -> moves if not parity (PF = 0)
> +            %   PO  -> moves if parity odd (PF = 0)
> +            %   L   -> moves if less (SF <> OF)
> +            %   NGE -> moves if not greater or equal (SF <> OF)
> +            %   NL  -> moves if not less (SF = OF)
> +            %   GE  -> moves if greater or equal (SF = OF)
> +            %   LE  -> moves if less or equal (ZF = 1 or SF <> OF)
> +            %   NG  -> moves if not greater (ZF = 1 or SF <> OF)
> +            %   NLE -> moves if not less or equal (ZF = 0 or SF = OF)
> +            %   G   -> moves if greater (ZF = 0 or SF = OF)
> +            % Details on amd64-prog-man-vol3 manual p(101-103).
> 
>      ;       cmp(
>                  cmp_src         :: operand,
> -                cmp_dest        :: reg_or_mem_ref_op
> +                                % register, memory location or immediate 
> value
> +                cmp_dest        :: operand
> +                                % register or memory location
>              )
>              % Compares 'cmp_src' with 'cmp_dest'.
>              % Details on amd64-prog-man-vol3 manual p105.
> 
>      ;       cmpxchg(
> -                cmpxchg_cmp     :: reg_or_mem_ref_op,
> -                cmpxchg_xchg    :: gp_reg
> +                cmpxchg_src     :: operand,
> +                                % register or memory location
> +                cmpxchg_dest    :: operand
> +                                % register
>              )
> -            % Compares the value in RAX with the value in 'cmpxchg_cmp'.
> -            % If equal, copies the value in 'cmpxchg_xchg' to 
> 'cmpxchg_cmp'.
> +            % Compares the value in RAX with the value in 'cmpxchg_dest'.
> +            % If equal, copies the value in 'cmpxchg_src' to 
> 'cmpxchg_dest'.
>              % Details on amd64-prog-man-vol3 manual p111.
> 
> -    ;       cmpxchg8b(mem_ref)
> +    ;       cmpxchg8b(
> +                cmpxchg8b_mem   :: operand
> +                                % memory reference
> +            )
>              % Compares the value in EDX:EAX with the value in 'mem_ref'.
>              % Details on amd64-prog-man-vol3 manual p113.
> 
> -    ;       dec(reg_or_mem_ref_op)
> -            % Decrements the contents of 'reg_or_mem_ref_op'.
> +    ;       dec(
> +                dec_op          :: operand
> +                                % register or memory reference
> +            )
> +            % Decrements the contents of 'dec_op'.
>              % Details on amd64-prog-man-vol3 manual p120.
> 
> -    ;       div(reg_or_mem_ref_op)
> -            % Unsigned divide RDX:RAX by the value in 'reg_or_mem_ref_op'.
> +    ;       div(
> +                div_op          :: operand
> +                                % register or memory reference
> +            )
> +            % Unsigned divide RDX:RAX by the value in 'div_op'.
>              % Details on amd64-prog-man-vol3 manual p122.
> 
>      ;       enter(
> @@ -1067,166 +948,87 @@
>              % 'enter_nesting_level'(0 to 31).
>              % Details on amd64-prog-man-vol3 manual p124.
> 
> -    ;       idiv(reg_or_mem_ref_op)
> -            % Signed divide RDX:RAX by the value in 'reg_or_mem_ref_op'.
> -            % Details on amd64-prog-man-vol3 manual p126.
> -
> -    ;       imul(reg_or_mem_ref_op)
> -            % Signed multiply RAX by the value in 'reg_or_mem_ref_op'.
> -            % Details on amd64-prog-man-vol3 manual p128.
> -
> -    ;       imul(
> -                imul1_src           :: reg_or_mem_ref_op,
> -                imul1_dest          :: gp_reg
> +    ;       idiv(
> +                idiv_op             :: operand
> +                                    % register or memory reference
>              )
> -            % Signed multiply 'imul1_src' by 'imul1_dest'.
> -            % Details on amd64-prog-man-vol3 manual p129.
> +            % Signed divide RDX:RAX by the value in 'operand'.
> +            % Details on amd64-prog-man-vol3 manual p126.
> 
>      ;       imul(
> -                imul2_src           :: reg_or_mem_ref_op,
> -                imul2_multiplicand  :: imm_operand,
> -                imul2_dest          :: gp_reg
> +                imul_src            :: operand,
> +                                    % register, memory location, immediate 
> value
> +                imul_dest           :: maybe(operand),
> +                                    % register
> +                imul_multiplicand   :: maybe(operand)
> +            )
> +            % Signed multiply 'imul_src' by 'imul_dest' (if specified).
> +            % Otherwise multiply 'imul_src' by the value in RAX register.
> +            % Details on amd64-prog-man-vol3 manual p(128-129).
> +
> +    ;       inc(
> +                inc_op              :: operand
> +                                    % register or memory location
>              )
> -            % Signed multiply 'imul2_src' by 'imul2_multiplicand'.
> -            % Details on amd64-prog-man-vol3 manual p129.
> -
> -    ;       inc(reg_or_mem_ref_op)
> -            % Increments the contents of 'reg_or_mem_ref_op'.
> +            % Increments the contents of 'inc_op'.
>              % Details on amd64-prog-man-vol3 manual p133.
> 
> -    ;       jo(rel_offset)
> -            % Jumps if overflow (OF = 1).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jno(rel_offset)
> -            % Jumps if not overflow (OF = 0).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jb(rel_offset)
> -            % Jumps if below (CF = 1).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jc(rel_offset)
> -            % Jumps if carry (CF = 1).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jnae(rel_offset)
> -            % Jumps if not above or equal (CF = 1).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jnb(rel_offset)
> -            % Jumps if not below (CF = 0).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jnc(rel_offset)
> -            % Jumps if not carry (CF = 0).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jae(rel_offset)
> -            % Jumps if above or equal (CF = 0).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jz(rel_offset)
> -            % Jumps if zero (ZF = 1).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       je(rel_offset)
> -            % Jumps if equal (ZF = 1).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jnz(rel_offset)
> -            % Jumps if not zero (ZF = 0).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jne(rel_offset)
> -            % Jumps if not equal (ZF = 0).
> -            % Details on amd64-prog-man-vol3 manual p147.
> -
> -    ;       jbe(rel_offset)
> -            % Jumps if below or equal (CF = 1 or ZF = 1).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jna(rel_offset)
> -            % Jumps if not above (CF = 1 or ZF = 1).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jnbe(rel_offset)
> -            % Jumps if not below or equal (CF = 0 or ZF = 0).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       ja(rel_offset)
> -            % Jumps if above (CF = 0 or ZF = 0).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       js(rel_offset)
> -            % Jumps if sign (SF = 1).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jns(rel_offset)
> -            % Jumps if not sign (SF = 0).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jp(rel_offset)
> -            % Jumps if parity (PF = 1).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jpe(rel_offset)
> -            % Jumps if parity even (PF = 1).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jnp(rel_offset)
> -            % Jumps if not parity (PF = 0).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jpo(rel_offset)
> -            % Jumps if parity odd (PF = 0).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jl(rel_offset)
> -            % Jumps if less (SF <> OF).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jnge(rel_offset)
> -            % Jumps if not greater or equal (SF <> OF).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jnl(rel_offset)
> -            % Jumps if not less (SF = OF).
> -            % Details on amd64-prog-man-vol3 manual p148.
> -
> -    ;       jge(rel_offset)
> -            % Jumps if greater or equal (SF = OF).
> -            % Details on amd64-prog-man-vol3 manual p149.
> -
> -    ;       jle(rel_offset)
> -            % Jumps if less or equal (ZF = 1 or SF <> OF).
> -            % Details on amd64-prog-man-vol3 manual p149.
> -
> -    ;       jng(rel_offset)
> -            % Jumps if not greater (ZF = 1 or SF <> OF).
> -            % Details on amd64-prog-man-vol3 manual p149.
> -
> -    ;       jnle(rel_offset)
> -            % Jumps if not less or equal (ZF = 0 and SF = OF).
> -            % Details on amd64-prog-man-vol3 manual p149.
> -
> -    ;       jg(rel_offset)
> -            % Jumps if greater (ZF = 0 and SF = OF).
> -            % Details on amd64-prog-man-vol3 manual p149.
> -
> -    ;       jrcxz(rel_offset)
> -            % Jumps to the target instruction located at the specified 
> 8-bit
> -            % relative offset if RCX is zero.
> +    ;       j(
> +                j_target            :: operand,
> +                                    % relative offset
> +                j_condition         :: string
> +            )
> +            % Conditional jump. Valid values of 'j_condition' are:
> +            % O    -> jumps if overflow (OF = 1)
> +            % NO   -> jumps if not overflow (OF = 0)
> +            % B    -> jumps if below (CF = 1)
> +            % C    -> jumps if carry (CF = 1)
> +            % NAE  -> jumps if not above or equal (CF = 1)
> +            % NB   -> jumps if not below (CF = 0)
> +            % NC   -> jumps if not carry (CF = 0)
> +            % AE   -> jumps if above or equal (CF = 0)
> +            % Z    -> jumps if zero (ZF = 1)
> +            % E    -> jumps if equal (ZF = 1)
> +            % NZ   -> jumps if not zero (ZF = 0)
> +            % NE   -> jumps if not equal (ZF = 0)
> +            % BE   -> jumps if below or equal (CF = 1 or ZF = 1)
> +            % NA   -> jumps if not above (CF = 1 or ZF = 1)
> +            % NBE  -> jumps if not below or equal (CF = 0 or ZF = 0)
> +            % A    -> jumps if above (CF = 0 or ZF = 0)
> +            % S    -> jumps if sign (SF = 1)
> +            % NS   -> jumps if not sign (SF = 0)
> +            % P    -> jumps if parity (PF = 1)
> +            % PE   -> jumps if parity even (PF = 1)
> +            % NP   -> jumps if not parity (PF = 0)
> +            % PO   -> jumps if parity odd (PF = 0)
> +            % L    -> jumps if less (SF <> OF)
> +            % NGE  -> jumps if not greater or equal (SF <> OF)
> +            % NL   -> jumps if not less (SF = OF)
> +            % GE   -> jumps if greater or equal (SF = OF)
> +            % LE   -> jumps if less or equal (ZF = 1 or SF <> OF)
> +            % NG   -> jumps if not greater (ZF = 1 or SF <> OF)
> +            % NLE  -> jumps if not less or equal (ZF = 0 and SF = OF)
> +            % G    -> jumps if greater (ZF = 0 and SF = OF)
> +            % Details on amd64-prog-man-vol3 manual p(147-149).
> +
> +    ;       jrcxz(
> +                jrcxz_8bit_off  :: operand
> +            )
> +            % Jumps to the target instruction located at 'jrcxz_8bit_off'
> +            % if RCX is zero.
>              % Details on amd64-prog-man-vol3 manual p150.
> 
> -    ;       jmp(rmrol)
> -            % Jumps with target specified in 'rmrol': register, memory 
> location,
> -            % relative offset or label.
> +    ;       jmp(
> +                jmp_op          :: operand
> +            )
> +            % Jumps with target specified in 'jmp_op'
>              % Details on amd64-prog-man-vol3 manual p152.
> 
>      ;       lea(
> -                lea_src         :: mem_ref,
> -                lea_dest        :: gp_reg
> +                lea_src         :: operand,
> +                                % memory location
> +                lea_dest        :: operand
> +                                % register
>              )
>              % Stores effective address 'lea_src' into 'lea_dest'.
>              % Details on amd64-prog-man-vol3 manual p163.
> @@ -1236,74 +1038,93 @@
>              % Details on amd64-prog-man-vol3 manual p164.
> 
>      ;       loop(
> -                loop_rel_8bit   :: rel_offset
> +                loop_rel_8bit   :: operand
>              )
>              % Decrements RCX then jump if RCX is not zero
>              % Details on amd64-prog-man-vol3 manual p169.
> 
>      ;       loope(
> -                loope_rel_8bit  :: rel_offset
> +                loope_rel_8bit  :: operand
>              )
>              % Decrements RCX then jump if RCX is not zero and ZF = 1.
>              % Details on amd64-prog-man-vol3 manual p169.
> 
>      ;       loopne(
> -                loopne_rel_8bit :: rel_offset
> +                loopne_rel_8bit :: operand
>              )
>              % Decrements RCX then jump if RCX is not zero and ZF = 0.
>              % Details on amd64-prog-man-vol3 manual p169.
> 
>      ;       loopnz(
> -                loopnz_rel_8bit :: rel_offset
> +                loopnz_rel_8bit :: operand
>              )
>              % Decrements RCX then jump if RCX is not zero and ZF = 0.
>              % Details on amd64-prog-man-vol3 manual p170.
> 
>      ;       loopz(
> -                loopz_rel_8bit  :: rel_offset
> +                loopz_rel_8bit  :: operand
>              )
>              % Decrements RCX then jump if RCX is not zero and ZF = 1.
>              % Details on amd64-prog-man-vol3 manual p170.
> 
>      ;       mov(
>                  mov_src          :: operand,
> -                mov_dest         :: reg_or_mem_ref_op
> +                                 % register, memory location or immediate 
> value
> +                mov_dest         :: operand
> +                                 % register or memory location
>              )
> -            % Copies 'mov_src' to 'mov_dest'.
> +            % Copies 'mov_src' to 'mov_dest'. 'mov_dest' cannot be 
> immediate op.
>              % Details on amd64-prog-man-vol3 manual p173.
> 
> -    ;       mul(reg_or_mem_ref_op)
> -            % Unsigned multiply 'reg_or_mem_ref_op' by RAX.
> +    ;       mul(
> +                mul_op          :: operand
> +                                % register or memory location
> +            )
> +            % Unsigned multiply 'mul_op' by RAX.
>              % Details on amd64-prog-man-vol3 manual p190.
> 
> -    ;       neg(reg_or_mem_ref_op)
> -            % Performs a two's complement negation of 'reg_or_mem_ref_op'.
> +    ;       neg(
> +                neg_op          :: operand
> +                                % register or memory location
> +            )
> +            % Performs a two's complement negation of 'operand'.
>              % Details on amd64-prog-man-vol3 manual p192.
> 
>      ;       nop
>              % Increments RIP to point to next instruction.
>              % Details on amd64-prog-man-vol3 manual p194.
> 
> -    ;       not_(reg_or_mem_ref_op)
> -            % Performs one's complement negation (NOT) of 
> 'reg_or_mem_ref_op'.
> +    ;       x86_64_instr_not(
> +                not_op          :: operand
> +                                % register or memory location
> +            )
> +            % Performs one's complement negation (NOT) of 'operand'.
>              % Details on amd64-prog-man-vol3 manual p195.
> 
>      ;       or(
>                  or_src           :: operand,
> -                or_dest          :: reg_or_mem_ref_op
> +                                % register, memory location or immediate 
> value
> +                or_dest          :: operand
> +                                % register or memory location
>              )
>              % Performs a logical OR on the bits in 'or_src' and 'or_dest'.
>              % Details on amd64-prog-man-vol3 manual p196.
> 
> -    ;       pop(reg_or_mem_ref_op)
> -            % Pops the stack into 'reg_or_mem_ref_op'.
> +    ;       pop(
> +                pop_op           :: operand
> +                                % register or memory location.
> +            )
> +            % Pops the stack into 'operand'.
>              % Details on amd64-prog-man-vol3 manual p204.
> 
>      ;       popfq
>              % Pops a quadword from the stack to the RFLAGS register.
>              % Details on amd64-prog-man-vol3 manual p208.
> 
> -    ;       push(operand)
> +    ;       push(
> +                push_op           :: operand
> +                                  % register, memory location or immediate 
> value
> +            )
>              % Pushes the content of operand onto the stack.
>              % Details on amd64-prog-man-vol3 manual p215.
> 
> @@ -1311,273 +1132,142 @@
>              % Pushes the RFLAGS quadword onto the stack.
>              % Details on amd64-prog-man-vol3 manual p218.
> 
> -    ;       ret
> -            % Near return to the calling procedure.
> -            % Details on amd64-prog-man-vol3 manual p224.
> -
> -    ;       rcl(
> -                rcl_amount       :: cl_reg_or_imm_op,
> -                rcl_dest         :: reg_or_mem_ref_op
> -            )
> -            % Rotate bits in 'rcl_dest' to the left and through the carry 
> flag
> -            % by the number of bit positions as specified in 'rcl_amount'.
> -            % Details on amd64-prog-man-vol3 manual p220.
> -
> -    ;       rcr(
> -                rcr_amount      :: cl_reg_or_imm_op,
> -                rcr_dest        :: reg_or_mem_ref_op
> -            )
> -            % Rotate bits in 'rcr_dest' to the right and through the carry 
> flag
> -            % by the number of bit positions as specified in 'rcr_amount'.
> -            % Details on amd64-prog-man-vol3 manual p222.
> +    ;       rc(
> +                rc_amount        :: operand,
> +                                % unsigned immediate value or register
> +                rc_dest          :: operand,
> +                                % register or memory location
> +                rc_cond          :: string
> +                                % "R" for right, "L" for left
> +            )
> +            % Rotate bits in 'rc_dest' according to 'rc_cond' direction
> +            % and through the carry flag by the number of bit positions as
> +            % specified in 'rc_amount'.
> +            % Details on amd64-prog-man-vol3 manual p(220-222).
> 
> -    ;       ret(uint16)
> +    ;       ret(
> +                ret_op          :: maybe(uint16)
> +            )
>              % Near return to the calling procedure, then pop the specified
> -            % number of bytes from stack.
> +            % number of bytes from stack (if specified).
>              % Details on amd64-prog-man-vol3 manual p224.
> 
> -    ;       rol(
> -                rol_amount      :: cl_reg_or_imm_op,
> -                rol_dest        :: reg_or_mem_ref_op
> -            )
> -            % Rotates the bits of 'rol_dest' left by 'rol_amount' bits.
> -            % Details on amd64-prog-man-vol3 manual p230.
> -
> -    ;       ror(
> -                ror_amount      :: cl_reg_or_imm_op,
> -                ror_dest        :: reg_or_mem_ref_op
> -            )
> -            % Rotates the bits of 'ror_dest' right by 'ror_amount bits'.
> -            % Details on amd64-prog-man-vol3 manual p232.
> +    ;       ro(
> +                ro_amount       :: operand,
> +                                % unsigned immediate value or a register
> +                ro_dest         :: operand,
> +                                % register or memory location
> +                ro_dir          :: string
> +                                % "L" for left, "R" for right
> +            )
> +            % Rotates the bits of 'rol_dest' to the 'ro_dir' direction by
> +            % 'rol_amount' bits.
> +            % Details on amd64-prog-man-vol3 manual p(230-232).
> 
>      ;       sal(
> -                sal_amount      :: cl_reg_or_imm_op,
> -                sal_dest        :: reg_or_mem_ref_op
> +                sal_amount      :: operand,
> +                                % unsigned immediate value or register
> +                sal_dest        :: operand
> +                                % register or memory location
>              )
>              % Shift 'sal_dest' left by 'sal_amount'.
>              % Details on amd64-prog-man-vol3 manual p235.
> 
>      ;       shl(
> -                shl_amount      :: cl_reg_or_imm_op,
> -                shl_dest        :: reg_or_mem_ref_op
> +                shl_amount      :: operand,
> +                                % unsigned immediate value or register
> +                shl_dest        :: operand
> +                                % register or memory location
>              )
> -            % Shift 'shl_dest' left by 'shl_amount'.
> +            % Alias to 'sal'.
>              % Details on amd64-prog-man-vol3 manual p235.
> 
>      ;       sar(
> -                sar_amount      :: cl_reg_or_imm_op,
> -                sar_dest        :: reg_or_mem_ref_op
> +                sar_amount      :: operand,
> +                                % unsigned immediate value or register
> +                sar_dest        :: operand
> +                                % register or memory location
>              )
>              % Shift 'sar_dest' right by 'sar_amount'.
>              % Details on amd64-prog-man-vol3 manual p238.
> 
>      ;       sbb(
>                  sbb_src         :: operand,
> -                sbb_dest        :: reg_or_mem_ref_op
> +                                % immediate value, register or memory 
> location
> +                sbb_dest        :: operand
> +                                % register or memory location
>              )
>              % Subtracts 'sbb_src' from 'sbb_dest' with borrow.
>              % Details on amd64-prog-man-vol3 manual p241.
> 
> -    ;       seto(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If overflow
> -            % (OF = 1), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       setno(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If not overflow
> -            % (OF = 0), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       setb(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If flag is 
> below
> -            % (CF = 1), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -
> -    ;       setc(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If flag is 
> carry
> -            % (CF = 1), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       setnae(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If flag is not 
> above
> -            % or equal (CF = 1), set the value in the specified register 
> or an
> -            % 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       setnb(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If flag is not 
> below
> -            % (CF = 0), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       setnc(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If flag is not 
> carry
> -            % (CF = 0), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       setae(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If flag is 
> above or
> -            % equal (CF = 0), set the value in the specified register or an
> -            % 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       setz(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If zero (ZF = 
> 1),
> -            % set the value in the specified register or an 8-bit memory
> -            % reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       sete(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If equal (ZF = 
> 1),
> -            % set the value in the specified register or an 8-bit memory
> -            % reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       setnz(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If not zero
> -            % (ZF = 0), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       setne(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If not equal
> -            % (ZF = 0), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p246.
> -
> -    ;       setbe(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If below or 
> equal
> -            % (CF = 1 or ZF = 1), set the value in the specified register 
> or
> -            % an 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setna(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If not above
> -            % (CF = 1 or ZF = 1), set the value in the specified register 
> or
> -            % an 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setnbe(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If not below or
> -            % equal (CF = 0 and ZF = 0), set the value in the specified
> -            % register or an 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       seta(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If above
> -            % (CF = 0 and ZF = 0), set the value in the specified
> -            % register or an 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       sets(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If flag is 
> sign,
> -            % (SF = 1), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setns(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If flag is not 
> sign,
> -            % (SF = 0), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setp(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If flag is 
> parity
> -            % (PF = 1), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setpe(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If parity even,
> -            % (PF = 1), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setnp(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If not parity,
> -            % (PF = 0), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setpo(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If parity odd,
> -            % (PF = 0), set the value in the specified register or an 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setl(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If less (SF <> 
> OF),
> -            % set the value in the specified register or an 8-bit memory
> -            % reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setnge(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If not greater 
> or
> -            % equal (SF <> OF), set the value in the specified register or 
> an
> -            % 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setnl(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If not less
> -            % (SF = OF), set the value in the specified register or an 
> 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setge(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If greater or 
> equal
> -            % (SF = OF), set the value in the specified register or an 
> 8-bit
> -            % memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setle(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If less or 
> equal
> -            % (ZF = 1 or SF <> OF), set the value in the specified 
> register or
> -            % an 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setng(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If not greater
> -            % (ZF = 1 or SF <> OF), set the value in the specified 
> register or
> -            % an 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setnle(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If not less or 
> equal
> -            % (ZF = 0 and SF = OF), set the value in the specified 
> register or
> -            % an 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> -
> -    ;       setg(reg_or_mem_ref_op)
> -            % Check the status flag in the RFLAGS register. If greater
> -            % (ZF = 0 and SF = OF), set the value in the specified 
> register or
> -            % an 8-bit memory reference to 1.
> -            % Details on amd64-prog-man-vol3 manual p247.
> +    ;       set(
> +                set_dest        :: operand,
> +                                % register or memory location
> +                set_cond        :: string
> +            )
> +            % Check the status flag in the RFLAGS register. Set the value 
> in
> +            % the specified register/8-bit memory reference in 'set_dest' 
> to 1
> +            % according to the 'set_cond'. Valid vales of 'set_cond' are:
> +            %   O   ->  set if overflow (OF = 1)
> +            %   NO  ->  set if not overflow (OF = 0)
> +            %   B   ->  set if below (CF = 1)
> +            %   C   ->  set if carry (CF = 1)
> +            %   NAE ->  set if not above or equal (CF = 1)
> +            %   NB  ->  set if not below (CF = 0)
> +            %   NC  ->  set if not carry (CF = 0)
> +            %   AE  ->  set if above or equal (CF = 0)
> +            %   Z   ->  set if zero (ZF = 1)
> +            %   E   ->  set if equal (ZF = 1)
> +            %   NZ  ->  set if not zero (ZF = 0)
> +            %   NE  ->  set if not equal (ZF = 0)
> +            %   BE  ->  set if below or equal(CF = 1 or ZF = 1)
> +            %   NA  ->  set if not above (CF = 1 or ZF = 1)
> +            %   NBE ->  set if not below or equal(CF = 0 and ZF = 0)
> +            %   A   ->  set if above (CF = 0 and ZF = 0)
> +            %   S   ->  set if sign (SF = 1)
> +            %   NS  ->  set if sign (SF = 0)
> +            %   P   ->  set if parity (PF = 1)
> +            %   PE  ->  set if parity even (PF = 1)
> +            %   NP  ->  set if not parity (PF = 0)
> +            %   PO  ->  set if parity odd (PF = 0)
> +            %   L   ->  set if less (SF <> OF)
> +            %   NGE ->  set if not greater or equal (SF <> OF)
> +            %   NL  ->  set if not less (SF = OF)
> +            %   GE  ->  set if greater or equal (SF = OF)
> +            %   LE  ->  set if less or equal (ZF = 1 or SF <> OF)
> +            %   NG  ->  set if not greater (ZF = 1 or SF <> OF)
> +            %   NLE ->  set if not less or equal (ZF = 0 and SF = OF)
> +            %   G   ->  set if greater (ZF = 0 and SF = OF)
> +            % Details on amd64-prog-man-vol3 manual p(246-247).
> 
>      ;       shld(
> -                shld_amount         :: cl_reg_or_imm_op,
> -                shld_dest1          :: reg_or_mem_ref_op,
> -                shld_dest2          :: gp_reg
> +                shld_amount         :: operand,
> +                                    % register or immediate value
> +                shld_dest1          :: operand,
> +                                    % register or memory location
> +                shld_dest2          :: operand
> +                                    % register
>              )
>              % Shift 'shld_dest1' to the left by 'shld_amount' and shift in 
>              a bit
>              % pattern in 'shld_dest2' from the right.
>              % Details on amd64-prog-man-vol3 manual p251.
> 
>      ;       shr(
> -                shr_amount          :: cl_reg_or_imm_op,
> -                shr_dest            :: reg_or_mem_ref_op
> +                shr_amount          :: operand,
> +                                    % register or immediate value
> +                shr_dest            :: operand
> +                                    % register or memory location
>              )
>              % Shift 'shr_dest' right by 'shr_amount'.
>              % Details on amd64-prog-man-vol3 manual p253.
> 
>      ;       shrd(
> -                shrd_amount         :: cl_reg_or_imm_op,
> -                shrd_dest1          :: reg_or_mem_ref_op,
> -                shrd_dest2          :: gp_reg
> +                shrd_amount         :: operand,
> +                                    % register or immediate value
> +                shrd_dest1          :: operand,
> +                                    % register or memory location
> +                shrd_dest2          :: operand
> +                                    % register
>              )
>              % Shift 'shrd_dest1' to the right by 'shrd_amount' and shift in
>              % a bit pattern in 'shrd_dest2' from the left.
> @@ -1593,39 +1283,62 @@
> 
>      ;       sub(
>                  sub_src             :: operand,
> -                sub_dest            :: reg_or_mem_ref_op
> +                                    % imm value, register or memory 
> location
> +                sub_dest            :: operand
> +                                    % register or memory location
>              )
>              % Subtracts 'sub_src' from 'sub_dest'.
>              % Details on amd64-prog-man-vol3 manual p261.
> 
>      ;       test(
> -                test_src1           :: reg_or_mem_ref_op,
> -                test_src2           :: reg_or_imm_op
> +                test_src1           :: operand,
> +                                    % imm value or register
> +                test_src2           :: operand
> +                                    % register or memory location
>              )
>              % Performs a bitwise AND on 'test_src1' and 'test_src2'.
>              % Details on amd64-prog-man-vol3 manual p264.
> 
>      ;       xadd(
> -                xadd_src            :: gp_reg,
> -                xadd_dest           :: reg_or_mem_ref_op
> +                xadd_src            :: operand,
> +                                    % register
> +                xadd_dest           :: operand
> +                                    % register or memory location
>              )
>              % Exchanges the contents of 'xadd_src' with 'xadd_dest', load
>              % their sum into 'xadd_dest'.
>              % Details on amd64-prog-man-vol3 manual p266.
> 
>      ;       xchg(
> -                xchg_src1           :: reg_or_mem_ref_op,
> -                xchg_src2           :: reg_or_mem_ref_op
> +                xchg_src1           :: operand,
> +                                    % register or memory location
> +                xchg_src2           :: operand
> +                                    % register or memory location
>              )
>              % Exchanges the contents of 'xchg_src1' and 'xchg_src2'.
>              % Details on amd64-prog-man-vol3 manual p268.
> 
>      ;       xor(
>                  xor_src :: operand,
> -                xor_dest :: reg_or_mem_ref_op
> +                xor_dest :: operand
>              ).
>              % Performs a bitwise XOR on 'xor_src' with 'xor_dest' and 
>              stores
>              % the result in xor_dest.
>              % Details on amd64-prog-man-vol3 manual p272.
> 
> 
> %-----------------------------------------------------------------------------%
> +%-----------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +init_x86_64_module(CModule) = x86_64_module(CModule, []).
> +
> +init_x86_64_proc(CProc) =
> +    x86_64_procedure(CProc ^ cproc_name,  CProc ^ cproc_orig_arity,
> +        CProc ^ cproc_id, CProc ^ cproc_code_model, [],
> +        CProc ^ cproc_proc_label, CProc ^ cproc_label_nums,
> +        CProc ^ cproc_may_alter_rtti, CProc ^ cproc_c_global_vars).
> +
> +init_x86_64_instruction = x86_64_instr([], "").
> +
> +%-----------------------------------------------------------------------------%
> Index: compiler/x86_64_out.m
> ===================================================================
> RCS file: 
> /home/mercury/mercury1/repository/mercury/compiler/x86_64_out.m,v
> retrieving revision 1.1
> diff -u -r1.1 x86_64_out.m
> --- compiler/x86_64_out.m	15 Jan 2007 22:49:41 -0000	1.1
> +++ compiler/x86_64_out.m	31 Jan 2007 22:25:37 -0000
> @@ -22,7 +22,10 @@
> 
> 
> %-----------------------------------------------------------------------------%
> 
> -:- pred output_x86_64_instrs(x86_64_instr::in, io::di, io::uo) is det.
> +:- pred output_x86_64_instruction(x86_64_instruction::in,
> +    io::di, io::uo) is det.
> +
> +:- pred operand_type(operand::in, string::out) is det.
> 
>      % XXX This is just for testing purposes.
>      %
> @@ -43,105 +46,6 @@
>  :- import_module type_desc.
> 
> 
> %-----------------------------------------------------------------------------%
> -
> -    % XXX This is just for testing purposes.
> -    %
> -% pretend_main(!IO) :-
> -%     Comment1 = comment("This is a comment"),
> -%     Label1 = label(".L1"),
> -%     PseudoOps1 = [
> -%         abort,
> -%         align(6, no, yes(2)),
> -%         align(7, yes(12), no),
> -%         align(8, no, no),
> -%         ascii([".LI", ".L2"]),
> -%         comm(".L3", 8, no),
> -%         section(".data", no, no, no)
> -%         ],
> -%     Instrs1 = [
> -%         x86_64_instr(adc(operand_reg(rax),
> -%                      rmro_reg(rbx)
> -%                     ), ""),
> -%         x86_64_instr(add(operand_imm(imm8(int8(0x178))),
> -%                      rmro_mem_ref(mem_abs(base_reg(0, r8)))
> -%                     ), ""),
> -%         x86_64_instr(and(operand_reg(rdx),
> -%                      rmro_mem_ref(mem_abs(base_reg(2, rdx)))
> -%                     ), ""),
> -%         x86_64_instr(bsf(rmro_reg(r8), r15), ""),
> -%         x86_64_instr(bsr(rmro_reg(rcx), rax), ""),
> -%         x86_64_instr(bswap(r10), ""),
> -%         x86_64_instr(bt(rmro_mem_ref(mem_rip(rip_expr(".L1"))),
> -%             rio_reg(rsi)), ""),
> -%         x86_64_instr(btc(rmro_reg(rdi), rio_imm(imm16(int16(0x1822)))), 
> ""),
> -%         x86_64_instr(btr(rmro_reg(rbp),
> -%             rio_imm(imm32(int32(0x182199)))), ""),
> -%         x86_64_instr(call(rmrol_rel_offset(ro8(int8(127)))), "comment"),
> -%         x86_64_instr(cmovo(rmro_mem_ref(mem_rip(rip_constant(int32(2)))),
> -%             r11), ""),
> -%         x86_64_instr(mov(operand_imm(imm32(int32(10))), rmro_reg(rbx)), 
> ""),
> -%         x86_64_instr(or(operand_mem_ref(mem_rip(rip_constant(int32(2)))),
> -%            rmro_reg(rcx)), ""),
> -%         x86_64_instr(push(operand_mem_ref(mem_abs(base_expr(".L2")))), 
> ""),
> -%          x86_64_instr(rol(crio_reg_cl(rcx), rmro_reg(rax)), ""),
> -%         x86_64_instr(ror(crio_imm8(int8(20)), rmro_mem_ref(mem_rip(
> -%             rip_expr(".L2")) )), ""),
> -%         x86_64_instr(sbb(operand_mem_ref(mem_rip(rip_expr(".L1"))),
> -%             rmro_reg(r11)), "")
> -%         ],
> -%
> -%     Label2 = label(".L2"),
> -%     PseudoOps2 = [
> -%         section(".rodata", yes("aMS"), yes("@progbits"), yes(1)),
> -%         p2align(1,no,yes(7)),
> -%         type_("Type", "@function")
> -%         ],
> -%     Instrs2 = [
> -%         x86_64_instr(loop(ro8(int8(19))), "another comment"),
> -%         x86_64_instr(xor(operand_imm(imm32(int32(19))),
> -%                      rmro_mem_ref(mem_rip(rip_expr(".L4")))
> -%                     ), "comment"),
> -%         x86_64_instr(jo(ro8(int8(22))), "comment again"),
> -%         x86_64_instr(div(rmro_reg(rdx)), "comment div"),
> -%         x86_64_instr(jmp(rmrol_label(".L2")), "comment jmp"),
> -%         x86_64_instr(mov(operand_mem_ref(mem_abs(base_expr(".L3"))),
> -%             rmro_reg(rbx)), "")
> -%         ],
> -%
> -%     Instructions = [
> -%         comment(""), label(""), directives([file("x86_64_out.m")]),
> -%           instrs([]),
> -%         Comment1, Label1, directives(PseudoOps1), instrs(Instrs1),
> -%         comment("Comment"), Label2, directives(PseudoOps2),
> -%           instrs(Instrs2)
> -%         ],
> -%     list.foldl(output_x86_64_instrs, Instructions, !IO).
> -
> -%-----------------------------------------------------------------------------%
> -
> -    % Output x86_64 instructions including comments, labels and 
> pseudo-ops.
> -    %
> -output_x86_64_instrs(comment(Comment), !IO) :-
> -    ( string.length(Comment) > 0 ->
> -        io.write_string("# " ++ Comment ++ "\n", !IO)
> -    ;
> -        true
> -    ).
> -output_x86_64_instrs(label(LabelName), !IO) :-
> -    ( string.length(LabelName) > 0 ->
> -        io.write_string(LabelName ++ ":\n", !IO)
> -    ;
> -        true
> -    ).
> -output_x86_64_instrs(directives(PseudoOps), !IO) :-
> -    list.foldl(output_x86_64_pseudo_op, PseudoOps, !IO).
> -output_x86_64_instrs(instrs(Instrs), !IO) :-
> -    ( list.length(Instrs) > 0 ->
> -        output_x86_64_instr_and_comment(Instrs, !IO)
> -    ;
> -        true
> -    ).
> -
> 
> %-----------------------------------------------------------------------------%
>  %
>  % Output x86_64 pseudo-op.
> @@ -191,7 +95,7 @@
>      output_pseudo_op_float_args(".double", NumList, !IO).
>  output_x86_64_pseudo_op(eject, !IO) :-
>      io.write_string("\t.eject\n", !IO).
> -output_x86_64_pseudo_op(else_, !IO) :-
> +output_x86_64_pseudo_op(x86_64_pseudo_else, !IO) :-
>      io.write_string("\t.else\n", !IO).
>  output_x86_64_pseudo_op(elseif, !IO) :-
>      io.write_string("\t.elseif\n", !IO).
> @@ -235,7 +139,7 @@
>      output_pseudo_op_str_args(".hword", ExprList, !IO).
>  output_x86_64_pseudo_op(ident, !IO) :-
>      io.write_string("\t.ident\n", !IO).
> -output_x86_64_pseudo_op(if_(Expr), !IO) :-
> +output_x86_64_pseudo_op(x86_64_pseudo_if(Expr), !IO) :-
>      io.write_string("\t.if\t" ++ Expr ++ "\n", !IO).
>  output_x86_64_pseudo_op(ifdef(Symbol), !IO) :-
>      io.write_string("\t.ifdef\t" ++ Symbol ++ "\n", !IO).
> @@ -377,7 +281,7 @@
>      io.write_string("\n", !IO).
>  output_x86_64_pseudo_op(title(Heading), !IO) :-
>      io.write_string("\t.title\t" ++ Heading ++ "\n", !IO).
> -output_x86_64_pseudo_op(type_(Name, Desc), !IO) :-
> +output_x86_64_pseudo_op(x86_64_pseudo_type(Name, Desc), !IO) :-
>      ( check_pseudo_type_desc(Desc) ->
>          io.write_string("\t.type\t" ++ Name ++ "," ++ Desc ++ "\n", !IO)
>      ;
> @@ -463,7 +367,7 @@
> 
>  pseudo_op_str_args_while([], !IO).
>  pseudo_op_str_args_while([Arg | Args], !IO) :-
> -    io.write_string(Arg, !IO),
> +    io.write_string(string.word_wrap("\"" ++ Arg ++ "\"", 68), !IO),
>      (
>          Args = [],
>          pseudo_op_str_args_while(Args, !IO)
> @@ -472,7 +376,7 @@
>          io.write_string(",", !IO),
>          pseudo_op_str_args_while(Args, !IO)
>      ).
> -
> +
>      % Check if FLAGS and TYPE argument of '.section' pseudo-op is valid
>      %
>  :- pred check_section_flags_and_type(string::in, maybe(string)::in,
> @@ -549,134 +453,177 @@
>  % Output x86_64 instructions.
>  %
> 
> -:- pred output_x86_64_instr_and_comment(list(x86_64_instruction)::in, 
> io::di,
> -    io::uo) is det.
> -
> -output_x86_64_instr_and_comment([], !IO).
> -output_x86_64_instr_and_comment([Instr | Instrs], !IO) :-
> -    Instr = x86_64_instr(InstrName, Comment),
> -    output_x86_64_instr(InstrName, !IO),
> +    % Output x86_64 instruction and comment.
> +    %
> +output_x86_64_instruction(x86_64_instr(Instr, Comment), !IO) :-
>      output_comment(Comment, !IO),
> -    output_x86_64_instr_and_comment(Instrs, !IO).
> +    output_x86_64_instr_list(Instr, !IO),
> +    io.write_string("\n", !IO).
> 
> -    % Output x86_64 instruction and its operands (if any).
> +:- pred output_x86_64_instr_list(list(x86_64_instr)::in, io::di, io::uo) 
> is det.
> +
> +output_x86_64_instr_list([], !IO).
> +output_x86_64_instr_list([Instr | Instrs], !IO) :-
> +    output_x86_64_instr(Instr, !IO),
> +    output_x86_64_instr_list(Instrs, !IO).

You can use folds for this list iteration idiom:

output_x86_64_instr_list(Instrs, !IO) :-
	list.foldl(output_x86_64_instr, Instrs, !IO).

folds can save you typing a lot of boiler-plate.

> +
> +:- pred output_x86_64_instr(x86_64_instr::in, io::di, io::uo) is det.
> +
> +output_x86_64_instr(comment(Comment), !IO) :-
> +    ( string.length(Comment) > 0 ->
> +        io.write_string("\t# ", !IO),
> +        ( string.length(Comment) > 68 ->
> +            string.split(Comment, 68, Comment1, Comment2),

Embedding magic numbers in code is naughty!  Define a constant instead.

> +            io.write_string(string.word_wrap(Comment1, 68), !IO),
> +            io.write_string("\n", !IO),
> +            output_x86_64_instr(comment(Comment2), !IO)
> +        ;
> +            io.write_string(string.word_wrap(Comment, 68), !IO)
> +        )
> +    ;
> +        true
> +    ).
> +output_x86_64_instr(label(LabelName), !IO) :-
> +    ( string.length(LabelName) > 0 ->
> +        io.write_string("\n" ++ LabelName ++ ":", !IO)
> +    ;
> +        true
> +    ).
> +output_x86_64_instr(directive(PseudoOp), !IO) :-
> +    output_x86_64_pseudo_op(PseudoOp, !IO).
> +output_x86_64_instr(instr(Instr), !IO) :-
> +    output_x86_64_inst(Instr, !IO),
> +    io.write_string("\n", !IO).
> +
> +
> +    % Output a single x86_64 instruction and its operands (if any).
>      %
> -:- pred output_x86_64_instr(x86_64_op::in, io::di, io::uo) is det.
> +:- pred output_x86_64_inst(x86_64_inst::in, io::di, io::uo) is det.
> 
> -output_x86_64_instr(adc(Src, Dest), !IO) :-
> -    instr_with_op_and_rmro("adc", Src, Dest, !IO).
> -output_x86_64_instr(add(Src, Dest), !IO) :-
> -    instr_with_op_and_rmro("add", Src, Dest, !IO).
> -output_x86_64_instr(and(Src, Dest), !IO) :-
> -    instr_with_op_and_rmro("and", Src, Dest, !IO).
> -output_x86_64_instr(bsf(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("bsf", Src, Dest, !IO).
> -output_x86_64_instr(bsr(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("bsr", Src, Dest, !IO).
> -output_x86_64_instr(bswap(Reg), !IO) :-
> -    io.write_string("\tbswap\t", !IO),
> -    reg_type(Reg, RegType),
> -    io.write_string(RegType ++ "\t", !IO).
> -output_x86_64_instr(bt(Src, Idx), !IO) :-
> -    instr_with_rmro_and_rio("bt", Src, Idx, !IO).
> -output_x86_64_instr(btc(Src, Idx), !IO) :-
> -    instr_with_rmro_and_rio("btc", Src, Idx, !IO).
> -output_x86_64_instr(btr(Src, Idx), !IO) :-
> -    instr_with_rmro_and_rio("btr", Src, Idx, !IO).
> -output_x86_64_instr(bts(Src, Idx), !IO) :-
> -    instr_with_rmro_and_rio("bts", Src, Idx, !IO).
> -output_x86_64_instr(call(TargetLocation), !IO) :-
> -    instr_with_rmrol("call", TargetLocation, !IO).
> -output_x86_64_instr(cbw, !IO) :-
> +output_x86_64_inst(adc(Src, Dest), !IO) :-
> +    output_instr_not_imm_dest("adc", Src, yes(Dest), !IO).
> +output_x86_64_inst(add(Src, Dest), !IO) :-
> +    output_instr_not_imm_dest("add", Src, yes(Dest), !IO).
> +output_x86_64_inst(and(Src, Dest), !IO) :-
> +    output_instr_not_imm_dest("and", Src, yes(Dest), !IO).
> +output_x86_64_inst(bs(Src, Dest, Cond), !IO) :-
> +    check_operand_not_immediate(Src, Result1),
> +    (
> +        Result1 = yes,
> +        operand_type(Src, SrcType),
> +        check_operand_register(Dest, DestRes),
> +        (
> +            DestRes = yes,
> +            CondRes = string.to_lower(Cond),
> +            ( CondRes = "f" ->
> +                true
> +            ;
> +                CondRes = "r" ->
> +                true

The comment for bs(_, _, _) uses "F" and "R".  I know you're using
string.to_lower here, but this is the sort of thing that can lead to
buggy code.

> +            ;
> +                unexpected(this_file, "output_x86_64_inst: unexpected:
> +                    invalid condition bs third operand")
> +            ),
> +            io.write_string("\tbs" ++ CondRes ++ "\t", !IO),
> +            operand_type(Dest, DestType),
> +            io.write_string(SrcType ++ ", " ++ DestType ++ "\t", !IO)
> +        ;
> +            DestRes = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected: bs
> +                second operand is not a register")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected: bsf first 
> operand
> +            is an immediate value")
> +    ).
> +output_x86_64_inst(bswap(Op), !IO) :-
> +    check_operand_register(Op, Result),
> +    (
> +        Result = yes,
> +        operand_type(Op, RegType),
> +        io.write_string("\tbswap\t" ++ RegType ++ "\t\t", !IO)
> +    ;
> +        Result = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected: bswap 
> operand is
> +            not a register")

String overrun.

> +    ).
> +output_x86_64_inst(bt(Src, Idx), !IO) :-
> +    output_bit_test_instr("bt", Src, Idx, !IO).
> +output_x86_64_inst(btc(Src, Idx), !IO) :-
> +    output_bit_test_instr("btc", Src, Idx, !IO).
> +output_x86_64_inst(btr(Src, Idx), !IO) :-
> +    output_bit_test_instr("btr", Src, Idx, !IO).
> +output_x86_64_inst(bts(Src, Idx), !IO) :-
> +    output_bit_test_instr("bts", Src, Idx, !IO).
> +output_x86_64_inst(call(Target), !IO) :-
> +    check_operand_not_immediate(Target, Result),
> +    (
> +        Result = yes,
> +        operand_type(Target, TargetType),
> +        io.write_string("\tcall\t" ++ TargetType ++ "\t\t", !IO)
> +    ;
> +        Result = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected call 
> operand")
> +    ).
> +output_x86_64_inst(cbw, !IO) :-
>      io.write_string("\tcbw\t", !IO).
> -output_x86_64_instr(cwde, !IO) :-
> +output_x86_64_inst(cwde, !IO) :-
>      io.write_string("\tcwde\t", !IO).
> -output_x86_64_instr(cdqe, !IO) :-
> +output_x86_64_inst(cdqe, !IO) :-
>      io.write_string("\tcdqe\t", !IO).
> -output_x86_64_instr(cwd, !IO) :-
> +output_x86_64_inst(cwd, !IO) :-
>      io.write_string("\tcwd\t", !IO).
> -output_x86_64_instr(cdq, !IO) :-
> +output_x86_64_inst(cdq, !IO) :-
>      io.write_string("\tcdq\t", !IO).
> -output_x86_64_instr(cqo, !IO) :-
> +output_x86_64_inst(cqo, !IO) :-
>      io.write_string("\tcqo\t", !IO).
> -output_x86_64_instr(clc, !IO) :-
> +output_x86_64_inst(clc, !IO) :-
>      io.write_string("\tclc\t", !IO).
> -output_x86_64_instr(cld, !IO) :-
> +output_x86_64_inst(cld, !IO) :-
>      io.write_string("\tcld\t", !IO).
> -output_x86_64_instr(cmc, !IO) :-
> +output_x86_64_inst(cmc, !IO) :-
>      io.write_string("\tcmc\t", !IO).
> -output_x86_64_instr(cmovo(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovo", Src, Dest, !IO).
> -output_x86_64_instr(cmovno(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovno", Src, Dest, !IO).
> -output_x86_64_instr(cmovb(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovb", Src, Dest, !IO).
> -output_x86_64_instr(cmovc(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovc", Src, Dest, !IO).
> -output_x86_64_instr(cmovnae(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovnae", Src, Dest, !IO).
> -output_x86_64_instr(cmovnb(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovnb", Src, Dest, !IO).
> -output_x86_64_instr(cmovnc(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovnc", Src, Dest, !IO).
> -output_x86_64_instr(cmovae(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovae", Src, Dest, !IO).
> -output_x86_64_instr(cmovz(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovz", Src, Dest, !IO).
> -output_x86_64_instr(cmove(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmove", Src, Dest, !IO).
> -output_x86_64_instr(cmovnz(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovnz", Src, Dest, !IO).
> -output_x86_64_instr(cmovne(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovne", Src, Dest, !IO).
> -output_x86_64_instr(cmovbe(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovbe", Src, Dest, !IO).
> -output_x86_64_instr(cmovna(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovna", Src, Dest, !IO).
> -output_x86_64_instr(cmovnbe(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovnbe", Src, Dest, !IO).
> -output_x86_64_instr(cmova(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmova", Src, Dest, !IO).
> -output_x86_64_instr(cmovs(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovs", Src, Dest, !IO).
> -output_x86_64_instr(cmovns(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovns", Src, Dest, !IO).
> -output_x86_64_instr(cmovp(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovp", Src, Dest, !IO).
> -output_x86_64_instr(cmovpe(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovpe", Src, Dest, !IO).
> -output_x86_64_instr(cmovnp(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovnp", Src, Dest, !IO).
> -output_x86_64_instr(cmovpo(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovpo", Src, Dest, !IO).
> -output_x86_64_instr(cmovl(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovl", Src, Dest, !IO).
> -output_x86_64_instr(cmovnge(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovnge", Src, Dest, !IO).
> -output_x86_64_instr(cmovnl(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovnl", Src, Dest, !IO).
> -output_x86_64_instr(cmovge(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovge", Src, Dest, !IO).
> -output_x86_64_instr(cmovle(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovle", Src, Dest, !IO).
> -output_x86_64_instr(cmovng(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovng", Src, Dest, !IO).
> -output_x86_64_instr(cmovnle(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovnle", Src, Dest, !IO).
> -output_x86_64_instr(cmovg(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("cmovg", Src, Dest, !IO).
> -output_x86_64_instr(cmp(Src, Dest), !IO) :-
> -    instr_with_op_and_rmro("cmp", Src, Dest, !IO).
> -output_x86_64_instr(cmpxchg(Cmp, Xchg), !IO) :-
> -    instr_with_rmro_and_reg("cmpxchg", Cmp, Xchg, !IO).
> -output_x86_64_instr(cmpxchg8b(MemRef), !IO) :-
> -    mem_ref_type(MemRef, MemRefType),
> -    io.write_string("\tcmpxchg8b" ++ MemRefType, !IO).
> -output_x86_64_instr(dec(RegOrMemRef), !IO) :-
> -    instr_with_rmro("dec", RegOrMemRef, !IO).
> -output_x86_64_instr(div(RegOrMemRef), !IO) :-
> -    instr_with_rmro("div", RegOrMemRef, !IO).
> -output_x86_64_instr(enter(StackSize, NestingLevel), !IO) :-
> +output_x86_64_inst(cmov(Src, Dest, Cond), !IO) :-
> +    output_instr_with_condition("cmov", Src, yes(Dest), Cond, !IO).
> +output_x86_64_inst(cmp(Src, Dest), !IO) :-
> +    output_instr_not_imm_dest("cmp", Src, yes(Dest), !IO).
> +output_x86_64_inst(cmpxchg(Src, Dest), !IO) :-
> +    check_operand_not_immediate(Src, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_register(Dest, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Src, Op1),
> +            operand_type(Dest, Op2),
> +            io.write_string("\tcmp\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected:
> +                second operand xmpxchg is a register")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected:
> +            first operand is an immediate value")
> +    ).
> +output_x86_64_inst(cmpxchg8b(Op), !IO) :-
> +    check_operand_not_mem_ref(Op, Result),
> +    (
> +        Result = no,
> +        operand_type(Op, OpType),
> +        io.write_string("\tcmpxchg8b" ++ OpType, !IO)
> +    ;
> +        Result = yes,
> +        unexpected(this_file, "output_x86_64_instr: unexpected:
> +            operand is not a memory reference")
> +    ).
> +output_x86_64_inst(dec(Operand), !IO) :-
> +    output_instr_not_imm_dest("dec", Operand, no, !IO).
> +output_x86_64_inst(div(Operand), !IO) :-
> +    output_instr_not_imm_dest("div", Operand, no, !IO).
> +output_x86_64_inst(enter(StackSize, NestingLevel), !IO) :-
>      StackSize = uint16(Size),
>      NestingLevel = uint8(Level),
>      check_unsigned_int_size(16, Size, Result0),
> @@ -693,231 +640,381 @@
>      ;
>          unexpected(this_file, "output_x86_64_instr: enter unexpected")
>      ).
> -output_x86_64_instr(idiv(RegOrMemRef), !IO) :-
> -    instr_with_rmro("idiv", RegOrMemRef, !IO).
> -output_x86_64_instr(imul(RegOrMemRef), !IO) :-
> -    instr_with_rmro("idiv", RegOrMemRef, !IO).
> -output_x86_64_instr(imul(Src, Dest), !IO) :-
> -    instr_with_rmro_and_reg("imul", Src, Dest, !IO).
> -output_x86_64_instr(imul(RegOrMemRefOp, Imm, Reg), !IO) :-
> -    io.write_string("\timul\t", !IO),
> -    rmro_type(RegOrMemRefOp, Type),
> -    io.write_string(Type ++ ", ", !IO),
> -    imm_op_type(Imm, ImmVal),
> -    io.write_string(ImmVal ++ ", ", !IO),
> -    reg_type(Reg, RegType),
> -    io.write_string(RegType ++ "\t", !IO).
> -output_x86_64_instr(inc(RegOrMemRef), !IO) :-
> -    instr_with_rmro("inc", RegOrMemRef, !IO).
> -output_x86_64_instr(jo(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jo", RelOffset, !IO).
> -output_x86_64_instr(jno(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jno", RelOffset, !IO).
> -output_x86_64_instr(jb(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jb", RelOffset, !IO).
> -output_x86_64_instr(jc(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jc", RelOffset, !IO).
> -output_x86_64_instr(jnae(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jnae", RelOffset, !IO).
> -output_x86_64_instr(jnb(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jnb", RelOffset, !IO).
> -output_x86_64_instr(jnc(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jnc", RelOffset, !IO).
> -output_x86_64_instr(jae(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jae", RelOffset, !IO).
> -output_x86_64_instr(jz(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jz", RelOffset, !IO).
> -output_x86_64_instr(je(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("je", RelOffset, !IO).
> -output_x86_64_instr(jnz(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jnz", RelOffset, !IO).
> -output_x86_64_instr(jne(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jne", RelOffset, !IO).
> -output_x86_64_instr(jbe(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jbe", RelOffset, !IO).
> -output_x86_64_instr(jna(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jna", RelOffset, !IO).
> -output_x86_64_instr(jnbe(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jnbe", RelOffset, !IO).
> -output_x86_64_instr(ja(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("ja", RelOffset, !IO).
> -output_x86_64_instr(js(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("js", RelOffset, !IO).
> -output_x86_64_instr(jns(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jns", RelOffset, !IO).
> -output_x86_64_instr(jp(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jp", RelOffset, !IO).
> -output_x86_64_instr(jpe(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jpe", RelOffset, !IO).
> -output_x86_64_instr(jnp(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jnp", RelOffset, !IO).
> -output_x86_64_instr(jpo(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jpo", RelOffset, !IO).
> -output_x86_64_instr(jl(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jl", RelOffset, !IO).
> -output_x86_64_instr(jnge(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jnge", RelOffset, !IO).
> -output_x86_64_instr(jnl(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jnl", RelOffset, !IO).
> -output_x86_64_instr(jge(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jge", RelOffset, !IO).
> -output_x86_64_instr(jle(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jle", RelOffset, !IO).
> -output_x86_64_instr(jng(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jng", RelOffset, !IO).
> -output_x86_64_instr(jnle(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jnle", RelOffset, !IO).
> -output_x86_64_instr(jg(RelOffset), !IO) :-
> -    instr_with_rel_offset_op("jg", RelOffset, !IO).
> -output_x86_64_instr(jrcxz(RelOffset), !IO) :-
> -    instr_with_8bit_rel_offset_op("jrcxz", RelOffset, !IO).
> -output_x86_64_instr(jmp(Target), !IO) :-
> -    instr_with_rmrol("jmp", Target, !IO).
> -output_x86_64_instr(lea(Src, Dest), !IO) :-
> -    instr_with_mem_ref_and_reg_op("lea", Src, Dest, !IO).
> -output_x86_64_instr(leave, !IO) :-
> +output_x86_64_inst(idiv(Operand), !IO) :-
> +    output_instr_not_imm_dest("idiv", Operand, no, !IO).
> +output_x86_64_inst(imul(Src, Dest, Mult), !IO) :-
> +    operand_type(Src, SrcType),
> +    io.write_string("\timul\t" ++ SrcType, !IO),
> +    (
> +        Dest = yes(DestRes),
> +        check_operand_register(DestRes, Result1),
> +        (
> +            Result1 = yes,
> +            operand_type(DestRes, DestType),
> +            io.write_string(", " ++ DestType, !IO),
> +            (
> +                Mult = yes(MultRes),
> +                operand_type(MultRes, Op3),
> +                io.write_string(", " ++ Op3 ++ " ", !IO)
> +            ;
> +                Mult = no,
> +                io.write_string("\t", !IO)
> +            )
> +        ;
> +
> +            Result1 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected:
> +                second operand is not a register")
> +        )
> +    ;
> +        Dest = no,
> +        io.write_string("\t\t", !IO)
> +   ).
> +output_x86_64_inst(inc(Operand), !IO) :-
> +    output_instr_not_imm_dest("inc", Operand, no, !IO).
> +output_x86_64_inst(j(Offset, Cond), !IO) :-
> +    output_instr_with_condition("j", Offset, no, Cond, !IO).
> +output_x86_64_inst(jrcxz(RelOffset), !IO) :-
> +    output_instr_8bit_rel_offset("jrcxz", RelOffset, !IO).
> +output_x86_64_inst(jmp(Target), !IO) :-
> +    operand_type(Target, Op),
> +    io.write_string("\tjmp\t" ++ Op ++ "\t\t", !IO).
> +output_x86_64_inst(lea(Src, Dest), !IO) :-
> +    check_operand_not_mem_ref(Src, Result1),
> +    (
> +        Result1 = no,
> +        check_operand_register(Dest, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Src, Op1),
> +            operand_type(Dest, Op2),
> +            io.write_string("\tlea\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_inst: unexpected:
> +                second operand is not a register")
> +        )
> +    ;
> +        Result1 = yes,
> +        unexpected(this_file, "output_x86_64_inst: unexpected:
> +            first operand is not a memory reference")
> +    ).
> +output_x86_64_inst(leave, !IO) :-
>      io.write_string("\tleave\t", !IO).
> -output_x86_64_instr(loop(RelOffset), !IO) :-
> -    instr_with_8bit_rel_offset_op("loop", RelOffset, !IO).
> -output_x86_64_instr(loope(RelOffset), !IO) :-
> -    instr_with_8bit_rel_offset_op("loope", RelOffset, !IO).
> -output_x86_64_instr(loopne(RelOffset), !IO) :-
> -    instr_with_8bit_rel_offset_op("loopne", RelOffset, !IO).
> -output_x86_64_instr(loopnz(RelOffset), !IO) :-
> -    instr_with_8bit_rel_offset_op("loopnz", RelOffset, !IO).
> -output_x86_64_instr(loopz(RelOffset), !IO) :-
> -    instr_with_8bit_rel_offset_op("loopz", RelOffset, !IO).
> -output_x86_64_instr(mov(Source, Dest), !IO) :-
> -    instr_with_op_and_rmro("mov", Source, Dest, !IO).
> -output_x86_64_instr(mul(RegOrMemRef), !IO) :-
> -    instr_with_rmro("mul", RegOrMemRef, !IO).
> -output_x86_64_instr(neg(RegOrMemRef), !IO) :-
> -    instr_with_rmro("neg", RegOrMemRef, !IO).
> -output_x86_64_instr(nop, !IO) :-
> +output_x86_64_inst(loop(RelOffset), !IO) :-
> +    output_instr_8bit_rel_offset("loop", RelOffset, !IO).
> +output_x86_64_inst(loope(RelOffset), !IO) :-
> +    output_instr_8bit_rel_offset("loope", RelOffset, !IO).
> +output_x86_64_inst(loopne(RelOffset), !IO) :-
> +    output_instr_8bit_rel_offset("loopne", RelOffset, !IO).
> +output_x86_64_inst(loopnz(RelOffset), !IO) :-
> +    output_instr_8bit_rel_offset("loopnz", RelOffset, !IO).
> +output_x86_64_inst(loopz(RelOffset), !IO) :-
> +    output_instr_8bit_rel_offset("loopz", RelOffset, !IO).
> +output_x86_64_inst(mov(Src, Dest), !IO) :-
> +    output_instr_not_imm_dest("mov", Src, yes(Dest), !IO).
> +output_x86_64_inst(mul(Operand), !IO) :-
> +    output_instr_not_imm_dest("mul", Operand, no, !IO).
> +output_x86_64_inst(neg(Operand), !IO) :-
> +    output_instr_not_imm_dest("neg", Operand, no, !IO).
> +output_x86_64_inst(nop, !IO) :-
>      io.write_string("nop", !IO).
> -output_x86_64_instr(not_(RegOrMemRef), !IO) :-
> -    instr_with_rmro("not", RegOrMemRef, !IO).
> -output_x86_64_instr(or(Src, Dest), !IO) :-
> -    instr_with_op_and_rmro("or", Src, Dest, !IO).
> -output_x86_64_instr(pop(RegOrMemRefOp), !IO) :-
> -    instr_with_rmro("pop", RegOrMemRefOp, !IO).
> -output_x86_64_instr(popfq, !IO) :-
> +output_x86_64_inst(x86_64_instr_not(Operand), !IO) :-
> +    output_instr_not_imm_dest("not", Operand, no, !IO).
> +output_x86_64_inst(or(Src, Dest), !IO) :-
> +    output_instr_not_imm_dest("or", Src, yes(Dest), !IO).
> +output_x86_64_inst(pop(Operand), !IO) :-
> +    output_instr_not_imm_dest("pop", Operand, no, !IO).
> +output_x86_64_inst(popfq, !IO) :-
>      io.write_string("\tpopfq\t", !IO).
> -output_x86_64_instr(push(Operand), !IO) :-
> +output_x86_64_inst(push(Operand), !IO) :-
>      io.write_string("\tpush\t", !IO),
>      operand_type(Operand, OperandType),
>      io.write_string(OperandType ++ "\t", !IO).
> -output_x86_64_instr(pushfq, !IO) :-
> +output_x86_64_inst(pushfq, !IO) :-
>      io.write_string("\tpushfq\t", !IO).
> -output_x86_64_instr(rcl(ClRegOrImm, RegOrMemRef), !IO) :-
> -    instr_with_crio_and_rmro("rcl", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(rcr(ClRegOrImm, RegOrMemRef), !IO) :-
> -    instr_with_crio_and_rmro("rcr", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(ret, !IO) :-
> -    io.write_string("\tret\t", !IO).
> -output_x86_64_instr(ret(uint16(NumBytes)), !IO) :-
> -    check_unsigned_int_size(16, NumBytes, Result),
> +output_x86_64_inst(rc(Amnt, Dest, Cond), !IO) :-
> +    check_rc_first_operand(Amnt, Result1),
>      (
> +        Result1 = yes,
> +        check_operand_not_immediate(Dest, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Amnt, Op1),
> +            operand_type(Dest, Op2),
> +            io.write_string("\trc\t" ++ Cond, !IO),
> +            io.write_string(Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected
> +                rc second operand is an immediate value")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected rc
> +            first operand")
> +    ).
> +output_x86_64_inst(ret(Op), !IO) :-
> +    (
> +        Op = yes(OpRes),
> +        OpRes = uint16(NumBytes)
> +    ->
> +        check_unsigned_int_size(16, NumBytes, Result),
> +        (
> +            Result = yes,
> +            io.write_string("\tret\t", !IO),
> +            io.write_int(NumBytes, !IO),
> +            io.write_string("\t", !IO)
> +        ;
> +            Result = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected ret
> +                uint operand size")
> +        )
> +    ;
> +        Op = no
> +    ->
> +        io.write_string("\tret\t\t", !IO)
> +    ;
> +        unexpected(this_file, "output_x86_64_instr: unexpected ret 
> operand")
> +    ).
> +output_x86_64_inst(ro(Amnt, Dest, Dir), !IO) :-
> +    check_operand_not_mem_ref(Amnt, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_not_immediate(Dest, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Amnt, Op1),
> +            operand_type(Dest, Op2),
> +            io.write_string("\tro" ++ Dir ++ "\t", !IO),
> +            io.write_string(Op1 ++ ", " ++ Op2 ++ "\t\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: ro unexpected")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: ro unexpected")
> +    ).
> +output_x86_64_inst(sal(Amnt, Dest), !IO) :-
> +    check_operand_unsigned_imm_or_reg(Amnt, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_not_immediate(Dest, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Amnt, Op1),
> +            operand_type(Dest, Op2),
> +            io.write_string("\tsal\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected: sal
> +                second operand is an immediate value")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected: sal
> +            first operand")
> +    ).
> +output_x86_64_inst(shl(Amnt, Dest), !IO) :-
> +    check_operand_unsigned_imm_or_reg(Amnt, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_not_immediate(Dest, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Amnt, Op1),
> +            operand_type(Dest, Op2),
> +            io.write_string("\tshl\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected: shl
> +                second operand is an immediate value")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected: shl
> +            first operand")
> +    ).
> +output_x86_64_inst(sar(Amnt, Dest), !IO) :-
> +    check_operand_unsigned_imm_or_reg(Amnt, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_not_immediate(Dest, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Amnt, Op1),
> +            operand_type(Dest, Op2),
> +            io.write_string("\tsar\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected: sar
> +                second operand is an immediate value")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected: sar
> +            first operand")
> +    ).
> +output_x86_64_inst(sbb(Src, Dest), !IO) :-
> +    output_instr_not_imm_dest("sbb", Src, yes(Dest), !IO).
> +output_x86_64_inst(set(Operand, Cond), !IO) :-
> +    check_operand_not_immediate(Operand, Result),
> +    (
>          Result = yes,
> -        io.write_string("\tret\t", !IO),
> -        io.write_int(NumBytes, !IO),
> -        io.write_string("\t", !IO)
> +        output_instr_with_condition("set", Operand, no, Cond, !IO)
>      ;
>          Result = no,
> -        unexpected(this_file, "output_x86_64_instr: ret unexpected")
> +        unexpected(this_file, "output_x86_64_instr: unexpected set 
> operand")
> +    ).
> +output_x86_64_inst(shld(Amnt, Dest1, Reg), !IO) :-
> +    check_operand_unsigned_imm_or_reg(Amnt, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_not_immediate(Dest1, Result2),
> +        (
> +            Result2 = yes,
> +            check_operand_register(Reg, Result3),
> +            (
> +                Result3 = yes,
> +                operand_type(Amnt, Op1),
> +                operand_type(Amnt, Op2),
> +                operand_type(Amnt, Op3),
> +                io.write_string("\tshld\t" ++ Op1 ++ ", ", !IO),
> +                io.write_string(Op2 ++ ", " ++ Op3 ++ "\t", !IO)
> +            ;
> +                Result3 = no,
> +                unexpected(this_file, "output_x86_64_instr: unexpected shld
> +                    third operand is not a register")
> +            )
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected shld
> +                second operand is an immediate value")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected shld
> +            first operand")
>      ).
> -output_x86_64_instr(rol(ClRegOrImm, RegOrMemRef), !IO) :-
> -    instr_with_crio_and_rmro("rol", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(ror(ClRegOrImm, RegOrMemRef), !IO) :-
> -    instr_with_crio_and_rmro("ror", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(sal(ClRegOrImm, RegOrMemRef), !IO) :-
> -    instr_with_crio_and_rmro("sal", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(shl(ClRegOrImm, RegOrMemRef), !IO) :-
> -    instr_with_crio_and_rmro("shl", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(sar(ClRegOrImm, RegOrMemRef), !IO) :-
> -    instr_with_crio_and_rmro("sar", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(sbb(Src, Dest), !IO) :-
> -    instr_with_op_and_rmro("sbb", Src, Dest, !IO).
> -output_x86_64_instr(seto(RegOrMemRef), !IO) :-
> -    instr_with_rmro("seto", RegOrMemRef, !IO).
> -output_x86_64_instr(setno(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setno", RegOrMemRef, !IO).
> -output_x86_64_instr(setb(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setb", RegOrMemRef, !IO).
> -output_x86_64_instr(setc(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setc", RegOrMemRef, !IO).
> -output_x86_64_instr(setnae(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setnae", RegOrMemRef, !IO).
> -output_x86_64_instr(setnb(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setnb", RegOrMemRef, !IO).
> -output_x86_64_instr(setnc(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setnc", RegOrMemRef, !IO).
> -output_x86_64_instr(setae(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setae", RegOrMemRef, !IO).
> -output_x86_64_instr(setz(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setz", RegOrMemRef, !IO).
> -output_x86_64_instr(sete(RegOrMemRef), !IO) :-
> -    instr_with_rmro("sete", RegOrMemRef, !IO).
> -output_x86_64_instr(setnz(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setnz", RegOrMemRef, !IO).
> -output_x86_64_instr(setne(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setne", RegOrMemRef, !IO).
> -output_x86_64_instr(setbe(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setbe", RegOrMemRef, !IO).
> -output_x86_64_instr(setna(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setna", RegOrMemRef, !IO).
> -output_x86_64_instr(setnbe(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setnbe", RegOrMemRef, !IO).
> -output_x86_64_instr(seta(RegOrMemRef), !IO) :-
> -    instr_with_rmro("seta", RegOrMemRef, !IO).
> -output_x86_64_instr(sets(RegOrMemRef), !IO) :-
> -    instr_with_rmro("sets", RegOrMemRef, !IO).
> -output_x86_64_instr(setns(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setns", RegOrMemRef, !IO).
> -output_x86_64_instr(setp(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setp", RegOrMemRef, !IO).
> -output_x86_64_instr(setpe(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setpe", RegOrMemRef, !IO).
> -output_x86_64_instr(setnp(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setnp", RegOrMemRef, !IO).
> -output_x86_64_instr(setpo(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setpo", RegOrMemRef, !IO).
> -output_x86_64_instr(setl(RegOrMemRef), !IO) :-
> -    instr_with_rmro("sel", RegOrMemRef, !IO).
> -output_x86_64_instr(setnge(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setnge", RegOrMemRef, !IO).
> -output_x86_64_instr(setnl(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setnl", RegOrMemRef, !IO).
> -output_x86_64_instr(setge(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setge", RegOrMemRef, !IO).
> -output_x86_64_instr(setle(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setle", RegOrMemRef, !IO).
> -output_x86_64_instr(setng(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setng", RegOrMemRef, !IO).
> -output_x86_64_instr(setnle(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setnle", RegOrMemRef, !IO).
> -output_x86_64_instr(setg(RegOrMemRef), !IO) :-
> -    instr_with_rmro("setg", RegOrMemRef, !IO).
> -output_x86_64_instr(shld(ClRegOrImm, RegOrMemRef, Reg), !IO) :-
> -    instr_with_crio_rmro_and_reg("shld", ClRegOrImm, RegOrMemRef, Reg, 
> !IO).
> -output_x86_64_instr(shr(ClRegOrImm, RegOrMemRef), !IO) :-
> -    instr_with_crio_and_rmro("shr", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(shrd(ClRegOrImm, RegOrMemRef, Reg), !IO) :-
> -    instr_with_crio_rmro_and_reg("shrd", ClRegOrImm, RegOrMemRef, Reg, 
> !IO).
> -output_x86_64_instr(stc, !IO) :-
> +output_x86_64_inst(shr(Amnt, Dest), !IO) :-
> +    check_operand_unsigned_imm_or_reg(Amnt, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_not_immediate(Dest, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Amnt, Op1),
> +            operand_type(Dest, Op2),
> +            io.write_string("\tshr\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected shr
> +               second operand is an immediate value")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected shr
> +            first operand")
> +    ).
> +output_x86_64_inst(shrd(Amnt, Dest1, Reg), !IO) :-
> +    check_operand_unsigned_imm_or_reg(Amnt, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_not_immediate(Dest1, Result2),
> +        (
> +            Result2 = yes,
> +            check_operand_register(Reg, Result3),
> +            (
> +                Result3 = yes,
> +                operand_type(Amnt, Op1),
> +                operand_type(Amnt, Op2),
> +                operand_type(Amnt, Op3),
> +                io.write_string("\tshrd\t" ++ Op1 ++ ", ", !IO),
> +                io.write_string(Op2 ++ ", " ++ Op3 ++ "\t", !IO)
> +            ;
> +                Result3 = no,
> +                unexpected(this_file, "output_x86_64_instr: unexpected shrd
> +                    third operand is not a register")
> +            )
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected shrd
> +                second operand is an immediate value")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected shrd
> +          first operand")
> +    ).
> +output_x86_64_inst(stc, !IO) :-
>      io.write_string("\tstc\t", !IO).
> -output_x86_64_instr(std, !IO) :-
> +output_x86_64_inst(std, !IO) :-
>      io.write_string("\tstd\t", !IO).
> -output_x86_64_instr(sub(Src, Dest), !IO) :-
> -    instr_with_op_and_rmro("sub", Src, Dest, !IO).
> -output_x86_64_instr(test(Src1, Src2), !IO) :-
> -    instr_with_rmro_and_rio("test", Src1, Src2, !IO).
> -output_x86_64_instr(xadd(Src, Dest), !IO) :-
> -    instr_with_reg_and_rmro("xadd", Src, Dest, !IO).
> -output_x86_64_instr(xchg(Src1, Src2), !IO) :-
> -    instr_with_rmro_and_rmro("xchg", Src1, Src2, !IO).
> -output_x86_64_instr(xor(Src, Dest), !IO) :-
> -    instr_with_op_and_rmro("xor", Src, Dest, !IO).
> +output_x86_64_inst(sub(Src, Dest), !IO) :-
> +    output_instr_not_imm_dest("sub", Src, yes(Dest), !IO).
> +output_x86_64_inst(test(Src1, Src2), !IO) :-
> +    check_operand_not_mem_ref(Src1, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_not_immediate(Src2, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Src1, Op1),
> +            operand_type(Src2, Op2),
> +            io.write_string("\ttest\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected
> +                test second operand is an immediate value")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected
> +            test first operand is a memory reference")
> +    ).
> +output_x86_64_inst(xadd(Src, Dest), !IO) :-
> +    check_operand_register(Src, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_not_immediate(Dest, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Src, Op1),
> +            operand_type(Dest, Op2),
> +            io.write_string("\txadd\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected
> +                xadd second operand is an immediate value")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected
> +            xadd first operand is not a register")
> +    ).
> +output_x86_64_inst(xchg(Src1, Src2), !IO) :-
> +    check_operand_reg_or_mem(Src1, Result1),
> +    (
> +        Result1 = yes,
> +        check_operand_reg_or_mem(Src2, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Src1, Op1),
> +            operand_type(Src2, Op2),
> +            io.write_string("\txchg\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_x86_64_instr: unexpected
> +                xchg second operand")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_x86_64_instr: unexpected
> +             xchg second operand")
> +    ).
> +output_x86_64_inst(xor(Src, Dest), !IO) :-
> +    output_instr_not_imm_dest("xor", Src, yes(Dest), !IO).
> 
> 
>  :- pred output_comment(string::in, io::di, io::uo) is det.
> @@ -947,30 +1044,14 @@
>  imm_op_type(imm32(int32(Val)), ImmVal) :-
>      ImmVal = "$" ++ string.int_to_string(Val).
> 
> -    % Output a string representation of a general-purpose register.
> -    %
> -:- pred reg_type(gp_reg::in, string::out) is det.
> 
> -reg_type(rax, "%rax").
> -reg_type(rbx, "%rbx").
> -reg_type(rcx, "%rcx").
> -reg_type(rdx, "%rdx").
> -reg_type(rbp, "%rbp").
> -reg_type(rsi, "%rsi").
> -reg_type(rdi, "%rdi").
> -reg_type(rsp, "%rsp").
> -reg_type(r8, "%r8").
> -reg_type(r9, "%r9").
> -reg_type(r10, "%r10").
> -reg_type(r11, "%r11").
> -reg_type(r12, "%r12").
> -reg_type(r13, "%r13").
> -reg_type(r14, "%r14").
> -reg_type(r15, "%r15").
> +:- func reg_type(gp_reg) = string.
> +
> +reg_type(gp_reg(RegNum)) = "%r" ++ string.int_to_string(RegNum).
> 
>      % Output a string representation of a memory reference.
>      %
> -:- pred mem_ref_type(mem_ref::in, string::out) is det.
> +:- pred mem_ref_type(x86_64_mem_ref::in, string::out) is det.
> 
>  mem_ref_type(mem_abs(DirectMemRef), MemRefVal) :-
>      base_address_type(DirectMemRef, MemRefVal).
> @@ -982,11 +1063,10 @@
>  :- pred base_address_type(base_address::in, string::out) is det.
> 
>  base_address_type(base_reg(Offset, Reg), BaseAddress) :-
> -    reg_type(Reg, RegType),
>      ( Offset = 0 ->
> -        BaseAddress = "(" ++ RegType ++ ")"
> +        BaseAddress = "(" ++ reg_type(Reg) ++ ")"
>      ;
> -        BaseAddress = string.int_to_string(Offset) ++ "(" ++ RegType ++ ")"
> +        BaseAddress = string.int_to_string(Offset) ++ "(" ++ reg_type(Reg) 
> ++ ")"
>      ).
>  base_address_type(base_expr(Expr), DispType) :-
>      DispType = "$" ++ Expr.
> @@ -1051,249 +1131,303 @@
>          unexpected(this_file, "rel_offset_type: ro32 unexpected")
>      ).
> 
> -    % Output a string representation of a general operand type.
> -    %
> -:- pred operand_type(operand::in, string::out) is det.
> 
>  operand_type(operand_reg(Reg), RegType) :-
> -    reg_type(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).
> -
> -    % Output a string representation of an operand whose type is a 
> register/
> -    % memory reference.
> -    %
> -:- pred rmro_type(reg_or_mem_ref_op::in, string::out) is det.
> -
> -rmro_type(rmro_reg(Reg), RegType) :-
> -    reg_type(Reg, RegType).
> -rmro_type(rmro_mem_ref(MemRef), MemRefVal) :-
> -    mem_ref_type(MemRef, MemRefVal).
> -
> -    % Output a string representation of an operand whose type is a register
> -    % or an immediate value.
> -    %
> -:- pred rio_type(reg_or_imm_op::in, string::out) is det.
> -
> -rio_type(rio_reg(Reg), RegType) :-
> -    reg_type(Reg, RegType).
> -rio_type(rio_imm(Imm), ImmVal) :-
> -    imm_op_type(Imm, ImmVal).
> -
> -    % Output a string representation of an operand whose type is a cl 
> register
> -    % or an unsigned immediate value.
> -    %
> -:- pred crio_type(cl_reg_or_imm_op::in, string::out) is det.
> -
> -crio_type(crio_reg_cl(Reg), RegType) :-
> -    ( Reg = rcx ->
> -        RegType = "%cl"
> -    ;
> -        unexpected(this_file, "crio_type: crio_reg_cl unexpected")
> -    ).
> -crio_type(crio_imm8(int8(Val)), ImmVal) :-
> -    check_unsigned_int_size(8, Val, Result),
> -    (
> -        Result = yes,
> -        ImmVal = "$" ++ string.int_to_string(Val)
> -    ;
> -        Result = no,
> -        unexpected(this_file, "crio_type: crio_imm8 unexpected")
> -    ).
> -
> -    % Output a string representation of an operand whose type is either
> -    % a register, memory reference, signed relative offset or a label.
> -    %
> -:- pred rmrol_type(rmrol::in, string::out) is det.
> -
> -rmrol_type(rmrol_reg(Reg), RegType) :-
> -    reg_type(Reg, RegType).
> -rmrol_type(rmrol_mem_ref(MemRef), MemRefVal) :-
> -    mem_ref_type(MemRef, MemRefVal).
> -rmrol_type(rmrol_rel_offset(RelOffset), RelOffsetVal) :-
> -    rel_offset_type(RelOffset, RelOffsetVal).
> -rmrol_type(rmrol_label(LabelName), LabelOut) :-
> -    LabelOut = LabelName.
> +operand_type(operand_rel_offset(RelOffset), RelOffsetType) :-
> +    rel_offset_type(RelOffset, RelOffsetType).
> +operand_type(operand_label(Label), (Label)).
> 
> 
> %-----------------------------------------------------------------------------%
>  %
>  % Subsection of "Output of x86_64 instructions".
>  %
> 
> -    % Output an instruction with a register/memory reference as an operand.
> +    % Output an instruction with either one or two operand(s). If the 
> second
> +    % operand is present, it cannot be an immediate operand.
>      %
> -:- pred instr_with_rmro(string::in, reg_or_mem_ref_op::in,
> +:- pred output_instr_not_imm_dest(string::in, operand::in, 
> maybe(operand)::in,
>      io::di, io::uo) is det.
> 
> -instr_with_rmro(InstrName, RegOrMemRef, !IO) :-
> -    io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -    rmro_type(RegOrMemRef, RegOrMemRefType),
> -    io.write_string(RegOrMemRefType ++ "\t\t", !IO).
> +output_instr_not_imm_dest(Instr, Op1, Op2, !IO) :-
> +    operand_type(Op1, Op1Type),
> +    (
> +        Op2 = yes(Op2Result),
> +        check_not_both_memory_ops(Op1, Op2Result, Result1),
> +        (
> +            Result1 = yes,
> +            operand_type(Op2Result, Op2Type),
> +            check_operand_not_immediate(Op2Result, Result2),
> +            (
> +                Result2 = yes,
> +                io.write_string("\t" ++ Instr ++ "\t", !IO),
> +                io.write_string(Op1Type ++ ", " ++ Op2Type ++ "\t", !IO)
> +            ;
> +                Result2 = no,
> +                io.write_string("\tmov\t" ++ Op2Type ++ ", %r13\t", !IO),
> +                io.write_string("# move immediate to temp reg\n", !IO),
> +                io.write_string("\t" ++ Instr ++ "\t", !IO),
> +                io.write_string(Op1Type ++ ", " ++ "%r13\t", !IO)
> +            )
> +        ;
> +            Result1 = no,
> +            unexpected(this_file, "output_instr_not_imm_dest: unexpected: 
> both
> +                operands are memory references")
> +        )
> +    ;
> +        Op2 = no,
> +        io.write_string(Op1Type ++ "\t\t", !IO)
> +    ).
> 
>      % Output an instruction with a signed offset relative to the 
>      instruction
>      % pointer as an operand.
> -    %
> -:- pred instr_with_rel_offset_op(string::in, rel_offset::in,
> -    io::di, io::uo) is det.
> -
> -instr_with_rel_offset_op(InstrName, RelOffset, !IO) :-
> -    io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -    rel_offset_type(RelOffset, RelOffsetType),
> -    io.write_string(RelOffsetType ++ "\t\t", !IO).
> -
>      % Output an instruction with a signed 8-bit offset relative to the
>      % instruction pointer as an operand.
>      %
> -:- pred instr_with_8bit_rel_offset_op(string::in, rel_offset::in,
> +:- pred output_instr_8bit_rel_offset(string::in, operand::in,
>      io::di, io::uo) is det.
> 
> -instr_with_8bit_rel_offset_op(InstrName, RelOffset, !IO) :-
> +output_instr_8bit_rel_offset(InstrName, RelOffset, !IO) :-
> +   check_operand_rel_offset(RelOffset, Result1),
>     (
> -        RelOffset = ro8(int8(Val)),
> -        check_signed_int_size(8, Val, Result),
> -        Result = yes
> -   ->
> -        io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -        io.write_int(Val, !IO),
> -        io.write_string("\t\t", !IO)
> +        Result1 = yes,
> +        operand_type(RelOffset, RelOffsetType),
> +        ( string.to_int(RelOffsetType, Val) ->
> +            check_signed_int_size(8, Val, Result2),
> +            (
> +                Result2 = yes,
> +                io.write_string("\t" ++ InstrName ++ "\t", !IO),
> +                io.write_int(Val, !IO),
> +                io.write_string("\t\t", !IO)
> +            ;
> +                Result2 = no,
> +                unexpected(this_file, "output_instr_8bit_rel_offset:
> +                    unexpected relative offset operand")
> +            )
> +        ;
> +            unexpected(this_file, "output_instr_8bit_rel_offset: 
> unexpected:
> +                string.to_int")
> +        )
>     ;
> -        unexpected(this_file, "instr_with_8bit_rel_offset_op: unexpected")
> +        Result1 = no,
> +        unexpected(this_file, "output_instr_8bit_rel_offset: unexpected:
> +            operand not a relative offset")
>     ).
> 
> -    % Output an instruction with either a register, memory reference,
> -    % relative offset or a label as its operand.
> -    %
> -:- pred instr_with_rmrol(string::in, rmrol::in, io::di, io::uo) is det.
> +:- pred output_bit_test_instr(string::in, operand::in, operand::in, io::di,
> +    io::uo) is det.
> +
> +output_bit_test_instr(Instr, Src, Idx, !IO) :-
> +    check_operand_not_immediate(Src, Result1),
> +    (
> +        Result1 = yes,
> +        operand_type(Src, Op1),
> +        check_operand_not_mem_ref(Idx, Result2),
> +        (
> +            Result2 = yes,
> +            operand_type(Idx, Op2),
> +            ( string.to_int(Op2, IdxInt) ->
> +                check_signed_int_size(8, IdxInt, Result3),
> +                (
> +                    Result3 = yes,
> +                    io.write_string("\t" ++ Instr ++ "\t", !IO),
> +                    io.write_string(Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> +                ;
> +                    Result3 = no,
> +                    unexpected(this_file, "output_bit_test_instr: 
> unexpected:
> +                        bt second operand not 8-bit immediate value")
> +                )
> +            ;
> +                unexpected(this_file, "output_bit_test_instr: string.to_int
> +                    unexpected")
> +            )
> +        ;
> +            Result2 = no,
> +            unexpected(this_file, "output_bit_test_instr: unexpected:
> +                bt second operand is a memory reference")
> +        )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_bit_test_instr: unexpected: bt first
> +            operand is an immediate value")
> +    ).
> 
> -instr_with_rmrol(InstrName, Target, !IO) :-
> -    io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -    rmrol_type(Target, TargetType),
> -    io.write_string(TargetType ++ "\t\t", !IO).
> +:- pred output_instr_with_condition(string::in, operand::in, 
> maybe(operand)::in,
> +    string::in, io::di, io::uo) is det.
> 
> -    % Output an instruction with a general operand and a register/memory
> -    % reference as the first and second operand respectively.
> -    %
> -:- pred instr_with_op_and_rmro(string::in, operand::in, 
> reg_or_mem_ref_op::in,
> -    io::di, io::uo) is det.
> +output_instr_with_condition(Instr, Op1, Op2, Cond, !IO) :-
> +    check_operand_not_immediate(Op1, Result1),
> +    (
> +        Result1 = yes,
> +        check_instr_condition(Cond, Result2),
> +        (
> +            Result2 = yes,
> +            io.write_string("\t" ++ Instr, !IO),
> +            io.write_string(string.to_lower(Cond) ++ "\t", !IO),
> +            operand_type(Op1, Op1Type),
> +            io.write_string(Op1Type, !IO),
> +            (
> +                Op2 = yes(Op2Res),
> +                check_operand_register(Op2Res, Result3),
> +                (
> +                    Result3 = yes,
> +                    operand_type(Op2Res, Op2Type),
> +                    io.write_string(", " ++ Op2Type, !IO)
> +                ;
> +                    Result3 = no,
> +                        unexpected(this_file, "output_instr_with_condition:
> +                            second operand is not a register")
> +                )
> +           ;
> +                Op2 = no,
> +                io.write_string("\t\t", !IO)
> +           )
> +       ;
> +            Result2 = no,
> +            unexpected(this_file, "output_instr_with_condition:
> +                condition not satisfied")
> +       )
> +    ;
> +        Result1 = no,
> +        unexpected(this_file, "output_instr_with_condition:
> +            unexpected: first operand is an immediate value")
> +   ).
> 
> -instr_with_op_and_rmro(InstrName, SrcOperand, DestRegOrMemRefOp, !IO) :-
> -    (
> -        SrcOperand = operand_mem_ref(_),
> -        DestRegOrMemRefOp = rmro_mem_ref(_)
> +%-----------------------------------------------------------------------------%
> +
> +:- pred check_rc_first_operand(operand::in, bool::out) is det.
> +
> +check_rc_first_operand(Op, Result) :-
> +    ( Op = operand_imm(_) ->
> +        operand_type(Op, OpType),
> +        ( string.to_int(OpType, OpInt) ->
> +            check_unsigned_int_size(8, OpInt, Result1),
> +            (
> +                Result1 = yes,
> +                Result = yes
> +            ;
> +                Result1 = no,
> +                Result = no
> +            )
> +        ;
> +            unexpected(this_file, "check_rc_first_operand: string.to_int
> +                unexpected")
> +        )
> +    ;
> +        Op = operand_reg(_) ->
> +        check_operand_register(Op, Result2),
> +        (
> +            Result2 = yes,
> +            Result = yes
> +       ;
> +            Result2 = no,
> +            Result = no
> +        )
> +    ;
> +        unexpected(this_file, "check_rc_first_operand: unexpected")
> +    ).
> +
> +:- pred check_not_both_memory_ops(operand::in, operand::in, bool::out) is 
> det.
> +
> +check_not_both_memory_ops(Op1, Op2, Result) :-
> +    (
> +        Op1 = operand_mem_ref(_),
> +        Op2 = operand_mem_ref(_)
>      ->
> -        % Both operands cannot be of type memory reference.
> -        unexpected(this_file, "instr_with_op_and_rmro: unexpected")
> +        Result = no
>      ;
> -        io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -        operand_type(SrcOperand, OperandType),
> -        io.write_string(OperandType ++ ", ", !IO),
> -        rmro_type(DestRegOrMemRefOp, DestType),
> -        io.write_string(DestType ++ "\t", !IO)
> +        Result = yes
>      ).
> 
> -    % Output an instruction with a register/memory reference and a 
> register as
> -    % the first and second operand respectively.
> -    %
> -:- pred instr_with_rmro_and_reg(string::in, reg_or_mem_ref_op::in, 
> gp_reg::in,
> -    io::di, io::uo) is det.
> +:- pred check_operand_not_immediate(operand::in, bool::out) is det.
> 
> -instr_with_rmro_and_reg(InstrName, SrcRegOrMemRefOp, DestReg, !IO) :-
> -    io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -    rmro_type(SrcRegOrMemRefOp, SrcType),
> -    io.write_string(SrcType ++ ", ", !IO),
> -    reg_type(DestReg, RegType),
> -    io.write_string(RegType ++ "\t", !IO).
> +check_operand_not_immediate(Operand, Result) :-
> +    ( Operand = operand_imm(_) ->
> +        Result = no
> +    ;
> +        Result = yes
> +    ).
> 
> -    % Output an instruction with a register/memory reference and a 
> register/
> -    % immediate value as the first and second operand respectively.
> -    %
> -:- pred instr_with_rmro_and_rio(string::in, reg_or_mem_ref_op::in,
> -    reg_or_imm_op::in, io::di, io::uo) is det.
> +:- pred check_operand_reg_or_mem(operand::in, bool::out) is det.
> 
> -instr_with_rmro_and_rio(InstrName, SrcRegOrMemRefOp, DestRegOrImmOp, !IO) 
> :-
> -    io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -    rmro_type(SrcRegOrMemRefOp, SrcType),
> -    io.write_string(SrcType ++ ",", !IO),
> -    rio_type(DestRegOrImmOp, DestType),
> -    io.write_string(DestType ++ "\t", !IO).
> +check_operand_reg_or_mem(Operand, Result) :-
> +    ( Operand = operand_reg(_) ->
> +        Result = yes
> +    ;
> +        Operand = operand_mem_ref(_) ->
> +        Result = yes
> +    ;
> +        Result = no
> +    ).
> 
> -    % Output an instruction with a register/memory reference as the first 
> and
> -    % second operand respectively.
> -    %
> -:- pred instr_with_rmro_and_rmro(string::in, reg_or_mem_ref_op::in,
> -    reg_or_mem_ref_op::in, io::di, io::uo) is det.
> +:- pred check_operand_unsigned_imm_or_reg(operand::in, bool::out) is det.
> 
> -instr_with_rmro_and_rmro(InstrName, RegOrMemRefOp0, RegOrMemRefOp1, !IO) 
> :-
> -    (
> -        RegOrMemRefOp0 = rmro_mem_ref(_),
> -        RegOrMemRefOp1 = rmro_mem_ref(_)
> -    ->
> -        unexpected(this_file, "instr_with_rmro_and_rmro: unexpected")
> +check_operand_unsigned_imm_or_reg(Operand, Result) :-
> +    ( Operand = operand_imm(Imm) ->
> +        imm_op_type(Imm, ImmType),
> +        ( string.to_int(ImmType, ImmInt) ->
> +            (
> +                check_unsigned_int_size(32, ImmInt, Result1),
> +                (
> +                    Result1 = yes,
> +                    Result = yes
> +                ;
> +                    Result1 = no,
> +                    Result = no
> +                )
> +            )
> +        ;
> +            unexpected(this_file, "check_operand_unsigned_imm_or_reg:
> +                unexpected")
> +        )
>      ;
> -        io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -        rmro_type(RegOrMemRefOp0, Type0),
> -        io.write_string(Type0 ++ ", ", !IO),
> -        rmro_type(RegOrMemRefOp1, Type1),
> -        io.write_string(Type1 ++ "\t", !IO)
> +        Result = no
>      ).
> 
> -    % Output an instruction with a register and a register/memory 
> reference as
> -    % the first and second operand respectively.
> -    %
> -:- pred instr_with_reg_and_rmro(string::in, gp_reg::in, 
> reg_or_mem_ref_op::in,
> -    io::di, io::uo) is det.
> +:- pred check_operand_register(operand::in, bool::out) is det.
> 
> -instr_with_reg_and_rmro(InstrName, SrcReg, DestRegOrMemRefOp, !IO) :-
> -    io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -    reg_type(SrcReg, RegType),
> -    io.write_string(RegType ++ ", ", !IO),
> -    rmro_type(DestRegOrMemRefOp, DestType),
> -    io.write_string(DestType ++ "\t", !IO).
> +check_operand_register(Operand, Result) :-
> +    ( Operand = operand_reg(_) ->
> +        Result = yes
> +    ;
> +        Result =  no
> +    ).
> 
> -    % Output an instruction with a cl register/immediate value and a 
> register/
> -    % memory reference as the first and second operand respectively.
> -    %
> -:- pred instr_with_crio_and_rmro(string::in, cl_reg_or_imm_op::in,
> -    reg_or_mem_ref_op::in, io::di, io::uo) is det.
> +:- pred check_operand_not_mem_ref(operand::in, bool::out) is det.
> 
> -instr_with_crio_and_rmro(InstrName, ClRegOrImm, RegOrMemRef, !IO) :-
> -    io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -    crio_type(ClRegOrImm, ClRegOrImmType),
> -    io.write_string(ClRegOrImmType ++ ", ", !IO),
> -    rmro_type(RegOrMemRef, RegOrMemRefType),
> -    io.write_string(RegOrMemRefType ++ "\t", !IO).
> -
> -    % Output an instruction with a cl register/immediate value, a register/
> -    % memory reference and a register as the first, second and third 
> operand
> -    % respectively.
> -    %
> -:- pred instr_with_crio_rmro_and_reg(string::in, cl_reg_or_imm_op::in,
> -    reg_or_mem_ref_op::in, gp_reg::in, io::di, io::uo) is det.
> +check_operand_not_mem_ref(Operand, Result) :-
> +    ( Operand = operand_mem_ref(_) ->
> +        Result = no
> +    ;
> +        Result = yes
> +    ).
> 
> -instr_with_crio_rmro_and_reg(InstrName, ClRegOrImm, RegOrMemRef, Reg, !IO) 
> :-
> -    io.write_string("\t" ++ InstrName ++ "\t", !IO),
> -    crio_type(ClRegOrImm, ClRegOrImmType),
> -    io.write_string(ClRegOrImmType ++ "\t", !IO),
> -    rmro_type(RegOrMemRef, RegOrMemRefType),
> -    io.write_string(RegOrMemRefType ++ ", ", !IO),
> -    reg_type(Reg, RegType),
> -    io.write_string(RegType ++ "\t", !IO).
> +:- pred check_operand_rel_offset(operand::in, bool::out) is det.
> 
> -    % Output an instruction with a memory reference and a register as the 
> first
> -    % and second operand respectively.
> -    %
> -:- pred instr_with_mem_ref_and_reg_op(string::in, mem_ref::in,
> -    gp_reg::in, io::di, io::uo) is det.
> +check_operand_rel_offset(Operand, Result) :-
> +    ( Operand = operand_rel_offset(_) ->
> +        Result = yes
> +    ;
> +        Result = no
> +    ).
> 
> -instr_with_mem_ref_and_reg_op(InstrName, SrcMemRef, DestReg, !IO) :-
> -    mem_ref_type(SrcMemRef, MemRefType),
> -    io.write_string("\t" ++ InstrName ++ "\t" ++ MemRefType, !IO),
> -    reg_type(DestReg, DestRegType),
> -    io.write_string(", " ++ DestRegType ++ "\t", !IO).
> +    % Check if the argument for a conditional instruction is valid.
> +    %
> +:- pred check_instr_condition(string::in, bool::out) is det.
> 
> -%-----------------------------------------------------------------------------%
> +check_instr_condition(Condition, Result) :-
> +    List = ["O", "NO", "B", "C", "NAE", "NB", "NC", "AE", "Z", "E", "NZ",
> +            "NE", "BE", "NA", "NBE", "A", "S", "NS", "P", "PE", "NP", "PO",
> +            "L", "NGE", "NL", "GE", "LE", "NG", "NLE", "G"],
> +    (  list.member(string.to_upper(Condition), List) ->
> +        Result = yes
> +    ;
> +        Result = no
> +    ).
> 
>      % Check whether an unsigned int (Val) with n bits (BitSize) is within 
>      the
>      % range of 0 and (2^n)-1.
> 
> --------------------------------------------------------------------------
> 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
> --------------------------------------------------------------------------
--------------------------------------------------------------------------
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