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

Fransiska Nathania HANDOKO fhandoko at students.csse.unimelb.edu.au
Mon Feb 5 10:24:45 AEDT 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)).
+
+%----------------------------------------------------------------------------%
+%
+% 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.
+    %
+:- 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,
+
+    %
+    % 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")
+            )
+        ;
+            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)
+                ;
+                    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")
+                        )
+                    ;
+                        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>>")]).
+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).
+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.
+
+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),
+    (
+       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"
+            )
+            % 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).
+
+:- 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),
+            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
+            ;
+                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")
+    ).
+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
--------------------------------------------------------------------------



More information about the reviews mailing list