[m-rev.] for review: llds->x86_64 asm generator modules
Ralph Becket
rafe at csse.unimelb.edu.au
Mon Feb 5 11:18:51 AEDT 2007
This looks pretty good. I have made a few comments below and you should
probably wait for a second review by Julien or Zoltan before committing.
-- Ralph
Fransiska Handoko, Monday, 5 February 2007:
>
> Estimated hours taken: 60
> Branches: main
>
> Updates the representation of several x86_64 instruction sets to make the
> llds->x86_64 generation simpler. Also adds the llds->x86_64 asm generator
> modules. There are still placeholders in several places in the modules.
> The modules are not working version yet.
>
> compiler/ll_backend.m:
> Includes new llds->x86_64 modules.
>
> compiler/llds_to_x86_64.m:
> The llds->x86_64 asm generator module.
>
> compiler/llds_to_x86_64_out.m:
> Outputs instructions produced by llds->x86_64 asm generator.
>
> compiler/mercury_compile.m:
> Imports llds->x86_64 modules.
> Calls predicates from llds->x86_64 asm generator module.
>
> compiler/x86_64_instrs.m:
> Fixes some x86_64 operands and instructions.
>
> compiler/x86_64_out.m:
> Fixes some predicates to print out x86_64 instructions.
>
>
> index: compiler/ll_backend.m
> ===================================================================
> rCS file:
> /home/mercury/mercury1/repository/mercury/compiler/ll_backend.m,v
> retrieving revision 1.18
> diff -u -r1.18 ll_backend.m
> --- compiler/ll_backend.m 15 Jan 2007 22:49:41 -0000 1.18
> +++ compiler/ll_backend.m 29 Jan 2007 00:45:30 -0000
> @@ -93,6 +93,8 @@
> :- include_module rtti_out.
>
> % The LLDS->x86_64 asm phase.
> +:- include_module llds_to_x86_64.
> +:- include_module llds_to_x86_64_out.
> :- include_module x86_64_instrs.
> :- include_module x86_64_out.
>
> Index: compiler/llds_to_x86_64.m
> ===================================================================
> RCS file: compiler/llds_to_x86_64.m
> diff -N compiler/llds_to_x86_64.m
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ compiler/llds_to_x86_64.m 2 Feb 2007 05:29:01 -0000
> @@ -0,0 +1,895 @@
> :- include_module rtti_out.
>
> % The LLDS->x86_64 asm phase.
> +:- include_module llds_to_x86_64.
> +:- include_module llds_to_x86_64_out.
> :- include_module x86_64_instrs.
> :- include_module x86_64_out.
>
> Index: compiler/llds_to_x86_64.m
> ===================================================================
> RCS file: compiler/llds_to_x86_64.m
> diff -N compiler/llds_to_x86_64.m
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ compiler/llds_to_x86_64.m 2 Feb 2007 05:29:01 -0000
> @@ -0,0 +1,895 @@
> +%-----------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%-----------------------------------------------------------------------------%
> +% Copyright (C) 2007 The University of Melbourne.
> +% This file may only be copied under the terms of the GNU General
> +% Public License - see the file COPYING in the Mercury distribution.
> +%-----------------------------------------------------------------------------%
> +%
> +% File: llds_to_x86_64.m.
> +% Main author: fhandoko.
> +%
> +% This module implements the LLDS->x86_64 asm code generator.
> +%
> +%-----------------------------------------------------------------------------%
> +
> +:- module ll_backend.llds_to_x86_64.
> +:- interface.
> +
> +:- import_module hlds.hlds_module.
> +:- import_module ll_backend.llds.
> +:- import_module ll_backend.x86_64_instrs.
> +
> +:- import_module list.
> +
> +%----------------------------------------------------------------------------%
> +
> +:- pred llds_to_x86_64_asm(module_info::in, list(c_procedure)::in,
> + list(x86_64_procedure)::out) is det.
> +
> +%----------------------------------------------------------------------------%
> +%----------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module backend_libs.builtin_ops.
> +:- import_module backend_libs.name_mangle.
> +:- import_module libs.compiler_util.
> +:- import_module ll_backend.llds_out.
> +:- import_module ll_backend.x86_64_out.
> +:- import_module mdbcomp.prim_data.
> +
> +:- import_module bool.
> +:- import_module int.
> +:- import_module io.
> +:- import_module maybe.
> +:- import_module set.
> +:- import_module string.
> +
> +%-----------------------------------------------------------------------------%
> +%
> +% binary operation type.
> +%
> +
> + % A binary operation can consist of two simple operands, one operand
> + % and one expression or two expressions.
> + %
> +:- type binop
> + ---> binop_two_ops(operand, operand)
> + ; binop_op_and_instr(operand, list(x86_64_instr))
> + ; binop_instr_and_op(list(x86_64_instr), operand)
> + ; binop_two_instrs(list(x86_64_instr), list(x86_64_instr)).
I don't understand from the comment what the data constructors mean.
Can you give a separate comment for each constructor?
Why are the instruction fields lists?
The word `op' is usually read as an abbreviation for `operator' rather
than `operand'. Instead of `op', use something like `opand' or even
`arg' (for `argument').
> +%----------------------------------------------------------------------------%
> +%
> +% llds to x86_64.
> +%
> +
> +llds_to_x86_64_asm(_, CProcs, AsmProcs) :-
> + transform_c_proc_list(CProcs, AsmProcs).
> +
> + % Transform a list of c procedure into a list of x86_64 procedure.
s/procedure/procedures/g
> + %
> +:- pred transform_c_proc_list(list(c_procedure)::in,
> + list(x86_64_procedure)::out) is det.
> +
> +transform_c_proc_list([], []).
> +transform_c_proc_list([CProc | CProcs], [AsmProc | AsmProcs]) :-
> + AsmProc0 = ll_backend.x86_64_instrs.init_x86_64_proc(CProc),
> + ProcInstr0 = ll_backend.x86_64_instrs.init_x86_64_instruction,
> +
Delete this blank line.
> + %
> + % Get the procedure's label and append it as an x86_64 instruction
> + % list before the output of the llds->x86_64 procedure transformation.
> + %
> + ProcStr = backend_libs.name_mangle.proc_label_to_c_string(
> + AsmProc0 ^ x86_64_proc_label, no),
> + ProcName = directive(x86_64_pseudo_type(ProcStr, "@function")),
> + ProcInstr = ProcInstr0 ^ x86_64_inst := [ProcName],
> + transform_c_instr_list(CProc ^ cproc_code, AsmInstr0),
> + list.append([ProcInstr], AsmInstr0, AsmInstr),
> + AsmProc = AsmProc0 ^ x86_64_code := AsmInstr,
> + transform_c_proc_list(CProcs, AsmProcs).
> +
> + % Transform a list of c instruction into a list of x86_64 instruction.
> + %
> +:- pred transform_c_instr_list(list(instruction)::in,
> + list(x86_64_instruction)::out) is det.
> +
> +transform_c_instr_list([], []).
> +transform_c_instr_list([CInstr0 | CInstr0s], [AsmInstr | AsmInstrs]) :-
> + CInstr0 = llds_instr(CInstr1, Comment),
> + instr_to_x86_64(CInstr1, AsmInstrList),
> + AsmInstr0 = ll_backend.x86_64_instrs.init_x86_64_instruction,
> + AsmInstr1 = AsmInstr0 ^ x86_64_inst := AsmInstrList,
> + AsmInstr = AsmInstr1 ^ x86_64_comment := Comment,
> + transform_c_instr_list(CInstr0s, AsmInstrs).
> +
> + % Transform a block instruction of an llds instruction into a list of
> + % x86_64 instruction.
> + %
> +:- pred transform_block_instr(list(instruction)::in,
> list(x86_64_instr)::out)
> + is det.
> +
> +transform_block_instr(CInstrs, Instrs) :-
> + transform_block_instr_list(CInstrs, ListInstrs),
> + list.condense(ListInstrs, Instrs).
> +
> +:- pred transform_block_instr_list(list(instruction)::in,
> + list(list(x86_64_instr))::out) is det.
> +
> +transform_block_instr_list([], []).
> +transform_block_instr_list([CInstr0 | CInstr0s], [Instr0 | Instr0s]) :-
> + CInstr0 = llds_instr(CInstr, _),
> + instr_to_x86_64(CInstr, Instr0),
> + transform_block_instr_list(CInstr0s, Instr0s).
> +
> + % Transform livevals of llds instruction into a list of x86_64
> instruction.
> + %
> +:- pred transform_livevals(list(lval)::in, list(x86_64_instr)::out) is det.
> +
> +transform_livevals([], []).
> +transform_livevals([Lval | Lvals], [Instr | Instrs]) :-
> + transform_lval(Lval, Res0, Res1),
> + (
> + Res0 = yes(LvalOp),
> + Instr = instr(mov(operand_label("<<livevals>>"), LvalOp)),
> + transform_livevals(Lvals, Instrs)
> + ;
> + Res0 = no,
> + (
> + Res1 = yes(LvalInstrs),
> + ( get_last_instr_op(LvalInstrs, LastOp) ->
> + Instr = instr(mov(operand_label("<<livevals>>"), LastOp)),
> + transform_livevals(Lvals, Instrs)
> + ;
> + unexpected(this_file, "transform_livevals: unexpected")
unexpected(ModuleName, Message) throws an error of the form
ModuleName ++ ": Unexpected: " ++ Message, so your Message should not
also say `unexpected', but rather give a hint as to what happened. This
pattern occurs elsewhere in this module, too.
> + )
> + ;
> + Res1 = no,
> + unexpected(this_file, "transform_livevals: unexpected")
> + )
> + ).
> +
> + % Given an llds instruction, transform it into equivalent x86_64
> + % instruction.
> + %
> +:- pred instr_to_x86_64(instr::in, list(x86_64_instr)::out) is det.
> +
> +instr_to_x86_64(comment(Comment), [comment(Comment)]).
> +instr_to_x86_64(livevals(RegsAndStackLocs), Instrs) :-
> + set.to_sorted_list(RegsAndStackLocs, List),
> + transform_livevals(List, Instrs).
> +instr_to_x86_64(block(_, _, CInstrs), Instrs) :-
> + transform_block_instr(CInstrs, Instrs).
> +instr_to_x86_64(assign(Lval, Rval), Instrs) :-
> + transform_lval(Lval, Res0, Res1),
> + transform_rval(Rval, Res2, Res3),
> + (
> + Res0 = yes(LvalOp),
> + (
> + Res2 = yes(RvalOp),
> + Instrs = [instr(mov(RvalOp, LvalOp))]
> + ;
> + Res2 = no,
> + (
> + Res3 = yes(RvalInstrs),
> + ( get_last_instr_op(RvalInstrs, LastOp) ->
> + LastInstr = instr(mov(LastOp, LvalOp)),
> + list.append(RvalInstrs, [LastInstr], Instrs)
Isn't appending going to make this O(n^2) in the number of instructions?
Or is that not an issue here?
> + ;
> + unexpected(this_file, "instr_to_x86_64: assign
> unexpected")
> + )
> + ;
> + Res3 = no,
> + unexpected(this_file, "instr_to_x86_64: assign Rval
> unexpected")
> + )
> + )
> + ;
> + Res0 = no,
> + (
> + Res1 = yes(LvalInstrs),
> + ( get_last_instr_op(LvalInstrs, LvalLastOp) ->
> + (
> + Res2 = yes(RvalOp),
> + Instr0 = instr(mov(RvalOp, LvalLastOp)),
> + list.append(LvalInstrs, [Instr0], Instrs)
> +
> + ;
> + Res2 = no,
> + (
> + Res3 = yes(RvalInstrs),
> + ( get_last_instr_op(RvalInstrs, RvalLastOp) ->
> + Instr0 = instr(mov(RvalLastOp, LvalLastOp)),
> + list.append(LvalInstrs, [Instr0], Instrs1),
> + list.append(RvalInstrs, Instrs1, Instrs)
> + ;
> + unexpected(this_file, "instr_to_x86_64: assign
> + unexpected")
Breaking strings like this will include the unwanted newline and
whitespace. You should break up string constants using ++ from string.m
(the compiler will optimise the ++ away):
unexpected(this_file, "instr_to_x86_64: " ++
"assign unexpected")
> + )
> + ;
> + Res3 = no,
> + unexpected(this_file, "instr_to_x86_64: assign Rval
> + unexpected")
> + )
> + )
> + ;
> + unexpected(this_file, "instr_to_x86_64: assign unexpected")
> + )
> + ;
> + Res1 = no,
> + unexpected(this_file, "instr_to_x86_64: assign Lval
> unexpected")
> + )
> + ).
> +instr_to_x86_64(llcall(Target0, Continuation0, _, _, _, _), Instrs) :-
> + code_addr_type(Target0, Target1),
> + code_addr_type(Continuation0, Continuation1),
> + Instr1 = instr(mov(operand_label(Continuation1),
> + operand_label("<<succip>>"))),
> + Instr2 = instr(jmp(operand_label(Target1))),
> + Instrs = [Instr1, Instr2].
> +instr_to_x86_64(mkframe(_, _), [comment("<<mkframe>>")]).
> +instr_to_x86_64(label(Label), Instrs) :-
> + LabelStr = ll_backend.llds_out.label_to_c_string(Label, no),
> + Instrs = [label(LabelStr)].
> +instr_to_x86_64(goto(CodeAddr), Instrs) :-
> + code_addr_type(CodeAddr, Label),
> + Instrs = [instr(jmp(operand_label(Label)))].
> +instr_to_x86_64(computed_goto(Rval, Labels), Instrs) :-
> + transform_rval(Rval, Res0, Res1),
> + (
> + Res0 = yes(RvalOp),
> + RvalInstrs = []
> + ;
> + Res0 = no,
> + (
> + Res1 = yes(RvalInstrs),
> + ( get_last_instr_op(RvalInstrs, RvalOp0) ->
> + RvalOp = RvalOp0
> + ;
> + unexpected(this_file, "instr_to_x86_64: computed_goto
> + unexpected")
> + )
> + ;
> + Res1 = no,
> + unexpected(this_file, "instr_to_x86_64: computed_goto
> unexpected")
> + )
> + ),
> + labels_to_string(Labels, "", LabelStr),
> + TempReg = operand_reg(gp_reg(13)),
> + Instr0 = instr(mov(operand_mem_ref(mem_abs(base_expr(LabelStr))),
> TempReg)),
> + Instr1 = instr(add(RvalOp, TempReg)),
> + Instr2 = instr(jmp(TempReg)),
> + list.append(RvalInstrs, [Instr0], Instr3),
> + list.append(Instr3, [Instr1], Instr4),
> + list.append(Instr4, [Instr2], Instrs).
> +instr_to_x86_64(arbitrary_c_code(_, _, _),
> [comment("<<arbitrary_c_code>>")]).
Indent the overrunning head line by two tabs.
> +instr_to_x86_64(if_val(Rval, CodeAddr), Instrs) :-
> + code_addr_type(CodeAddr, Target),
> + transform_rval(Rval, Res0, Res1),
> + (
> + Res0 = yes(RvalOp)
> + ;
> + Res0 = no,
> + (
> + Res1 = yes(RvalInstrs),
> + ( get_last_instr_op(RvalInstrs, LastOp) ->
> + RvalOp = LastOp
> + ;
> + unexpected(this_file, "instr_to_x86_64: if_val unexpected")
> + )
> + ;
> + Res1 = no,
> + unexpected(this_file, "instr_to_x86_64: if_val unexpected")
> + )
> + ),
> + ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
> + Instrs = [directive(x86_64_pseudo_if(RvalStr)), instr(j(
> + operand_label(Target), "E")), directive(endif)].
> +instr_to_x86_64(save_maxfr(_), [comment("<<save_maxfr>>")]).
> +instr_to_x86_64(restore_maxfr(_), [comment("<<restore_maxfr>>")]).
> +instr_to_x86_64(incr_hp(Lval, Tag0, Words0, Rval, _, _), Instrs) :-
> + transform_rval(Rval, Res0, Res1),
> + transform_lval(Lval, Res2, Res3),
> + (
> + Res0 = yes(RvalOp)
> + ;
> + Res0 = no,
> + (
> + Res1 = yes(RvalInstrs),
> + ( get_last_instr_op(RvalInstrs, RvalLastOp) ->
> + RvalOp = RvalLastOp
> + ;
> + unexpected(this_file, "instr_to_x86_64: incr hp
> unexpected")
> + )
> + ;
> + Res1 = no,
> + unexpected(this_file, "instr_to_x86_64: incr hp: Rval
> unexpected")
> + )
> + ),
> + (
> + Res2 = yes(LvalOp)
> + ;
> + Res2 = no,
> + (
> + Res3 = yes(LvalInstrs),
> + ( get_last_instr_op(LvalInstrs, LvalLastOp) ->
> + LvalOp = LvalLastOp
> + ;
> + unexpected(this_file, "instr_to_x86_64: incr_hp
> unexpected")
> + )
> + ;
> + Res3 = no,
> + unexpected(this_file, "instr_to_x86_64: incr_hp Lval
> unexpected")
> + )
> + ),
> + (
> + Words0 = yes(Words),
> + IncrVal = operand_imm(imm32(int32(Words))),
> + TempReg = operand_reg(gp_reg(13)),
> + ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
> + MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
> + LoadAddr = instr(lea(MemRef, TempReg)),
> + IncrAddInstr = instr(add(IncrVal, TempReg)),
> + list.append([LoadAddr], [IncrAddInstr], IncrAddr)
> + ;
> + Words0 = no,
> + IncrAddr = []
> + ),
> + (
> + Tag0 = yes(Tag)
> + ;
> + Tag0 = no,
> + Tag = 0
> + ),
> + TempReg = operand_reg(gp_reg(13)),
> + ImmToReg = [instr(mov(RvalOp, TempReg))],
> + SetTag = [instr(or(operand_imm(imm32(int32(Tag))), TempReg))],
> + Instr0 = instr(mov(TempReg, LvalOp)),
> + list.append(IncrAddr, ImmToReg, Instr1),
> + list.append(Instr1, SetTag, Instr2),
> + list.append(Instr2, [Instr0], Instrs).
You can replace sequences of appends with ++ from list.m:
Instrs = IncrAddr ++ ImmToReg ++ SetTag ++ [Instr0].
This situation occurrs elsewhere, too.
> +instr_to_x86_64(mark_hp(_), [comment("<<mark_hp>>")]).
> +instr_to_x86_64(restore_hp(_), [comment("<<restore_hp>>")]).
> +instr_to_x86_64(free_heap(_), [comment("<<free_heap>>")]).
> +instr_to_x86_64(store_ticket(_), [comment("<<store_ticket>>")]).
> +instr_to_x86_64(reset_ticket(_, _), [comment("<<reset_ticket>>")]).
> +instr_to_x86_64(prune_ticket, [comment("<<prune_ticket>>")]).
> +instr_to_x86_64(discard_ticket, [comment("<<discard_ticket>>")]).
> +instr_to_x86_64(mark_ticket_stack(_), [comment("<<mark_ticket_stack>>")]).
> +instr_to_x86_64(prune_tickets_to(_), [comment("<<prune_tickets_to>>")]).
> +instr_to_x86_64(incr_sp(NumSlots, ProcName, _), Instrs) :-
> + Instr1 = comment("<<incr_sp>> " ++ ProcName),
> + Instr2 = instr(enter(uint16(NumSlots), uint8(0))),
> + Instrs = [Instr1, Instr2].
> +instr_to_x86_64(decr_sp(NumSlots), Instrs) :-
> + DecrOp = operand_imm(imm32(int32(NumSlots))),
> + Instr = instr(sub(DecrOp, operand_reg(gp_reg(13)))),
> + list.append([comment("<<decr_sp>> ")], [Instr], Instrs).
> +instr_to_x86_64(decr_sp_and_return(NumSlots), Instrs) :-
> + Instrs = [comment("<<decr_sp_and_return>> " ++
> + string.int_to_string(NumSlots))].
> +instr_to_x86_64(foreign_proc_code(_, _, _, _, _, _, _, _, _),
> + [comment("<<foreign_proc_code>>")]).
> +instr_to_x86_64(init_sync_term(_, _), [comment("<<init_sync_term>>")]).
> +instr_to_x86_64(fork(_), [comment("<<fork>>")]).
> +instr_to_x86_64(join_and_continue(_, _),
> [comment("<<join_and_continue>>")]).
> +
> +
> + % Transform lval into either an x86_64 operand or x86_64 instructions.
> + %
> +:- pred transform_lval(lval::in, maybe(operand)::out,
> maybe(list(x86_64_instr))
> + ::out) is det.
Formatting problem.
> +
> +transform_lval(reg(CReg, CRegNum), Op, no) :-
> + (
> + CReg = reg_r,
> + Op = yes(operand_reg(gp_reg(CRegNum)))
> + ;
> + CReg = reg_f,
> + Op = no
> + ).
> +transform_lval(succip, yes(operand_label("<<succip>>")), no).
> +transform_lval(maxfr, yes(operand_label("<<maxfr>>")), no).
> +transform_lval(curfr, yes(operand_label("<<curfr>>")), no).
> +transform_lval(hp, yes(operand_label("<<hp>>")), no).
> +transform_lval(sp, yes(operand_label("<<sp>>")), no).
> +transform_lval(parent_sp, yes(operand_label("<<parent_sp>>")), no).
> +transform_lval(temp(CReg, CRegNum), Op, no) :-
> + (
> + CReg = reg_r,
> + Op = yes(operand_reg(gp_reg(CRegNum)))
> + ;
> + CReg = reg_f,
> + Op = no
> + ).
> +transform_lval(stackvar(Offset), Op, no) :-
> + Op = yes(operand_label(string.int_to_string(Offset) ++
> "(<<stackvar>>)")).
> +transform_lval(parent_stackvar(_),
> yes(operand_label("<<parent_stackvar>>")), no).
> +transform_lval(framevar(_), yes(operand_label("<<framevar>>")), no).
> +transform_lval(succip_slot(Rval), Op, no) :-
> + transform_rval(Rval, Op, _).
> +transform_lval(redoip_slot(Rval), Op, no) :-
> + transform_rval(Rval, Op, _).
> +transform_lval(redofr_slot(Rval), Op, no) :-
> + transform_rval(Rval, Op, _).
> +transform_lval(succfr_slot(Rval), Op, no) :-
> + transform_rval(Rval, Op, _).
> +transform_lval(prevfr_slot(Rval), Op, no) :-
> + transform_rval(Rval, Op, _).
> +transform_lval(mem_ref(Rval), Op, no) :-
> + transform_rval(Rval, Op, _).
> +transform_lval(global_var_ref(env_var_ref(Name)),
> yes(operand_label(Name)), no).
> +transform_lval(lvar(_), yes(operand_label("<<lvar>>")), no).
> +transform_lval(field(Tag0, Rval1, Rval2), no, Instrs) :-
> + transform_rval(Rval1, Res0, Res1),
> + transform_rval(Rval2, Res2, Res3),
> + (
> + Res0 = yes(RvalOp1),
> + Instrs1 = []
> + ;
> + Res0 = no,
> + (
> + Res1 = yes(RvalInstrs1),
> + ( get_last_instr_op(RvalInstrs1, LastOp1) ->
> + RvalOp1 = LastOp1,
> + Instrs1 = RvalInstrs1
> + ;
> + unexpected(this_file, "lval_instrs: field unexpected")
> + )
> + ;
> + Res1 = no,
> + unexpected(this_file, "lval_instrs: field: Rval1 unexpected")
> + )
> + ),
> + (
> + Res2 = yes(RvalOp2),
> + Instrs2 = []
> + ;
> + Res2 = no,
> + (
> + Res3 = yes(RvalInstrs2),
> + ( get_last_instr_op(RvalInstrs2, LastOp2) ->
> + RvalOp2 = LastOp2,
> + Instrs2 = RvalInstrs2
> + ;
> + unexpected(this_file, "lval_instrs: field unexpected")
> + )
> + ;
> + Res3 = no,
> + unexpected(this_file, "lval_instrs: field: Rval2 unexpected")
> + )
> + ),
> + TempReg1 = operand_reg(gp_reg(13)),
> + ll_backend.x86_64_out.operand_type(RvalOp1, RvalStr1),
> + MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr1))),
> + LoadAddr = instr(lea(MemRef, TempReg1)),
> + FieldNum = instr(add(RvalOp2, TempReg1)),
> + list.append(Instrs1, Instrs2, Instr3),
> + list.append(Instr3, [comment("<<field>>")], Instr4),
> + list.append(Instr4, [LoadAddr], Instr5),
> + (
> + Tag0 = yes(Tag),
> + Mrbody = instr(sub(operand_imm(imm32(int32(Tag))), TempReg1)),
> + list.append(Instr5, [Mrbody], Instr6),
> + list.append(Instr6, [FieldNum], Instr7),
> + Instrs = yes(Instr7)
> + ;
> + Tag0 = no,
> + list.append(Instr5, [FieldNum], Instr6),
> + Instrs = yes(Instr6)
> + ).
> +
> + % Translates rval into its corresponding x86_64 operand.
> + %
> +:- pred transform_rval(rval::in, maybe(operand)::out,
> maybe(list(x86_64_instr))
> + ::out) is det.
> +
> +transform_rval(lval(Lval0), Op, Instrs) :-
> + transform_lval(Lval0, Op, Instrs).
> +transform_rval(var(_), yes(operand_label("<<var>>")), no).
> +transform_rval(mkword(Tag, Rval), no, Instrs) :-
> + transform_rval(Rval, Res0, Res1),
> + (
> + Res0 = yes(RvalOp),
> + list.append([comment("<<mkword>>")], [], Instr0)
> + ;
> + Res0 = no,
> + (
> + Res1 = yes(RvalInstrs),
> + ( get_last_instr_op(RvalInstrs, LastOp) ->
> + RvalOp = LastOp,
> + list.append(RvalInstrs, [comment("<<mkword>>")], Instr0)
> + ;
> + unexpected(this_file, "transform_rval: mkword unexpected")
> + )
> + ;
> + Res1 = no,
> + unexpected(this_file, "transform_rval: mkword Rval unexpected")
> + )
> + ),
> + TempReg = operand_reg(gp_reg(13)),
> + ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
> + MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
> + LoadAddr = instr(lea(MemRef, TempReg)),
> + SetTag = instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
> + list.append(Instr0, [LoadAddr], Instr1),
> + list.append(Instr1, [SetTag], Instr2),
> + Instrs = yes(Instr2).
> +transform_rval(const(llconst_true),
> yes(operand_label("<<llconst_true>>")), no).
> +transform_rval(const(llconst_false),
> yes(operand_label("<<llconst_false>>")), no).
> +transform_rval(const(llconst_int(Val)),
> yes(operand_imm(imm32(int32(Val)))), no).
> +transform_rval(const(llconst_float(_)),
> yes(operand_label("<<llconst_float>>")), no).
> +transform_rval(const(llconst_string(String)), no, yes(Op)) :-
> + Op = [directive(string([String]))].
> +transform_rval(const(llconst_multi_string(_, _)), Op, no) :-
> + Op = yes(operand_label("<<llconst_multi_string>>")).
> +transform_rval(const(llconst_code_addr(CodeAddr)), Op, no) :-
> + code_addr_type(CodeAddr, CodeAddrType),
> + Op = yes(operand_label("<<llconst_code_addr>>" ++ CodeAddrType)).
> +transform_rval(const(llconst_data_addr(_, _)), Op, no) :-
> + Op = yes(operand_label("<<llconst_data_addr>>")).
> +transform_rval(unop(Op, Rval), no, Instrs) :-
> + transform_rval(Rval, Res0, Res1),
> + (
> + Res0 = yes(_),
> + unop_instrs(Op, Res0, no, Instr0),
> + Instrs = yes(Instr0)
> + ;
> + Res0 = no,
> + (
> + Res1 = yes(_),
> + unop_instrs(Op, no, Res1, Instr0),
> + Instrs = yes(Instr0)
> + ;
> + Res1 = no,
> + unexpected(this_file, "transform_rval: unop Rval unexpected")
> + )
> + ).
> +transform_rval(binop(Op, Rval1, Rval2), no, Instrs) :-
> + transform_rval(Rval1, Res1, Res2),
> + transform_rval(Rval2, Res3, Res4),
> + (
> + Res1 = yes(Val1),
> + (
> + Res3 = yes(Val2),
> + binop_instrs(binop_two_ops(Val1, Val2), Op, Instr0),
> + Instrs = yes(Instr0)
> + ;
> + Res3 = no,
> + (
> + Res4 = yes(RvalInstr2),
> + binop_instrs(binop_op_and_instr(Val1, RvalInstr2), Op,
> Instr0),
> + Instrs = yes(Instr0)
> + ;
> + Res4 = no,
> + Instrs = no
> + )
> + )
> + ;
> + Res1 = no,
> + (
> + Res2 = yes(RvalInstr1),
> + (
> + Res3 = yes(Val2),
> + binop_instrs(binop_instr_and_op(RvalInstr1, Val2), Op,
> Instr0),
> + Instrs = yes(Instr0)
> + ;
> + Res3 = no,
> + (
> + Res4 = yes(RvalInstr2),
> + binop_instrs(binop_two_instrs(RvalInstr1, RvalInstr2),
> + Op, Instr0),
> + Instrs = yes(Instr0)
> + ;
> + Res4 = no,
> + unexpected(this_file, "rval_instrs: binop: Rval2
> + unexpected")
> + )
> + )
> + ;
> + Res2 = no,
> + unexpected(this_file, "rval_instrs: binop: Rval1 unexpected")
> + )
> + ).
> +transform_rval(mem_addr(stackvar_ref(Rval)), Op, no) :-
> + transform_rval(Rval, Op, _).
> +transform_rval(mem_addr(framevar_ref(Rval)), Op, no) :-
> + transform_rval(Rval, Op, _).
> +transform_rval(mem_addr(heap_ref(Rval1, Tag, Rval2)), no, Instrs) :-
> + transform_rval(Rval1, Res0, Res1),
> + transform_rval(Rval2, Res2, Res3),
> + (
> + Res0 = yes(Rval1Op),
> + (
> + Res2 = yes(Rval2Op),
> + Instr2 = []
> + ;
> + Res2 = no,
> + (
> + Res3 = yes(Rval2Instr),
> + Instr2 = [],
> + ( get_last_instr_op(Rval2Instr, LastOp) ->
> + Rval2Op = LastOp
> + ;
> + unexpected(this_file, "transform_rval:
> mem_addr(heap_ref)
> + unexpected")
> + )
> + ;
> + Res3 = no,
> + unexpected(this_file, "transform_rval: mem_addr(heap_ref)
> + unexpected")
> + )
> + )
> + ;
> + Res0 = no,
> + (
> + Res1 = yes(Rval1Instr),
> + ( get_last_instr_op(Rval1Instr, LastOp) ->
> + Rval1Op = LastOp,
> + (
> + Res2 = yes(Rval2Op),
> + Instr2 = Rval1Instr
> + ;
> + Res2 = no,
> + (
> + Res3 = yes(Rval2Instr),
> + ( get_last_instr_op(Rval2Instr, LastOp) ->
> + Rval2Op = LastOp,
> + list.append(Rval1Instr, Rval2Instr, Instr2)
> + ;
> + unexpected(this_file, "transform_rval:
> mem_addr(heap_ref)
> + unexpected")
> + )
> + ;
> + Res3 = no,
> + unexpected(this_file, "transform_rval:
> mem_addr(heap_ref)
> + unexpected")
> + )
> + )
> + ;
> + unexpected(this_file, "transform_rval: mem_addr(heap_ref)
> + unexpected")
> + )
> + ;
> + Res1 = no,
> + unexpected(this_file, "transform_rval: mem_addr(heap_ref)
> + unexpected")
> + )
> + ),
> + TempReg = operand_reg(gp_reg(13)),
> + ll_backend.x86_64_out.operand_type(Rval1Op, Rval1Str),
> + MemRef = operand_mem_ref(mem_abs(base_expr(Rval1Str))),
> + LoadAddr = instr(lea(MemRef, TempReg)),
> + Instr0 = instr(sub(Rval2Op, TempReg)),
> + Instr1 = instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
> + list.append(Instr2, [LoadAddr], Instr3),
> + list.append(Instr3, [Instr0], Instr4),
> + list.append(Instr4, [Instr1], Instr5),
> + Instrs = yes(Instr5).
> +
> + % x86_64 instructions for binary operation with either an operand or an
> + % expression (given as a list of x86_64 instructions) or a combination
> of
> + % both.
> + %
> +:- pred binop_instrs(binop::in, binary_op::in, list(x86_64_instr)::out) is
> det.
> +
> +binop_instrs(binop_two_ops(Op1, Op2), Op, Instrs) :-
> + binop_instr(Op, Op1, Op2, Instrs).
> +binop_instrs(binop_op_and_instr(Op1, InstrsOp), Op, Instrs) :-
> + ( get_last_instr_op(InstrsOp, LastOp) ->
> + binop_instr(Op, Op1, LastOp, Instr0),
> + list.append(InstrsOp, Instr0, Instrs)
> + ;
> + unexpected(this_file, "binop_instrs: binop_op_and_instr
> unexpected")
> + ).
> +binop_instrs(binop_instr_and_op(InstrsOp, Op2), Op, Instrs) :-
> + ( get_last_instr_op(InstrsOp, LastOp) ->
> + binop_instr(Op, LastOp, Op2, Instr0),
> + list.append(InstrsOp, Instr0, Instrs)
> + ;
> + unexpected(this_file, "binop_instrs: binop_instr_and_op:
> unexpected")
> + ).
> +binop_instrs(binop_two_instrs(InstrsOp1, InstrsOp2), Op, Instrs) :-
> + (
> + get_last_instr_op(InstrsOp1, LastOp1),
> + get_last_instr_op(InstrsOp2, LastOp2)
> + ->
> + binop_instr(Op, LastOp1, LastOp2, Instr0),
> + list.append(InstrsOp1, InstrsOp2, Instr1),
> + list.append(Instr1, Instr0, Instrs)
> + ;
> + unexpected(this_file, "binop_instrs: binop_two_instrs: unexpected")
> + ).
> +
> + % Equivalent x86_64 instructions for a unary operation. A unary
> operation
> + % may consist of an operand or an expression (as a list of x86_64
> + % instructions).
> + %
> +:- pred unop_instrs(backend_libs.builtin_ops.unary_op::in,
> maybe(operand)::in,
> + maybe(list(x86_64_instr))::in, list(x86_64_instr)::out) is det.
> +
> +unop_instrs(mktag, _, _, [comment("<<mktag>>")]).
> +unop_instrs(tag, _, _, [comment("<<tag>>")]).
> +unop_instrs(unmktag, _, _, [comment("<<unmktag>>")]).
> +unop_instrs(strip_tag, _, _, [comment("<<strip_tag>>")]).
> +unop_instrs(mkbody, _, _, [comment("<<mkbody>>")]).
> +unop_instrs(unmkbody, _, _, [comment("<<unmkbody>>")]).
> +unop_instrs(hash_string, _, _, [comment("<<hash_string>>")]).
> +unop_instrs(bitwise_complement, Op, Instrs0, Instrs) :-
> + (
> + Op = yes(OpRes),
> + Instrs = [instr(x86_64_instr_not(OpRes))]
> + ;
> + Op = no,
> + (
> + Instrs0 = yes(InsRes),
> + ( get_last_instr_op(InsRes, LastOp) ->
> + list.append(InsRes, [instr(x86_64_instr_not(LastOp))],
> Instrs)
> + ;
> + unexpected(this_file, "unop_instrs: bitwise_complement
> + unexpected")
> + )
> + ;
> + Instrs0 = no,
> + unexpected(this_file, "unop_instrs: bitwise_complement
> unexpected")
> + )
> + ).
> +unop_instrs(logical_not, _, _, [comment("<<logical_not>>")]).
> +
> + % Equivalent x86_64 instructions for a binary operation.
> + %
> +:- pred binop_instr(backend_libs.builtin_ops.binary_op::in, operand::in,
> + operand::in, list(x86_64_instr)::out) is det.
> +
> +binop_instr(int_add, Op1, Op2, [instr(add(Op1, Op2))]).
> +binop_instr(int_sub, Op1, Op2, [instr(sub(Op1, Op2))]).
> +binop_instr(int_mul, Op1, Op2, [instr(imul(Op1, yes(Op2), no))]).
> +binop_instr(int_mod, _, _, [comment("<<int_mod>>")]).
> +binop_instr(int_div, Op1, Op2, Instrs) :-
> + LoadDividend = instr(mov(Op2, operand_label("<<int_div>>"))),
> + list.cons(LoadDividend, [instr(idiv(Op1))], Instrs).
> +binop_instr(unchecked_left_shift, Op1, Op2, [instr(shl(Op1, Op2))]).
> +binop_instr(unchecked_right_shift, Op1, Op2, [instr(shr(Op1, Op2))]).
> +binop_instr(bitwise_and, Op1, Op2, [instr(and(Op1, Op2))]).
> +binop_instr(bitwise_or, _, _, [comment("<<bitwise_or>>")]).
> +binop_instr(bitwise_xor, Op1, Op2, [instr(xor(Op1, Op2))]).
> +binop_instr(logical_and, _, _, [comment("<<logical_and>>")]).
> +binop_instr(logical_or, _, _, [comment("<<logical_or>>")]).
> +binop_instr(eq, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(ne, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(body, _, _, [comment("<<body>>")]).
> +binop_instr(array_index(_), _, _, [comment("<<array_index>>")]).
> +binop_instr(str_eq, _, _, [comment("<<str_eq>>")]).
> +binop_instr(str_ne, _, _, [comment("<<str_ne>>")]).
> +binop_instr(str_lt, _, _, [comment("<<str_lt>>")]).
> +binop_instr(str_gt, _, _, [comment("<<str_gt>>")]).
> +binop_instr(str_le, _, _, [comment("<<str_le>>")]).
> +binop_instr(str_ge, _, _, [comment("<<str_ge>>")]).
> +binop_instr(int_lt, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(int_gt, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(int_le, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(int_ge, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(unsigned_le, Op1, Op2, [instr(cmp(Op1, Op2))]).
> +binop_instr(float_plus, _, _, [comment("<<float_plus>>")]).
> +binop_instr(float_minus, _, _, [comment("<<float_minus>>")]).
> +binop_instr(float_times, _, _, [comment("<<float_times>>")]).
> +binop_instr(float_divide, _, _, [comment("<<float_divide>>")]).
> +binop_instr(float_eq, _, _, [comment("<<float_eq>>")]).
> +binop_instr(float_ne, _, _, [comment("<<float_ne>>")]).
> +binop_instr(float_lt, _, _, [comment("<<float_lt>>")]).
> +binop_instr(float_gt, _, _, [comment("<<float_gt>>")]).
> +binop_instr(float_le, _, _, [comment("<<float_le>>")]).
> +binop_instr(float_ge, _, _, [comment("<<float_ge>>")]).
> +
> + % Get a string representation of code address types.
> + %
> +:- pred code_addr_type(code_addr::in, string::out) is det.
> +
> +code_addr_type(code_label(Label), CodeAddr) :-
> + CodeAddr = "$" ++ ll_backend.llds_out.label_to_c_string(Label, no).
> +code_addr_type(code_imported_proc(ProcLabel), CodeAddr) :-
> + CodeAddr = "$" ++
> + backend_libs.name_mangle.proc_label_to_c_string(ProcLabel, no).
> +code_addr_type(code_succip, CodeAddr) :-
> + CodeAddr = "<<code_succip>>".
> +code_addr_type(do_succeed(_), CodeAddr) :-
> + CodeAddr = "<<do_succeed>>".
> +code_addr_type(do_redo, CodeAddr) :-
> + CodeAddr = "<<do_redo>>".
> +code_addr_type(do_fail, CodeAddr) :-
> + CodeAddr = "<<do_fail>>".
> +code_addr_type(do_trace_redo_fail_shallow, CodeAddr) :-
> + CodeAddr = "<<do_trace_redo_fail_shallow>>".
> +code_addr_type(do_trace_redo_fail_deep, CodeAddr) :-
> + CodeAddr = "<<do_trace_redo_fail_deep>>".
> +code_addr_type(do_call_closure(_), CodeAddr) :-
> + CodeAddr = "<<do_call_closure>>".
> +code_addr_type(do_call_class_method(_), CodeAddr) :-
> + CodeAddr = "<<do_call_class_method>>".
> +code_addr_type(do_not_reached, CodeAddr) :-
> + CodeAddr = "<<do_not_reached>>".
> +
> + % Given a list of x86_64 instructions, figure out the operand of the
> last
> + % instruction in the list.
> + %
> +:- pred get_last_instr_op(list(x86_64_instr)::in, operand::out) is semidet.
> +
> +get_last_instr_op(Instrs, Op) :-
> + list.last_det(Instrs, LastInstr),
It's preferable to use a function rather than a predicate where
possible:
LastInstr = list.last_det(Instrs),
> + (
> + LastInstr = comment(Comment),
> + Op = operand_label(Comment)
> + ;
> + LastInstr = label(Label),
> + Op = operand_label(Label)
> + ;
> + LastInstr = instr(Instr),
> + last_instr_dest(Instr, Op)
> + ;
> + LastInstr = directive(_),
> + Op = operand_label("<<directive>>")
> + ).
> +
> + % Destination operand of an x86_64_instruction.
> + %
> +:- pred last_instr_dest(x86_64_inst::in, operand::out) is semidet.
> +
> +last_instr_dest(adc(_, Dest), Dest).
> +last_instr_dest(add(_, Dest), Dest).
> +last_instr_dest(and(_, Dest), Dest).
> +last_instr_dest(bs(_, Dest, _), Dest).
> +last_instr_dest(bswap(Dest), Dest).
> +last_instr_dest(cmov(_, Dest, _), Dest).
> +last_instr_dest(cmp(_, Dest), Dest).
> +last_instr_dest(cmpxchg(_, Dest), Dest).
> +last_instr_dest(cmpxchg8b(Dest), Dest).
> +last_instr_dest(dec(Dest), Dest).
> +last_instr_dest(div(Dest), Dest).
> +last_instr_dest(idiv(Dest), Dest).
> +last_instr_dest(imul(_, yes(Dest), _), Dest).
> +last_instr_dest(inc(Dest), Dest).
> +last_instr_dest(jrcxz(Dest), Dest).
> +last_instr_dest(jmp(Dest), Dest).
> +last_instr_dest(lea(_, Dest), Dest).
> +last_instr_dest(loop(Dest), Dest).
> +last_instr_dest(loope(Dest), Dest).
> +last_instr_dest(loopne(Dest), Dest).
> +last_instr_dest(loopnz(Dest), Dest).
> +last_instr_dest(loopz(Dest), Dest).
> +last_instr_dest(mov(_, Dest), Dest).
> +last_instr_dest(mul(Dest), Dest).
> +last_instr_dest(x86_64_instr_not(Dest), Dest).
> +last_instr_dest(or(_, Dest), Dest).
> +last_instr_dest(pop(Dest), Dest).
> +last_instr_dest(push(Dest), Dest).
> +last_instr_dest(rc(_, Dest, _), Dest).
> +last_instr_dest(ro(_, Dest, _), Dest).
> +last_instr_dest(sal(_, Dest), Dest).
> +last_instr_dest(shl(_, Dest), Dest).
> +last_instr_dest(sar(_, Dest), Dest).
> +last_instr_dest(sbb(_, Dest), Dest).
> +last_instr_dest(set(Dest, _), Dest).
> +last_instr_dest(shr(_, Dest), Dest).
> +last_instr_dest(sub(_, Dest), Dest).
> +last_instr_dest(xadd(_, Dest), Dest).
> +last_instr_dest(xor(_, Dest), Dest).
> +
> + % Get a string representation of llds labels.
> + %
> +:- pred labels_to_string(list(label)::in, string::in, string::out) is det.
> +
> +labels_to_string([], Str, Str).
> +labels_to_string([Label | Labels], Str0, Str) :-
> + LabelStr = ll_backend.llds_out.label_to_c_string(Label, no),
> + labels_to_string(Labels, Str0 ++ LabelStr, Str).
> +
> +%----------------------------------------------------------------------------%
> +
> +:- func this_file = string.
> +
> +this_file = "llds_to_x86_64.m".
> +
> +%----------------------------------------------------------------------------%
> +:- end_module llds_to_x86_64.
> +%----------------------------------------------------------------------------%
> Index: compiler/llds_to_x86_64_out.m
> ===================================================================
> RCS file: compiler/llds_to_x86_64_out.m
> diff -N compiler/llds_to_x86_64_out.m
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ compiler/llds_to_x86_64_out.m 2 Feb 2007 02:20:46 -0000
> @@ -0,0 +1,58 @@
> +%-----------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%-----------------------------------------------------------------------------%
> +% Copyright (C) 2007 The University of Melbourne.
> +% This file may only be copied under the terms of the GNU General
> +% Public License - see the file COPYING in the Mercury distribution.
> +%-----------------------------------------------------------------------------%
> +%
> +% File: llds_to_x86_64_out.m.
> +% Main author: fhandoko.
> +%
> +% This module defines the routines for printing out instructions produced
> by
> +% llds->x86_64 asm generator.
> +%
> +%-----------------------------------------------------------------------------%
> +
> +:- module ll_backend.llds_to_x86_64_out.
> +:- interface.
> +
> +:- import_module ll_backend.x86_64_instrs.
> +
> +:- import_module io.
> +:- import_module list.
> +
> +%-----------------------------------------------------------------------------%
> +
> +:- pred output_x86_64_asm(list(x86_64_procedure)::in, io::di, io::uo) is
> det.
> +
> +%-----------------------------------------------------------------------------%
> +%-----------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module ll_backend.llds_to_x86_64.
> +:- import_module ll_backend.x86_64_out.
> +
> +output_x86_64_asm(AsmProcs, !IO) :-
> + output_asm_proc_list(AsmProcs, !IO).
> +
> +
> +:- pred output_asm_proc_list(list(x86_64_procedure)::in, io::di, io::uo)
> is det.
> +
> +output_asm_proc_list([], !IO).
> +output_asm_proc_list([AsmProc | AsmProcs], !IO) :-
> + output_asm_instr_list(AsmProc ^ x86_64_code, !IO),
> + output_asm_proc_list(AsmProcs, !IO).
> +
> +:- pred output_asm_instr_list(list(x86_64_instruction)::in, io::di, io::uo)
> + is det.
> +
> +output_asm_instr_list([], !IO).
> +output_asm_instr_list([AsmInstr | AsmInstrs], !IO) :-
> + output_x86_64_instruction(AsmInstr, !IO),
> + output_asm_instr_list(AsmInstrs, !IO).
> +
> +%----------------------------------------------------------------------------%
> +:- end_module llds_to_x86_64_out.
> +%----------------------------------------------------------------------------%
> Index: compiler/mercury_compile.m
> ===================================================================
> RCS file:
> /home/mercury/mercury1/repository/mercury/compiler/mercury_compile.m,v
> retrieving revision 1.426
> diff -u -r1.426 mercury_compile.m
> --- compiler/mercury_compile.m 23 Jan 2007 03:45:34 -0000 1.426
> +++ compiler/mercury_compile.m 31 Jan 2007 23:46:04 -0000
> @@ -122,6 +122,12 @@
> :- import_module bytecode_backend.bytecode_gen.
> :- import_module bytecode_backend.bytecode.
>
> + % The x86_64 asm back-end.
> + %
> +:- import_module ll_backend.llds_to_x86_64.
> +:- import_module ll_backend.llds_to_x86_64_out.
> +:- import_module ll_backend.x86_64_instrs.
> +
> % the MLDS back-end
> :- import_module ml_backend.add_trail_ops. % HLDS -> HLDS
> :- import_module ml_backend.add_heap_ops. % HLDS -> HLDS
> @@ -1639,12 +1645,16 @@
> )
> ;
> Target = target_x86_64,
> - backend_pass(!HLDS, GlobalData, LLDS, !DumpInfo, !IO),
> +% backend_pass(!HLDS, GlobalData, LLDS, !DumpInfo, !IO),
> + backend_pass(!HLDS, _, LLDS, !DumpInfo, !IO),
> % XXX Eventually we will call the LLDS->x86_64 asm code
> % generator here and then output the assembler. At the moment
> % we just output the LLDS as C code.
> - output_pass(!.HLDS, GlobalData, LLDS, ModuleName,
> - _CompileErrors, _, !IO),
> + llds_to_x86_64_asm(!.HLDS, LLDS, X86_64_Asm),
> + output_x86_64_asm(X86_64_Asm, !IO),
> + % need to output x86_64_Asm
> + %output_pass(!.HLDS, GlobalData, LLDS, ModuleName,
> + % _CompileErrors, _, !IO),
> FactTableBaseFiles = []
> ),
> recompilation.usage.write_usage_file(!.HLDS, NestedSubModules,
> Index: compiler/x86_64_instrs.m
> ===================================================================
> RCS file:
> /home/mercury/mercury1/repository/mercury/compiler/x86_64_instrs.m,v
> retrieving revision 1.1
> diff -u -r1.1 x86_64_instrs.m
> --- compiler/x86_64_instrs.m 15 Jan 2007 22:49:41 -0000 1.1
> +++ compiler/x86_64_instrs.m 30 Jan 2007 23:33:36 -0000
> @@ -16,14 +16,69 @@
> :- module ll_backend.x86_64_instrs.
> :- interface.
>
> +:- import_module hlds.hlds_pred.
> +:- import_module hlds.code_model.
> +:- import_module ll_backend.llds.
> +:- import_module mdbcomp.prim_data.
> +
> +:- import_module counter.
> :- import_module list.
> :- import_module maybe.
> +:- import_module set.
> +
> +%-----------------------------------------------------------------------------%
> +
> + % We turn a llds.c_file into this.
> + %
> +:- type x86_64_module
> + ---> x86_64_module(
> + x86_64_modulename :: module_name,
> + % The name of this x86_64 module.
> + x86_64_procs :: list(list(x86_64_procedure))
> + % The code.
> + ).
> +
> +:- func init_x86_64_module(module_name) = x86_64_module.
> +
> +:- func init_x86_64_proc(c_procedure) = x86_64_procedure.
> +
> +:- func init_x86_64_instruction = x86_64_instruction.
> +
> +%-----------------------------------------------------------------------------%
> +
> + % We turn an llds.c_procedure into one of these.
> + % XXX Do we really need to replicate all these fields from the llds?
> + %
> +:- type x86_64_procedure
> + ---> x86_64_procedure(
> + x86_64_name :: string,
> + % Predicate name.
> + x86_64_arity :: int,
> + % Original arity.
> + x86_64_id :: pred_proc_id,
> + % The pred_proc_id of this code.
> + x86_64_code_model :: code_model,
> + % The code model of the procedure.
> + x86_64_code :: list(x86_64_instruction),
> + % The code for this procedure.
> + x86_64_proc_label :: proc_label,
> + % Proc_label of this procedure.
> + x86_64_label_nums :: counter,
> + x86_64_may_alter_rtti :: may_alter_rtti,
> + % The compiler is allowed to
> perform
> + % optimizations on this procedure
> + % that could alter RTTI information
> + % (e.g. the set of variables live
> at
> + % a label) only if this field is
> set
> + % to `may_alter_rtti'.
> + x86_64_c_global_vars :: set(string)
> + ).
>
>
> %-----------------------------------------------------------------------------%
>
> :- type x86_64_instruction
> ---> x86_64_instr(
> - x86_64_instr_name :: x86_64_op,
> + x86_64_inst :: list(x86_64_instr),
> x86_64_comment :: string
> ).
>
> @@ -32,8 +87,8 @@
> :- type x86_64_instr
> ---> comment(string)
> ; label(label_name)
> - ; directives(list(pseudo_op))
> - ; instrs(list(x86_64_instruction)).
> + ; directive(pseudo_op)
> + ; instr(x86_64_inst).
>
>
> %-----------------------------------------------------------------------------%
>
> @@ -136,7 +191,7 @@
> ; eject
> % Force a page break.
>
> - ; else_
> + ; x86_64_pseudo_else
> % As in 'if-then-else' conditional expression.
>
> ; elseif
> @@ -239,7 +294,7 @@
> ; ident
> % To place tags in object files.
>
> - ; if_(
> + ; x86_64_pseudo_if(
> if_expr :: string
> )
> % Mark the beginning of a conditional section.
> @@ -520,7 +575,7 @@
> )
> % Use 'title_heading' as the title when generating assembly
> listing.
>
> - ; type_(
> + ; x86_64_pseudo_type(
> type_name :: string,
> type_desc :: string
> )
> @@ -571,22 +626,7 @@
> % Details on amd64-prog-man-vol1 manual p27.
> %
> :- type gp_reg
> - ---> rax
> - ; rbx
> - ; rcx
> - ; rdx
> - ; rbp
> - ; rsi
> - ; rdi
> - ; rsp
> - ; r8
> - ; r9
> - ; r10
> - ; r11
> - ; r12
> - ; r13
> - ; r14
> - ; r15.
> + ---> gp_reg(int).
>
> % 64-bit instruction pointer register on the x86_64. Instruction
> pointer
> % RIP is used as a base register for relative addressing. x86_64
> @@ -622,7 +662,7 @@
> % or an instruction-relative address.
> % Details on amd64-prog-man-vol1 p19.
> %
> -:- type mem_ref
> +:- type x86_64_mem_ref
> ---> mem_abs(
> mem_abs_address :: base_address
> )
> @@ -650,35 +690,14 @@
> :- type operand
> ---> operand_reg(gp_reg)
> ; operand_imm(imm_operand)
> - ; operand_mem_ref(mem_ref).
> -
> + ; operand_mem_ref(x86_64_mem_ref)
> + ; operand_rel_offset(rel_offset)
> + ; operand_label(string).
>
> %
> % Subtypes of the operand type.
> % XXX maybe we should use inst-subtyping for these?
> %
> -
> - % x86_64_instruction's operand is either the content a general-purpose
> - % register or the content of a memory reference.
> - %
> -:- type reg_or_mem_ref_op
> - ---> rmro_reg(gp_reg)
> - ; rmro_mem_ref(mem_ref).
> -
> - % x86_64_instruction's operand is either the contents of a
> general-purpose
> - % register or the value of an immediate operand.
> - %
> -:- type reg_or_imm_op
> - ---> rio_reg(gp_reg)
> - ; rio_imm(imm_operand).
> -
> - % x86_64_instruction's operand is either the content of CL register
> (the
> - % bottom 16 bits of RCX register) or an 8-bit immediate value.
> - %
> -:- type cl_reg_or_imm_op
> - ---> crio_reg_cl(gp_reg)
> - ; crio_imm8(int8).
> -
> % x86_64 instruction's operand is an offset relative to the instruction
> % pointer.
> %
> @@ -692,7 +711,7 @@
> %
> :- type rmrol
> ---> rmrol_reg(gp_reg)
> - ; rmrol_mem_ref(mem_ref)
> + ; rmrol_mem_ref(x86_64_mem_ref)
> ; rmrol_rel_offset(rel_offset)
> ; rmrol_label(
> rmrol_label_name :: string
> @@ -706,83 +725,101 @@
> % We use At&T style instructions where the source comes before the
> % destination.
> %
> -:- type x86_64_op
> +:- type x86_64_inst
> ---> adc(
> adc_src :: operand,
> - adc_dst :: reg_or_mem_ref_op
> + % immediate, register or memory location
> + adc_dst :: operand
> + % register or memory location
> )
> % Add with carry. Add 'adc_src' to 'adc_dst' + carry flag (CF).
> + % Cannot add two memory operands.
> % Details on amd64-prog-man-vol3 manual p65.
>
> ; add(
> add_src :: operand,
> - add_dst :: reg_or_mem_ref_op
> + % immediate, register or memory location
> + add_dst :: operand
> + % register or memory location
> )
> % Signed or unsigned add. Add 'adc_src' to 'adc_dst'.
> + % Cannot add two memory operands.
> % Details on amd64-prog-man-vol3 manual p67.
>
> ; and(
> and_src :: operand,
> - and_dst :: reg_or_mem_ref_op
> + % immediate, register or memory location
> + and_dst :: operand
> + % register or memory location
> )
> % Performs a bitwise AND operation on both operands.
> + % Cannot and two memory operands.
> % Details on amd64-prog-man-vol3 manual p69.
>
> - ; bsf(
> - bsf_src :: reg_or_mem_ref_op,
> - bsf_dst :: gp_reg
> - )
> - % Bit scan forward. Searches the value in 'bsf_src' for the
> least
> - % significant set bit.
> - % Details on amd64-prog-man-vol3 manual p74.
> -
> - ; bsr(
> - bsr_src :: reg_or_mem_ref_op,
> - bsr_dst :: gp_reg
> - )
> - % Bit scan reverse. Searches the value in 'bsf_src' for the
> most
> - % significant set bit.
> - % Details on amd64-prog-man-vol3 manual p75.
> + ; bs(
> + bs_src :: operand,
> + % register or memory location
> + bs_dst :: operand,
> + % register
> + bs_cond :: string
> + % "F" for forward, "R" for reverse"
Using strings like this is usually bad. Why not use a discriminated
union type?
> + )
> + % Bit scan. Searches the value in 'bs_src' for the least
> + % significant set bit if 'bs_cond' is "F". Searches
> + % for the most significant set bit if 'bs_cond' is "R".
> + % Details on amd64-prog-man-vol3 manual p(74-75).
>
> - ; bswap(gp_reg)
> - % Byte swap. Reverses the byte order of the specified 'gp_reg'.
> + ; bswap(
> + bswap_reg :: operand
> + )
> + % Byte swap. Reverses the byte order of the specified
> 'operand'.
> % Details on amd64-prog-man-vol3 manual p76.
>
> ; bt(
> - bt_src :: reg_or_mem_ref_op,
> - bt_idx :: reg_or_imm_op
> + bt_src :: operand,
> + % register or memory reference
> + bt_idx :: operand
> + % register or 8-bit immediate value
> )
> % Bit test. Copies a bit specified by 'bt_idx' from a bit
> string in
> % 'bt_src' to the carry flag (CF) or RFLAGS register.
> % Details on amd64-prog-man-vol3 manual p77.
> ; btc(
> - btc_src :: reg_or_mem_ref_op,
> - btc_idx :: reg_or_imm_op
> + btc_src :: operand,
> + % register or memory reference
> + btc_idx :: operand
> + % register or 8-bit immediate value
> )
> % Bit test and complement. Complements 'btc_src' after
> performing
> % 'bt' operation.
> % Details on amd64-prog-man-vol3 manual p79.
>
> ; btr(
> - btr_src :: reg_or_mem_ref_op,
> - btr_idx :: reg_or_imm_op
> + btr_src :: operand,
> + % register or memory reference
> + btr_idx :: operand
> + % register or 8-bit immediate value
> )
> % Bit test and reverse. Clears 'btr_src' to 0 after performing
> 'bt'
> % operation.
> % Details on amd64-prog-man-vol3 manual p81.
>
> ; bts(
> - bts_src :: reg_or_mem_ref_op,
> - bts_idx :: reg_or_imm_op
> + bts_src :: operand,
> + % register or memory reference
> + bts_idx :: operand
> + % register or 8-bit immediate value
> )
> % Bit test and set. Sets 'bts_src' to 1 after performing 'bt'
> % operation.
> % Details on amd64-prog-man-vol3 manual p83.
>
> - ; call(rmrol)
> - % Call with target specified by 'rmrol': register, memory
> location,
> - % relative offset or a label.
> + ; call(
> + call_target :: operand
> + % label, register, memory reference or rel
> offset
> + )
> + % Call with target specified by call_target
> % Details on amd64-prog-man-vol3 manual p85.
>
> ; cbw
> @@ -821,241 +858,85 @@
> % Complements the carry flag bit (CF) bit in the rFLAGS
> register.
> % Details on amd64-prog-man-vol3 manual p100.
>
> - ; cmovo(
> - cmovo_src :: reg_or_mem_ref_op,
> - cmovo_dest :: gp_reg
> - )
> - % Moves if overflow (OF = 1).
> - % Details on amd64-prog-man-vol3 manual p101.
> -
> - ; cmovno(
> - cmovno_src :: reg_or_mem_ref_op,
> - cmovno_dest :: gp_reg
> - )
> - % Moves if not overflow (OF = 0).
> - % Details on amd64-prog-man-vol3 manual p101.
> -
> - ; cmovb(
> - cmovb_src :: reg_or_mem_ref_op,
> - cmovb_dest :: gp_reg
> - )
> - % Moves if below (CF = 1).
> - % Details on amd64-prog-man-vol3 manual p101.
> -
> - ; cmovc(
> - cmovc_src :: reg_or_mem_ref_op,
> - cmovc_dest :: gp_reg
> - )
> - % Moves if carry (CF = 1).
> - % Details on amd64-prog-man-vol3 manual p101.
> -
> - ; cmovnae(
> - cmovnae_src :: reg_or_mem_ref_op,
> - cmovnae_dest :: gp_reg
> - )
> - % Moves if not above or equal (CF = 1).
> - % Details on amd64-prog-man-vol3 manual p101.
> -
> - ; cmovnb(
> - cmovnb_src :: reg_or_mem_ref_op,
> - cmovnb_dest :: gp_reg
> - )
> - % Moves if not below (CF = 0).
> - % Details on amd64-prog-man-vol3 manual p101.
> -
> - ; cmovnc(
> - cmovnc_src :: reg_or_mem_ref_op,
> - cmovnc_dest :: gp_reg
> - )
> - % Moves if not carry (CF = 0).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovae(
> - cmovae_src :: reg_or_mem_ref_op,
> - cmovae_dest :: gp_reg
> - )
> - % Moves if above or equal (CF = 0).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovz(
> - cmovz_src :: reg_or_mem_ref_op,
> - cmovz_dest :: gp_reg
> - )
> - % Moves if zero (ZF = 1).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmove(
> - cmove_src :: reg_or_mem_ref_op,
> - cmove_dest :: gp_reg
> - )
> - % Moves if equal (ZF = 1).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovnz(
> - cmovnz_src :: reg_or_mem_ref_op,
> - cmovnz_dest :: gp_reg
> - )
> - % Moves if not zero (ZF = 0).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovne(
> - cmovne_src :: reg_or_mem_ref_op,
> - cmovne_dest :: gp_reg
> - )
> - % Moves if not equal (ZF = 0).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovbe(
> - cmovbe_src :: reg_or_mem_ref_op,
> - cmovbe_dest :: gp_reg
> - )
> - % Moves if below or equal (CF = 1 or ZF = 1).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovna(
> - cmovna_src :: reg_or_mem_ref_op,
> - cmovna_dest :: gp_reg
> - )
> - % Moves if not above (CF = 1 or ZF = 1).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovnbe(
> - cmovnbe_src :: reg_or_mem_ref_op,
> - cmovnbe_dest :: gp_reg
> - )
> - % Moves if not below or equal (CF = 0 or ZF = 0).
> - % Details on amd64-prog-man-vol3 manual p102.
> - ; cmova(
> - cmova_src :: reg_or_mem_ref_op,
> - cmova_dest :: gp_reg
> - )
> - % Moves if above (CF = 1 or ZF = 0).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovs(
> - cmovs_src :: reg_or_mem_ref_op,
> - cmovs_dest :: gp_reg
> - )
> - % Moves if sign (SF = 1).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovns(
> - cmovns_src :: reg_or_mem_ref_op,
> - cmovns_dest :: gp_reg
> - )
> - % Moves if not sign (SF = 0).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovp(
> - cmovp_src :: reg_or_mem_ref_op,
> - cmovp_dest :: gp_reg
> - )
> - % Moves if parity (PF = 1).
> - % Details on amd64-prog-man-vol3 manual p102.
> -
> - ; cmovpe(
> - cmovpe_src :: reg_or_mem_ref_op,
> - cmovpe_dest :: gp_reg
> - )
> - % Moves if parity even (PF = 1).
> - % Details on amd64-prog-man-vol3 manual p103.
> -
> - ; cmovnp(
> - cmovnp_src :: reg_or_mem_ref_op,
> - cmovnp_dest :: gp_reg
> - )
> - % Moves if not parity (PF = 0).
> - % Details on amd64-prog-man-vol3 manual p103.
> -
> - ; cmovpo(
> - cmovpo_src :: reg_or_mem_ref_op,
> - cmovpo_dest :: gp_reg
> - )
> - % Moves if parity odd (PF = 0).
> - % Details on amd64-prog-man-vol3 manual p103.
> -
> - ; cmovl(
> - cmovl_src :: reg_or_mem_ref_op,
> - cmovl_dest :: gp_reg
> - )
> - % Moves if less (SF <> OF).
> - % Details on amd64-prog-man-vol3 manual p103.
> -
> - ; cmovnge(
> - cmovnge_src :: reg_or_mem_ref_op,
> - cmovnge_dest :: gp_reg
> - )
> - % Moves if not greater or equal (SF <> OF).
> - % Details on amd64-prog-man-vol3 manual p103.
> -
> - ; cmovnl(
> - cmovnl_src :: reg_or_mem_ref_op,
> - cmovnl_dest :: gp_reg
> - )
> - % Moves if not less (SF = OF).
> - % Details on amd64-prog-man-vol3 manual p103.
> -
> - ; cmovge(
> - cmovge_src :: reg_or_mem_ref_op,
> - cmovge_dest :: gp_reg
> - )
> - % Moves if greater or equal (SF = OF).
> - % Details on amd64-prog-man-vol3 manual p103.
> -
> - ; cmovle(
> - cmovle_src :: reg_or_mem_ref_op,
> - cmovle_dest :: gp_reg
> - )
> - % Moves if less or equal (ZF = 1 or SF <> OF).
> - % Details on amd64-prog-man-vol3 manual p103.
> -
> - ; cmovng(
> - cmovng_src :: reg_or_mem_ref_op,
> - cmovng_dest :: gp_reg
> - )
> - % Moves if not greater (ZF = 1 or SF <> OF).
> - % Details on amd64-prog-man-vol3 manual p103.
> -
> - ; cmovnle(
> - cmovnle_src :: reg_or_mem_ref_op,
> - cmovnle_dest :: gp_reg
> - )
> - % Moves if not less or equal (ZF = 0 or SF = OF).
> - % Details on amd64-prog-man-vol3 manual p103.
> -
> - ; cmovg(
> - cmovg_src :: reg_or_mem_ref_op,
> - cmovg_dest :: gp_reg
> - )
> - % Moves if greater (ZF = 0 or SF = OF).
> - % Details on amd64-prog-man-vol3 manual p103.
> + ; cmov(
> + cmov_src :: operand,
> + % memory or register
> + cmov_dest :: operand,
> + % register
> + cmov_cmp_op :: string
> + )
> + % Moves with comparison operation defined in 'cmov_cmp_op'.
> + % Valid values of 'cmov_cmp_op' are:
> + % O -> moves if overflow (OF = 1)
> + % NO -> moves if not overflow (OF = 0)
> + % B -> moves if below (CF = 1)
> + % C -> moves if carry (CF = 1)
> + % NAE -> moves if not above or equal (CF = 1)
> + % NB -> moves if not below (CF = 0)
> + % NC -> moves if not carry (CF = 0)
> + % AE -> moves if above or equal (CF = 0)
> + % Z -> moves if zero (ZF = 1)
> + % E -> moves if equal (ZF = 1)
> + % NZ -> moves if not zero (ZF = 0)
> + % NE -> moves if not equal (ZF = 0)
> + % BE -> moves if below or equal (CF = 1 or ZF = 1)
> + % NA -> moves if not above (CF = 1 or ZF = 1)
> + % NBE -> moves if not below or equal (CF = 0 or ZF = 0)
> + % A -> moves if above (CF = 1 or ZF = 0)
> + % S -> moves if sign (SF = 1)
> + % NS -> moves if not sign (SF = 0)
> + % P -> moves if parity (PF = 1)
> + % PE -> moves if parity even (PF = 1)
> + % NP -> moves if not parity (PF = 0)
> + % PO -> moves if parity odd (PF = 0)
> + % L -> moves if less (SF <> OF)
> + % NGE -> moves if not greater or equal (SF <> OF)
> + % NL -> moves if not less (SF = OF)
> + % GE -> moves if greater or equal (SF = OF)
> + % LE -> moves if less or equal (ZF = 1 or SF <> OF)
> + % NG -> moves if not greater (ZF = 1 or SF <> OF)
> + % NLE -> moves if not less or equal (ZF = 0 or SF = OF)
> + % G -> moves if greater (ZF = 0 or SF = OF)
> + % Details on amd64-prog-man-vol3 manual p(101-103).
>
> ; cmp(
> cmp_src :: operand,
> - cmp_dest :: reg_or_mem_ref_op
> + % register, memory location or immediate
> value
> + cmp_dest :: operand
> + % register or memory location
> )
> % Compares 'cmp_src' with 'cmp_dest'.
> % Details on amd64-prog-man-vol3 manual p105.
>
> ; cmpxchg(
> - cmpxchg_cmp :: reg_or_mem_ref_op,
> - cmpxchg_xchg :: gp_reg
> + cmpxchg_src :: operand,
> + % register or memory location
> + cmpxchg_dest :: operand
> + % register
> )
> - % Compares the value in RAX with the value in 'cmpxchg_cmp'.
> - % If equal, copies the value in 'cmpxchg_xchg' to
> 'cmpxchg_cmp'.
> + % Compares the value in RAX with the value in 'cmpxchg_dest'.
> + % If equal, copies the value in 'cmpxchg_src' to
> 'cmpxchg_dest'.
> % Details on amd64-prog-man-vol3 manual p111.
>
> - ; cmpxchg8b(mem_ref)
> + ; cmpxchg8b(
> + cmpxchg8b_mem :: operand
> + % memory reference
> + )
> % Compares the value in EDX:EAX with the value in 'mem_ref'.
> % Details on amd64-prog-man-vol3 manual p113.
>
> - ; dec(reg_or_mem_ref_op)
> - % Decrements the contents of 'reg_or_mem_ref_op'.
> + ; dec(
> + dec_op :: operand
> + % register or memory reference
> + )
> + % Decrements the contents of 'dec_op'.
> % Details on amd64-prog-man-vol3 manual p120.
>
> - ; div(reg_or_mem_ref_op)
> - % Unsigned divide RDX:RAX by the value in 'reg_or_mem_ref_op'.
> + ; div(
> + div_op :: operand
> + % register or memory reference
> + )
> + % Unsigned divide RDX:RAX by the value in 'div_op'.
> % Details on amd64-prog-man-vol3 manual p122.
>
> ; enter(
> @@ -1067,166 +948,87 @@
> % 'enter_nesting_level'(0 to 31).
> % Details on amd64-prog-man-vol3 manual p124.
>
> - ; idiv(reg_or_mem_ref_op)
> - % Signed divide RDX:RAX by the value in 'reg_or_mem_ref_op'.
> - % Details on amd64-prog-man-vol3 manual p126.
> -
> - ; imul(reg_or_mem_ref_op)
> - % Signed multiply RAX by the value in 'reg_or_mem_ref_op'.
> - % Details on amd64-prog-man-vol3 manual p128.
> -
> - ; imul(
> - imul1_src :: reg_or_mem_ref_op,
> - imul1_dest :: gp_reg
> + ; idiv(
> + idiv_op :: operand
> + % register or memory reference
> )
> - % Signed multiply 'imul1_src' by 'imul1_dest'.
> - % Details on amd64-prog-man-vol3 manual p129.
> + % Signed divide RDX:RAX by the value in 'operand'.
> + % Details on amd64-prog-man-vol3 manual p126.
>
> ; imul(
> - imul2_src :: reg_or_mem_ref_op,
> - imul2_multiplicand :: imm_operand,
> - imul2_dest :: gp_reg
> + imul_src :: operand,
> + % register, memory location, immediate
> value
> + imul_dest :: maybe(operand),
> + % register
> + imul_multiplicand :: maybe(operand)
> + )
> + % Signed multiply 'imul_src' by 'imul_dest' (if specified).
> + % Otherwise multiply 'imul_src' by the value in RAX register.
> + % Details on amd64-prog-man-vol3 manual p(128-129).
> +
> + ; inc(
> + inc_op :: operand
> + % register or memory location
> )
> - % Signed multiply 'imul2_src' by 'imul2_multiplicand'.
> - % Details on amd64-prog-man-vol3 manual p129.
> -
> - ; inc(reg_or_mem_ref_op)
> - % Increments the contents of 'reg_or_mem_ref_op'.
> + % Increments the contents of 'inc_op'.
> % Details on amd64-prog-man-vol3 manual p133.
>
> - ; jo(rel_offset)
> - % Jumps if overflow (OF = 1).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jno(rel_offset)
> - % Jumps if not overflow (OF = 0).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jb(rel_offset)
> - % Jumps if below (CF = 1).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jc(rel_offset)
> - % Jumps if carry (CF = 1).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jnae(rel_offset)
> - % Jumps if not above or equal (CF = 1).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jnb(rel_offset)
> - % Jumps if not below (CF = 0).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jnc(rel_offset)
> - % Jumps if not carry (CF = 0).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jae(rel_offset)
> - % Jumps if above or equal (CF = 0).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jz(rel_offset)
> - % Jumps if zero (ZF = 1).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; je(rel_offset)
> - % Jumps if equal (ZF = 1).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jnz(rel_offset)
> - % Jumps if not zero (ZF = 0).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jne(rel_offset)
> - % Jumps if not equal (ZF = 0).
> - % Details on amd64-prog-man-vol3 manual p147.
> -
> - ; jbe(rel_offset)
> - % Jumps if below or equal (CF = 1 or ZF = 1).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jna(rel_offset)
> - % Jumps if not above (CF = 1 or ZF = 1).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jnbe(rel_offset)
> - % Jumps if not below or equal (CF = 0 or ZF = 0).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; ja(rel_offset)
> - % Jumps if above (CF = 0 or ZF = 0).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; js(rel_offset)
> - % Jumps if sign (SF = 1).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jns(rel_offset)
> - % Jumps if not sign (SF = 0).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jp(rel_offset)
> - % Jumps if parity (PF = 1).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jpe(rel_offset)
> - % Jumps if parity even (PF = 1).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jnp(rel_offset)
> - % Jumps if not parity (PF = 0).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jpo(rel_offset)
> - % Jumps if parity odd (PF = 0).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jl(rel_offset)
> - % Jumps if less (SF <> OF).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jnge(rel_offset)
> - % Jumps if not greater or equal (SF <> OF).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jnl(rel_offset)
> - % Jumps if not less (SF = OF).
> - % Details on amd64-prog-man-vol3 manual p148.
> -
> - ; jge(rel_offset)
> - % Jumps if greater or equal (SF = OF).
> - % Details on amd64-prog-man-vol3 manual p149.
> -
> - ; jle(rel_offset)
> - % Jumps if less or equal (ZF = 1 or SF <> OF).
> - % Details on amd64-prog-man-vol3 manual p149.
> -
> - ; jng(rel_offset)
> - % Jumps if not greater (ZF = 1 or SF <> OF).
> - % Details on amd64-prog-man-vol3 manual p149.
> -
> - ; jnle(rel_offset)
> - % Jumps if not less or equal (ZF = 0 and SF = OF).
> - % Details on amd64-prog-man-vol3 manual p149.
> -
> - ; jg(rel_offset)
> - % Jumps if greater (ZF = 0 and SF = OF).
> - % Details on amd64-prog-man-vol3 manual p149.
> -
> - ; jrcxz(rel_offset)
> - % Jumps to the target instruction located at the specified
> 8-bit
> - % relative offset if RCX is zero.
> + ; j(
> + j_target :: operand,
> + % relative offset
> + j_condition :: string
> + )
> + % Conditional jump. Valid values of 'j_condition' are:
> + % O -> jumps if overflow (OF = 1)
> + % NO -> jumps if not overflow (OF = 0)
> + % B -> jumps if below (CF = 1)
> + % C -> jumps if carry (CF = 1)
> + % NAE -> jumps if not above or equal (CF = 1)
> + % NB -> jumps if not below (CF = 0)
> + % NC -> jumps if not carry (CF = 0)
> + % AE -> jumps if above or equal (CF = 0)
> + % Z -> jumps if zero (ZF = 1)
> + % E -> jumps if equal (ZF = 1)
> + % NZ -> jumps if not zero (ZF = 0)
> + % NE -> jumps if not equal (ZF = 0)
> + % BE -> jumps if below or equal (CF = 1 or ZF = 1)
> + % NA -> jumps if not above (CF = 1 or ZF = 1)
> + % NBE -> jumps if not below or equal (CF = 0 or ZF = 0)
> + % A -> jumps if above (CF = 0 or ZF = 0)
> + % S -> jumps if sign (SF = 1)
> + % NS -> jumps if not sign (SF = 0)
> + % P -> jumps if parity (PF = 1)
> + % PE -> jumps if parity even (PF = 1)
> + % NP -> jumps if not parity (PF = 0)
> + % PO -> jumps if parity odd (PF = 0)
> + % L -> jumps if less (SF <> OF)
> + % NGE -> jumps if not greater or equal (SF <> OF)
> + % NL -> jumps if not less (SF = OF)
> + % GE -> jumps if greater or equal (SF = OF)
> + % LE -> jumps if less or equal (ZF = 1 or SF <> OF)
> + % NG -> jumps if not greater (ZF = 1 or SF <> OF)
> + % NLE -> jumps if not less or equal (ZF = 0 and SF = OF)
> + % G -> jumps if greater (ZF = 0 and SF = OF)
> + % Details on amd64-prog-man-vol3 manual p(147-149).
> +
> + ; jrcxz(
> + jrcxz_8bit_off :: operand
> + )
> + % Jumps to the target instruction located at 'jrcxz_8bit_off'
> + % if RCX is zero.
> % Details on amd64-prog-man-vol3 manual p150.
>
> - ; jmp(rmrol)
> - % Jumps with target specified in 'rmrol': register, memory
> location,
> - % relative offset or label.
> + ; jmp(
> + jmp_op :: operand
> + )
> + % Jumps with target specified in 'jmp_op'
> % Details on amd64-prog-man-vol3 manual p152.
>
> ; lea(
> - lea_src :: mem_ref,
> - lea_dest :: gp_reg
> + lea_src :: operand,
> + % memory location
> + lea_dest :: operand
> + % register
> )
> % Stores effective address 'lea_src' into 'lea_dest'.
> % Details on amd64-prog-man-vol3 manual p163.
> @@ -1236,74 +1038,93 @@
> % Details on amd64-prog-man-vol3 manual p164.
>
> ; loop(
> - loop_rel_8bit :: rel_offset
> + loop_rel_8bit :: operand
> )
> % Decrements RCX then jump if RCX is not zero
> % Details on amd64-prog-man-vol3 manual p169.
>
> ; loope(
> - loope_rel_8bit :: rel_offset
> + loope_rel_8bit :: operand
> )
> % Decrements RCX then jump if RCX is not zero and ZF = 1.
> % Details on amd64-prog-man-vol3 manual p169.
>
> ; loopne(
> - loopne_rel_8bit :: rel_offset
> + loopne_rel_8bit :: operand
> )
> % Decrements RCX then jump if RCX is not zero and ZF = 0.
> % Details on amd64-prog-man-vol3 manual p169.
>
> ; loopnz(
> - loopnz_rel_8bit :: rel_offset
> + loopnz_rel_8bit :: operand
> )
> % Decrements RCX then jump if RCX is not zero and ZF = 0.
> % Details on amd64-prog-man-vol3 manual p170.
>
> ; loopz(
> - loopz_rel_8bit :: rel_offset
> + loopz_rel_8bit :: operand
> )
> % Decrements RCX then jump if RCX is not zero and ZF = 1.
> % Details on amd64-prog-man-vol3 manual p170.
>
> ; mov(
> mov_src :: operand,
> - mov_dest :: reg_or_mem_ref_op
> + % register, memory location or immediate
> value
> + mov_dest :: operand
> + % register or memory location
> )
> - % Copies 'mov_src' to 'mov_dest'.
> + % Copies 'mov_src' to 'mov_dest'. 'mov_dest' cannot be
> immediate op.
> % Details on amd64-prog-man-vol3 manual p173.
>
> - ; mul(reg_or_mem_ref_op)
> - % Unsigned multiply 'reg_or_mem_ref_op' by RAX.
> + ; mul(
> + mul_op :: operand
> + % register or memory location
> + )
> + % Unsigned multiply 'mul_op' by RAX.
> % Details on amd64-prog-man-vol3 manual p190.
>
> - ; neg(reg_or_mem_ref_op)
> - % Performs a two's complement negation of 'reg_or_mem_ref_op'.
> + ; neg(
> + neg_op :: operand
> + % register or memory location
> + )
> + % Performs a two's complement negation of 'operand'.
> % Details on amd64-prog-man-vol3 manual p192.
>
> ; nop
> % Increments RIP to point to next instruction.
> % Details on amd64-prog-man-vol3 manual p194.
>
> - ; not_(reg_or_mem_ref_op)
> - % Performs one's complement negation (NOT) of
> 'reg_or_mem_ref_op'.
> + ; x86_64_instr_not(
> + not_op :: operand
> + % register or memory location
> + )
> + % Performs one's complement negation (NOT) of 'operand'.
> % Details on amd64-prog-man-vol3 manual p195.
>
> ; or(
> or_src :: operand,
> - or_dest :: reg_or_mem_ref_op
> + % register, memory location or immediate
> value
> + or_dest :: operand
> + % register or memory location
> )
> % Performs a logical OR on the bits in 'or_src' and 'or_dest'.
> % Details on amd64-prog-man-vol3 manual p196.
>
> - ; pop(reg_or_mem_ref_op)
> - % Pops the stack into 'reg_or_mem_ref_op'.
> + ; pop(
> + pop_op :: operand
> + % register or memory location.
> + )
> + % Pops the stack into 'operand'.
> % Details on amd64-prog-man-vol3 manual p204.
>
> ; popfq
> % Pops a quadword from the stack to the RFLAGS register.
> % Details on amd64-prog-man-vol3 manual p208.
>
> - ; push(operand)
> + ; push(
> + push_op :: operand
> + % register, memory location or immediate
> value
> + )
> % Pushes the content of operand onto the stack.
> % Details on amd64-prog-man-vol3 manual p215.
>
> @@ -1311,273 +1132,142 @@
> % Pushes the RFLAGS quadword onto the stack.
> % Details on amd64-prog-man-vol3 manual p218.
>
> - ; ret
> - % Near return to the calling procedure.
> - % Details on amd64-prog-man-vol3 manual p224.
> -
> - ; rcl(
> - rcl_amount :: cl_reg_or_imm_op,
> - rcl_dest :: reg_or_mem_ref_op
> - )
> - % Rotate bits in 'rcl_dest' to the left and through the carry
> flag
> - % by the number of bit positions as specified in 'rcl_amount'.
> - % Details on amd64-prog-man-vol3 manual p220.
> -
> - ; rcr(
> - rcr_amount :: cl_reg_or_imm_op,
> - rcr_dest :: reg_or_mem_ref_op
> - )
> - % Rotate bits in 'rcr_dest' to the right and through the carry
> flag
> - % by the number of bit positions as specified in 'rcr_amount'.
> - % Details on amd64-prog-man-vol3 manual p222.
> + ; rc(
> + rc_amount :: operand,
> + % unsigned immediate value or register
> + rc_dest :: operand,
> + % register or memory location
> + rc_cond :: string
> + % "R" for right, "L" for left
> + )
> + % Rotate bits in 'rc_dest' according to 'rc_cond' direction
> + % and through the carry flag by the number of bit positions as
> + % specified in 'rc_amount'.
> + % Details on amd64-prog-man-vol3 manual p(220-222).
>
> - ; ret(uint16)
> + ; ret(
> + ret_op :: maybe(uint16)
> + )
> % Near return to the calling procedure, then pop the specified
> - % number of bytes from stack.
> + % number of bytes from stack (if specified).
> % Details on amd64-prog-man-vol3 manual p224.
>
> - ; rol(
> - rol_amount :: cl_reg_or_imm_op,
> - rol_dest :: reg_or_mem_ref_op
> - )
> - % Rotates the bits of 'rol_dest' left by 'rol_amount' bits.
> - % Details on amd64-prog-man-vol3 manual p230.
> -
> - ; ror(
> - ror_amount :: cl_reg_or_imm_op,
> - ror_dest :: reg_or_mem_ref_op
> - )
> - % Rotates the bits of 'ror_dest' right by 'ror_amount bits'.
> - % Details on amd64-prog-man-vol3 manual p232.
> + ; ro(
> + ro_amount :: operand,
> + % unsigned immediate value or a register
> + ro_dest :: operand,
> + % register or memory location
> + ro_dir :: string
> + % "L" for left, "R" for right
> + )
> + % Rotates the bits of 'rol_dest' to the 'ro_dir' direction by
> + % 'rol_amount' bits.
> + % Details on amd64-prog-man-vol3 manual p(230-232).
>
> ; sal(
> - sal_amount :: cl_reg_or_imm_op,
> - sal_dest :: reg_or_mem_ref_op
> + sal_amount :: operand,
> + % unsigned immediate value or register
> + sal_dest :: operand
> + % register or memory location
> )
> % Shift 'sal_dest' left by 'sal_amount'.
> % Details on amd64-prog-man-vol3 manual p235.
>
> ; shl(
> - shl_amount :: cl_reg_or_imm_op,
> - shl_dest :: reg_or_mem_ref_op
> + shl_amount :: operand,
> + % unsigned immediate value or register
> + shl_dest :: operand
> + % register or memory location
> )
> - % Shift 'shl_dest' left by 'shl_amount'.
> + % Alias to 'sal'.
> % Details on amd64-prog-man-vol3 manual p235.
>
> ; sar(
> - sar_amount :: cl_reg_or_imm_op,
> - sar_dest :: reg_or_mem_ref_op
> + sar_amount :: operand,
> + % unsigned immediate value or register
> + sar_dest :: operand
> + % register or memory location
> )
> % Shift 'sar_dest' right by 'sar_amount'.
> % Details on amd64-prog-man-vol3 manual p238.
>
> ; sbb(
> sbb_src :: operand,
> - sbb_dest :: reg_or_mem_ref_op
> + % immediate value, register or memory
> location
> + sbb_dest :: operand
> + % register or memory location
> )
> % Subtracts 'sbb_src' from 'sbb_dest' with borrow.
> % Details on amd64-prog-man-vol3 manual p241.
>
> - ; seto(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If overflow
> - % (OF = 1), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; setno(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If not overflow
> - % (OF = 0), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; setb(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If flag is
> below
> - % (CF = 1), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> -
> - ; setc(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If flag is
> carry
> - % (CF = 1), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; setnae(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If flag is not
> above
> - % or equal (CF = 1), set the value in the specified register
> or an
> - % 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; setnb(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If flag is not
> below
> - % (CF = 0), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; setnc(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If flag is not
> carry
> - % (CF = 0), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; setae(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If flag is
> above or
> - % equal (CF = 0), set the value in the specified register or an
> - % 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; setz(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If zero (ZF =
> 1),
> - % set the value in the specified register or an 8-bit memory
> - % reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; sete(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If equal (ZF =
> 1),
> - % set the value in the specified register or an 8-bit memory
> - % reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; setnz(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If not zero
> - % (ZF = 0), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; setne(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If not equal
> - % (ZF = 0), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p246.
> -
> - ; setbe(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If below or
> equal
> - % (CF = 1 or ZF = 1), set the value in the specified register
> or
> - % an 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setna(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If not above
> - % (CF = 1 or ZF = 1), set the value in the specified register
> or
> - % an 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setnbe(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If not below or
> - % equal (CF = 0 and ZF = 0), set the value in the specified
> - % register or an 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; seta(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If above
> - % (CF = 0 and ZF = 0), set the value in the specified
> - % register or an 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; sets(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If flag is
> sign,
> - % (SF = 1), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setns(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If flag is not
> sign,
> - % (SF = 0), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setp(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If flag is
> parity
> - % (PF = 1), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setpe(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If parity even,
> - % (PF = 1), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setnp(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If not parity,
> - % (PF = 0), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setpo(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If parity odd,
> - % (PF = 0), set the value in the specified register or an 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setl(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If less (SF <>
> OF),
> - % set the value in the specified register or an 8-bit memory
> - % reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setnge(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If not greater
> or
> - % equal (SF <> OF), set the value in the specified register or
> an
> - % 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setnl(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If not less
> - % (SF = OF), set the value in the specified register or an
> 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setge(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If greater or
> equal
> - % (SF = OF), set the value in the specified register or an
> 8-bit
> - % memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setle(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If less or
> equal
> - % (ZF = 1 or SF <> OF), set the value in the specified
> register or
> - % an 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setng(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If not greater
> - % (ZF = 1 or SF <> OF), set the value in the specified
> register or
> - % an 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setnle(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If not less or
> equal
> - % (ZF = 0 and SF = OF), set the value in the specified
> register or
> - % an 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> -
> - ; setg(reg_or_mem_ref_op)
> - % Check the status flag in the RFLAGS register. If greater
> - % (ZF = 0 and SF = OF), set the value in the specified
> register or
> - % an 8-bit memory reference to 1.
> - % Details on amd64-prog-man-vol3 manual p247.
> + ; set(
> + set_dest :: operand,
> + % register or memory location
> + set_cond :: string
> + )
> + % Check the status flag in the RFLAGS register. Set the value
> in
> + % the specified register/8-bit memory reference in 'set_dest'
> to 1
> + % according to the 'set_cond'. Valid vales of 'set_cond' are:
> + % O -> set if overflow (OF = 1)
> + % NO -> set if not overflow (OF = 0)
> + % B -> set if below (CF = 1)
> + % C -> set if carry (CF = 1)
> + % NAE -> set if not above or equal (CF = 1)
> + % NB -> set if not below (CF = 0)
> + % NC -> set if not carry (CF = 0)
> + % AE -> set if above or equal (CF = 0)
> + % Z -> set if zero (ZF = 1)
> + % E -> set if equal (ZF = 1)
> + % NZ -> set if not zero (ZF = 0)
> + % NE -> set if not equal (ZF = 0)
> + % BE -> set if below or equal(CF = 1 or ZF = 1)
> + % NA -> set if not above (CF = 1 or ZF = 1)
> + % NBE -> set if not below or equal(CF = 0 and ZF = 0)
> + % A -> set if above (CF = 0 and ZF = 0)
> + % S -> set if sign (SF = 1)
> + % NS -> set if sign (SF = 0)
> + % P -> set if parity (PF = 1)
> + % PE -> set if parity even (PF = 1)
> + % NP -> set if not parity (PF = 0)
> + % PO -> set if parity odd (PF = 0)
> + % L -> set if less (SF <> OF)
> + % NGE -> set if not greater or equal (SF <> OF)
> + % NL -> set if not less (SF = OF)
> + % GE -> set if greater or equal (SF = OF)
> + % LE -> set if less or equal (ZF = 1 or SF <> OF)
> + % NG -> set if not greater (ZF = 1 or SF <> OF)
> + % NLE -> set if not less or equal (ZF = 0 and SF = OF)
> + % G -> set if greater (ZF = 0 and SF = OF)
> + % Details on amd64-prog-man-vol3 manual p(246-247).
>
> ; shld(
> - shld_amount :: cl_reg_or_imm_op,
> - shld_dest1 :: reg_or_mem_ref_op,
> - shld_dest2 :: gp_reg
> + shld_amount :: operand,
> + % register or immediate value
> + shld_dest1 :: operand,
> + % register or memory location
> + shld_dest2 :: operand
> + % register
> )
> % Shift 'shld_dest1' to the left by 'shld_amount' and shift in
> a bit
> % pattern in 'shld_dest2' from the right.
> % Details on amd64-prog-man-vol3 manual p251.
>
> ; shr(
> - shr_amount :: cl_reg_or_imm_op,
> - shr_dest :: reg_or_mem_ref_op
> + shr_amount :: operand,
> + % register or immediate value
> + shr_dest :: operand
> + % register or memory location
> )
> % Shift 'shr_dest' right by 'shr_amount'.
> % Details on amd64-prog-man-vol3 manual p253.
>
> ; shrd(
> - shrd_amount :: cl_reg_or_imm_op,
> - shrd_dest1 :: reg_or_mem_ref_op,
> - shrd_dest2 :: gp_reg
> + shrd_amount :: operand,
> + % register or immediate value
> + shrd_dest1 :: operand,
> + % register or memory location
> + shrd_dest2 :: operand
> + % register
> )
> % Shift 'shrd_dest1' to the right by 'shrd_amount' and shift in
> % a bit pattern in 'shrd_dest2' from the left.
> @@ -1593,39 +1283,62 @@
>
> ; sub(
> sub_src :: operand,
> - sub_dest :: reg_or_mem_ref_op
> + % imm value, register or memory
> location
> + sub_dest :: operand
> + % register or memory location
> )
> % Subtracts 'sub_src' from 'sub_dest'.
> % Details on amd64-prog-man-vol3 manual p261.
>
> ; test(
> - test_src1 :: reg_or_mem_ref_op,
> - test_src2 :: reg_or_imm_op
> + test_src1 :: operand,
> + % imm value or register
> + test_src2 :: operand
> + % register or memory location
> )
> % Performs a bitwise AND on 'test_src1' and 'test_src2'.
> % Details on amd64-prog-man-vol3 manual p264.
>
> ; xadd(
> - xadd_src :: gp_reg,
> - xadd_dest :: reg_or_mem_ref_op
> + xadd_src :: operand,
> + % register
> + xadd_dest :: operand
> + % register or memory location
> )
> % Exchanges the contents of 'xadd_src' with 'xadd_dest', load
> % their sum into 'xadd_dest'.
> % Details on amd64-prog-man-vol3 manual p266.
>
> ; xchg(
> - xchg_src1 :: reg_or_mem_ref_op,
> - xchg_src2 :: reg_or_mem_ref_op
> + xchg_src1 :: operand,
> + % register or memory location
> + xchg_src2 :: operand
> + % register or memory location
> )
> % Exchanges the contents of 'xchg_src1' and 'xchg_src2'.
> % Details on amd64-prog-man-vol3 manual p268.
>
> ; xor(
> xor_src :: operand,
> - xor_dest :: reg_or_mem_ref_op
> + xor_dest :: operand
> ).
> % Performs a bitwise XOR on 'xor_src' with 'xor_dest' and
> stores
> % the result in xor_dest.
> % Details on amd64-prog-man-vol3 manual p272.
>
>
> %-----------------------------------------------------------------------------%
> +%-----------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +init_x86_64_module(CModule) = x86_64_module(CModule, []).
> +
> +init_x86_64_proc(CProc) =
> + x86_64_procedure(CProc ^ cproc_name, CProc ^ cproc_orig_arity,
> + CProc ^ cproc_id, CProc ^ cproc_code_model, [],
> + CProc ^ cproc_proc_label, CProc ^ cproc_label_nums,
> + CProc ^ cproc_may_alter_rtti, CProc ^ cproc_c_global_vars).
> +
> +init_x86_64_instruction = x86_64_instr([], "").
> +
> +%-----------------------------------------------------------------------------%
> Index: compiler/x86_64_out.m
> ===================================================================
> RCS file:
> /home/mercury/mercury1/repository/mercury/compiler/x86_64_out.m,v
> retrieving revision 1.1
> diff -u -r1.1 x86_64_out.m
> --- compiler/x86_64_out.m 15 Jan 2007 22:49:41 -0000 1.1
> +++ compiler/x86_64_out.m 31 Jan 2007 22:25:37 -0000
> @@ -22,7 +22,10 @@
>
>
> %-----------------------------------------------------------------------------%
>
> -:- pred output_x86_64_instrs(x86_64_instr::in, io::di, io::uo) is det.
> +:- pred output_x86_64_instruction(x86_64_instruction::in,
> + io::di, io::uo) is det.
> +
> +:- pred operand_type(operand::in, string::out) is det.
>
> % XXX This is just for testing purposes.
> %
> @@ -43,105 +46,6 @@
> :- import_module type_desc.
>
>
> %-----------------------------------------------------------------------------%
> -
> - % XXX This is just for testing purposes.
> - %
> -% pretend_main(!IO) :-
> -% Comment1 = comment("This is a comment"),
> -% Label1 = label(".L1"),
> -% PseudoOps1 = [
> -% abort,
> -% align(6, no, yes(2)),
> -% align(7, yes(12), no),
> -% align(8, no, no),
> -% ascii([".LI", ".L2"]),
> -% comm(".L3", 8, no),
> -% section(".data", no, no, no)
> -% ],
> -% Instrs1 = [
> -% x86_64_instr(adc(operand_reg(rax),
> -% rmro_reg(rbx)
> -% ), ""),
> -% x86_64_instr(add(operand_imm(imm8(int8(0x178))),
> -% rmro_mem_ref(mem_abs(base_reg(0, r8)))
> -% ), ""),
> -% x86_64_instr(and(operand_reg(rdx),
> -% rmro_mem_ref(mem_abs(base_reg(2, rdx)))
> -% ), ""),
> -% x86_64_instr(bsf(rmro_reg(r8), r15), ""),
> -% x86_64_instr(bsr(rmro_reg(rcx), rax), ""),
> -% x86_64_instr(bswap(r10), ""),
> -% x86_64_instr(bt(rmro_mem_ref(mem_rip(rip_expr(".L1"))),
> -% rio_reg(rsi)), ""),
> -% x86_64_instr(btc(rmro_reg(rdi), rio_imm(imm16(int16(0x1822)))),
> ""),
> -% x86_64_instr(btr(rmro_reg(rbp),
> -% rio_imm(imm32(int32(0x182199)))), ""),
> -% x86_64_instr(call(rmrol_rel_offset(ro8(int8(127)))), "comment"),
> -% x86_64_instr(cmovo(rmro_mem_ref(mem_rip(rip_constant(int32(2)))),
> -% r11), ""),
> -% x86_64_instr(mov(operand_imm(imm32(int32(10))), rmro_reg(rbx)),
> ""),
> -% x86_64_instr(or(operand_mem_ref(mem_rip(rip_constant(int32(2)))),
> -% rmro_reg(rcx)), ""),
> -% x86_64_instr(push(operand_mem_ref(mem_abs(base_expr(".L2")))),
> ""),
> -% x86_64_instr(rol(crio_reg_cl(rcx), rmro_reg(rax)), ""),
> -% x86_64_instr(ror(crio_imm8(int8(20)), rmro_mem_ref(mem_rip(
> -% rip_expr(".L2")) )), ""),
> -% x86_64_instr(sbb(operand_mem_ref(mem_rip(rip_expr(".L1"))),
> -% rmro_reg(r11)), "")
> -% ],
> -%
> -% Label2 = label(".L2"),
> -% PseudoOps2 = [
> -% section(".rodata", yes("aMS"), yes("@progbits"), yes(1)),
> -% p2align(1,no,yes(7)),
> -% type_("Type", "@function")
> -% ],
> -% Instrs2 = [
> -% x86_64_instr(loop(ro8(int8(19))), "another comment"),
> -% x86_64_instr(xor(operand_imm(imm32(int32(19))),
> -% rmro_mem_ref(mem_rip(rip_expr(".L4")))
> -% ), "comment"),
> -% x86_64_instr(jo(ro8(int8(22))), "comment again"),
> -% x86_64_instr(div(rmro_reg(rdx)), "comment div"),
> -% x86_64_instr(jmp(rmrol_label(".L2")), "comment jmp"),
> -% x86_64_instr(mov(operand_mem_ref(mem_abs(base_expr(".L3"))),
> -% rmro_reg(rbx)), "")
> -% ],
> -%
> -% Instructions = [
> -% comment(""), label(""), directives([file("x86_64_out.m")]),
> -% instrs([]),
> -% Comment1, Label1, directives(PseudoOps1), instrs(Instrs1),
> -% comment("Comment"), Label2, directives(PseudoOps2),
> -% instrs(Instrs2)
> -% ],
> -% list.foldl(output_x86_64_instrs, Instructions, !IO).
> -
> -%-----------------------------------------------------------------------------%
> -
> - % Output x86_64 instructions including comments, labels and
> pseudo-ops.
> - %
> -output_x86_64_instrs(comment(Comment), !IO) :-
> - ( string.length(Comment) > 0 ->
> - io.write_string("# " ++ Comment ++ "\n", !IO)
> - ;
> - true
> - ).
> -output_x86_64_instrs(label(LabelName), !IO) :-
> - ( string.length(LabelName) > 0 ->
> - io.write_string(LabelName ++ ":\n", !IO)
> - ;
> - true
> - ).
> -output_x86_64_instrs(directives(PseudoOps), !IO) :-
> - list.foldl(output_x86_64_pseudo_op, PseudoOps, !IO).
> -output_x86_64_instrs(instrs(Instrs), !IO) :-
> - ( list.length(Instrs) > 0 ->
> - output_x86_64_instr_and_comment(Instrs, !IO)
> - ;
> - true
> - ).
> -
>
> %-----------------------------------------------------------------------------%
> %
> % Output x86_64 pseudo-op.
> @@ -191,7 +95,7 @@
> output_pseudo_op_float_args(".double", NumList, !IO).
> output_x86_64_pseudo_op(eject, !IO) :-
> io.write_string("\t.eject\n", !IO).
> -output_x86_64_pseudo_op(else_, !IO) :-
> +output_x86_64_pseudo_op(x86_64_pseudo_else, !IO) :-
> io.write_string("\t.else\n", !IO).
> output_x86_64_pseudo_op(elseif, !IO) :-
> io.write_string("\t.elseif\n", !IO).
> @@ -235,7 +139,7 @@
> output_pseudo_op_str_args(".hword", ExprList, !IO).
> output_x86_64_pseudo_op(ident, !IO) :-
> io.write_string("\t.ident\n", !IO).
> -output_x86_64_pseudo_op(if_(Expr), !IO) :-
> +output_x86_64_pseudo_op(x86_64_pseudo_if(Expr), !IO) :-
> io.write_string("\t.if\t" ++ Expr ++ "\n", !IO).
> output_x86_64_pseudo_op(ifdef(Symbol), !IO) :-
> io.write_string("\t.ifdef\t" ++ Symbol ++ "\n", !IO).
> @@ -377,7 +281,7 @@
> io.write_string("\n", !IO).
> output_x86_64_pseudo_op(title(Heading), !IO) :-
> io.write_string("\t.title\t" ++ Heading ++ "\n", !IO).
> -output_x86_64_pseudo_op(type_(Name, Desc), !IO) :-
> +output_x86_64_pseudo_op(x86_64_pseudo_type(Name, Desc), !IO) :-
> ( check_pseudo_type_desc(Desc) ->
> io.write_string("\t.type\t" ++ Name ++ "," ++ Desc ++ "\n", !IO)
> ;
> @@ -463,7 +367,7 @@
>
> pseudo_op_str_args_while([], !IO).
> pseudo_op_str_args_while([Arg | Args], !IO) :-
> - io.write_string(Arg, !IO),
> + io.write_string(string.word_wrap("\"" ++ Arg ++ "\"", 68), !IO),
> (
> Args = [],
> pseudo_op_str_args_while(Args, !IO)
> @@ -472,7 +376,7 @@
> io.write_string(",", !IO),
> pseudo_op_str_args_while(Args, !IO)
> ).
> -
> +
> % Check if FLAGS and TYPE argument of '.section' pseudo-op is valid
> %
> :- pred check_section_flags_and_type(string::in, maybe(string)::in,
> @@ -549,134 +453,177 @@
> % Output x86_64 instructions.
> %
>
> -:- pred output_x86_64_instr_and_comment(list(x86_64_instruction)::in,
> io::di,
> - io::uo) is det.
> -
> -output_x86_64_instr_and_comment([], !IO).
> -output_x86_64_instr_and_comment([Instr | Instrs], !IO) :-
> - Instr = x86_64_instr(InstrName, Comment),
> - output_x86_64_instr(InstrName, !IO),
> + % Output x86_64 instruction and comment.
> + %
> +output_x86_64_instruction(x86_64_instr(Instr, Comment), !IO) :-
> output_comment(Comment, !IO),
> - output_x86_64_instr_and_comment(Instrs, !IO).
> + output_x86_64_instr_list(Instr, !IO),
> + io.write_string("\n", !IO).
>
> - % Output x86_64 instruction and its operands (if any).
> +:- pred output_x86_64_instr_list(list(x86_64_instr)::in, io::di, io::uo)
> is det.
> +
> +output_x86_64_instr_list([], !IO).
> +output_x86_64_instr_list([Instr | Instrs], !IO) :-
> + output_x86_64_instr(Instr, !IO),
> + output_x86_64_instr_list(Instrs, !IO).
You can use folds for this list iteration idiom:
output_x86_64_instr_list(Instrs, !IO) :-
list.foldl(output_x86_64_instr, Instrs, !IO).
folds can save you typing a lot of boiler-plate.
> +
> +:- pred output_x86_64_instr(x86_64_instr::in, io::di, io::uo) is det.
> +
> +output_x86_64_instr(comment(Comment), !IO) :-
> + ( string.length(Comment) > 0 ->
> + io.write_string("\t# ", !IO),
> + ( string.length(Comment) > 68 ->
> + string.split(Comment, 68, Comment1, Comment2),
Embedding magic numbers in code is naughty! Define a constant instead.
> + io.write_string(string.word_wrap(Comment1, 68), !IO),
> + io.write_string("\n", !IO),
> + output_x86_64_instr(comment(Comment2), !IO)
> + ;
> + io.write_string(string.word_wrap(Comment, 68), !IO)
> + )
> + ;
> + true
> + ).
> +output_x86_64_instr(label(LabelName), !IO) :-
> + ( string.length(LabelName) > 0 ->
> + io.write_string("\n" ++ LabelName ++ ":", !IO)
> + ;
> + true
> + ).
> +output_x86_64_instr(directive(PseudoOp), !IO) :-
> + output_x86_64_pseudo_op(PseudoOp, !IO).
> +output_x86_64_instr(instr(Instr), !IO) :-
> + output_x86_64_inst(Instr, !IO),
> + io.write_string("\n", !IO).
> +
> +
> + % Output a single x86_64 instruction and its operands (if any).
> %
> -:- pred output_x86_64_instr(x86_64_op::in, io::di, io::uo) is det.
> +:- pred output_x86_64_inst(x86_64_inst::in, io::di, io::uo) is det.
>
> -output_x86_64_instr(adc(Src, Dest), !IO) :-
> - instr_with_op_and_rmro("adc", Src, Dest, !IO).
> -output_x86_64_instr(add(Src, Dest), !IO) :-
> - instr_with_op_and_rmro("add", Src, Dest, !IO).
> -output_x86_64_instr(and(Src, Dest), !IO) :-
> - instr_with_op_and_rmro("and", Src, Dest, !IO).
> -output_x86_64_instr(bsf(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("bsf", Src, Dest, !IO).
> -output_x86_64_instr(bsr(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("bsr", Src, Dest, !IO).
> -output_x86_64_instr(bswap(Reg), !IO) :-
> - io.write_string("\tbswap\t", !IO),
> - reg_type(Reg, RegType),
> - io.write_string(RegType ++ "\t", !IO).
> -output_x86_64_instr(bt(Src, Idx), !IO) :-
> - instr_with_rmro_and_rio("bt", Src, Idx, !IO).
> -output_x86_64_instr(btc(Src, Idx), !IO) :-
> - instr_with_rmro_and_rio("btc", Src, Idx, !IO).
> -output_x86_64_instr(btr(Src, Idx), !IO) :-
> - instr_with_rmro_and_rio("btr", Src, Idx, !IO).
> -output_x86_64_instr(bts(Src, Idx), !IO) :-
> - instr_with_rmro_and_rio("bts", Src, Idx, !IO).
> -output_x86_64_instr(call(TargetLocation), !IO) :-
> - instr_with_rmrol("call", TargetLocation, !IO).
> -output_x86_64_instr(cbw, !IO) :-
> +output_x86_64_inst(adc(Src, Dest), !IO) :-
> + output_instr_not_imm_dest("adc", Src, yes(Dest), !IO).
> +output_x86_64_inst(add(Src, Dest), !IO) :-
> + output_instr_not_imm_dest("add", Src, yes(Dest), !IO).
> +output_x86_64_inst(and(Src, Dest), !IO) :-
> + output_instr_not_imm_dest("and", Src, yes(Dest), !IO).
> +output_x86_64_inst(bs(Src, Dest, Cond), !IO) :-
> + check_operand_not_immediate(Src, Result1),
> + (
> + Result1 = yes,
> + operand_type(Src, SrcType),
> + check_operand_register(Dest, DestRes),
> + (
> + DestRes = yes,
> + CondRes = string.to_lower(Cond),
> + ( CondRes = "f" ->
> + true
> + ;
> + CondRes = "r" ->
> + true
The comment for bs(_, _, _) uses "F" and "R". I know you're using
string.to_lower here, but this is the sort of thing that can lead to
buggy code.
> + ;
> + unexpected(this_file, "output_x86_64_inst: unexpected:
> + invalid condition bs third operand")
> + ),
> + io.write_string("\tbs" ++ CondRes ++ "\t", !IO),
> + operand_type(Dest, DestType),
> + io.write_string(SrcType ++ ", " ++ DestType ++ "\t", !IO)
> + ;
> + DestRes = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected: bs
> + second operand is not a register")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected: bsf first
> operand
> + is an immediate value")
> + ).
> +output_x86_64_inst(bswap(Op), !IO) :-
> + check_operand_register(Op, Result),
> + (
> + Result = yes,
> + operand_type(Op, RegType),
> + io.write_string("\tbswap\t" ++ RegType ++ "\t\t", !IO)
> + ;
> + Result = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected: bswap
> operand is
> + not a register")
String overrun.
> + ).
> +output_x86_64_inst(bt(Src, Idx), !IO) :-
> + output_bit_test_instr("bt", Src, Idx, !IO).
> +output_x86_64_inst(btc(Src, Idx), !IO) :-
> + output_bit_test_instr("btc", Src, Idx, !IO).
> +output_x86_64_inst(btr(Src, Idx), !IO) :-
> + output_bit_test_instr("btr", Src, Idx, !IO).
> +output_x86_64_inst(bts(Src, Idx), !IO) :-
> + output_bit_test_instr("bts", Src, Idx, !IO).
> +output_x86_64_inst(call(Target), !IO) :-
> + check_operand_not_immediate(Target, Result),
> + (
> + Result = yes,
> + operand_type(Target, TargetType),
> + io.write_string("\tcall\t" ++ TargetType ++ "\t\t", !IO)
> + ;
> + Result = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected call
> operand")
> + ).
> +output_x86_64_inst(cbw, !IO) :-
> io.write_string("\tcbw\t", !IO).
> -output_x86_64_instr(cwde, !IO) :-
> +output_x86_64_inst(cwde, !IO) :-
> io.write_string("\tcwde\t", !IO).
> -output_x86_64_instr(cdqe, !IO) :-
> +output_x86_64_inst(cdqe, !IO) :-
> io.write_string("\tcdqe\t", !IO).
> -output_x86_64_instr(cwd, !IO) :-
> +output_x86_64_inst(cwd, !IO) :-
> io.write_string("\tcwd\t", !IO).
> -output_x86_64_instr(cdq, !IO) :-
> +output_x86_64_inst(cdq, !IO) :-
> io.write_string("\tcdq\t", !IO).
> -output_x86_64_instr(cqo, !IO) :-
> +output_x86_64_inst(cqo, !IO) :-
> io.write_string("\tcqo\t", !IO).
> -output_x86_64_instr(clc, !IO) :-
> +output_x86_64_inst(clc, !IO) :-
> io.write_string("\tclc\t", !IO).
> -output_x86_64_instr(cld, !IO) :-
> +output_x86_64_inst(cld, !IO) :-
> io.write_string("\tcld\t", !IO).
> -output_x86_64_instr(cmc, !IO) :-
> +output_x86_64_inst(cmc, !IO) :-
> io.write_string("\tcmc\t", !IO).
> -output_x86_64_instr(cmovo(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovo", Src, Dest, !IO).
> -output_x86_64_instr(cmovno(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovno", Src, Dest, !IO).
> -output_x86_64_instr(cmovb(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovb", Src, Dest, !IO).
> -output_x86_64_instr(cmovc(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovc", Src, Dest, !IO).
> -output_x86_64_instr(cmovnae(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovnae", Src, Dest, !IO).
> -output_x86_64_instr(cmovnb(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovnb", Src, Dest, !IO).
> -output_x86_64_instr(cmovnc(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovnc", Src, Dest, !IO).
> -output_x86_64_instr(cmovae(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovae", Src, Dest, !IO).
> -output_x86_64_instr(cmovz(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovz", Src, Dest, !IO).
> -output_x86_64_instr(cmove(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmove", Src, Dest, !IO).
> -output_x86_64_instr(cmovnz(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovnz", Src, Dest, !IO).
> -output_x86_64_instr(cmovne(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovne", Src, Dest, !IO).
> -output_x86_64_instr(cmovbe(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovbe", Src, Dest, !IO).
> -output_x86_64_instr(cmovna(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovna", Src, Dest, !IO).
> -output_x86_64_instr(cmovnbe(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovnbe", Src, Dest, !IO).
> -output_x86_64_instr(cmova(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmova", Src, Dest, !IO).
> -output_x86_64_instr(cmovs(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovs", Src, Dest, !IO).
> -output_x86_64_instr(cmovns(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovns", Src, Dest, !IO).
> -output_x86_64_instr(cmovp(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovp", Src, Dest, !IO).
> -output_x86_64_instr(cmovpe(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovpe", Src, Dest, !IO).
> -output_x86_64_instr(cmovnp(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovnp", Src, Dest, !IO).
> -output_x86_64_instr(cmovpo(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovpo", Src, Dest, !IO).
> -output_x86_64_instr(cmovl(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovl", Src, Dest, !IO).
> -output_x86_64_instr(cmovnge(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovnge", Src, Dest, !IO).
> -output_x86_64_instr(cmovnl(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovnl", Src, Dest, !IO).
> -output_x86_64_instr(cmovge(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovge", Src, Dest, !IO).
> -output_x86_64_instr(cmovle(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovle", Src, Dest, !IO).
> -output_x86_64_instr(cmovng(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovng", Src, Dest, !IO).
> -output_x86_64_instr(cmovnle(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovnle", Src, Dest, !IO).
> -output_x86_64_instr(cmovg(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("cmovg", Src, Dest, !IO).
> -output_x86_64_instr(cmp(Src, Dest), !IO) :-
> - instr_with_op_and_rmro("cmp", Src, Dest, !IO).
> -output_x86_64_instr(cmpxchg(Cmp, Xchg), !IO) :-
> - instr_with_rmro_and_reg("cmpxchg", Cmp, Xchg, !IO).
> -output_x86_64_instr(cmpxchg8b(MemRef), !IO) :-
> - mem_ref_type(MemRef, MemRefType),
> - io.write_string("\tcmpxchg8b" ++ MemRefType, !IO).
> -output_x86_64_instr(dec(RegOrMemRef), !IO) :-
> - instr_with_rmro("dec", RegOrMemRef, !IO).
> -output_x86_64_instr(div(RegOrMemRef), !IO) :-
> - instr_with_rmro("div", RegOrMemRef, !IO).
> -output_x86_64_instr(enter(StackSize, NestingLevel), !IO) :-
> +output_x86_64_inst(cmov(Src, Dest, Cond), !IO) :-
> + output_instr_with_condition("cmov", Src, yes(Dest), Cond, !IO).
> +output_x86_64_inst(cmp(Src, Dest), !IO) :-
> + output_instr_not_imm_dest("cmp", Src, yes(Dest), !IO).
> +output_x86_64_inst(cmpxchg(Src, Dest), !IO) :-
> + check_operand_not_immediate(Src, Result1),
> + (
> + Result1 = yes,
> + check_operand_register(Dest, Result2),
> + (
> + Result2 = yes,
> + operand_type(Src, Op1),
> + operand_type(Dest, Op2),
> + io.write_string("\tcmp\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected:
> + second operand xmpxchg is a register")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected:
> + first operand is an immediate value")
> + ).
> +output_x86_64_inst(cmpxchg8b(Op), !IO) :-
> + check_operand_not_mem_ref(Op, Result),
> + (
> + Result = no,
> + operand_type(Op, OpType),
> + io.write_string("\tcmpxchg8b" ++ OpType, !IO)
> + ;
> + Result = yes,
> + unexpected(this_file, "output_x86_64_instr: unexpected:
> + operand is not a memory reference")
> + ).
> +output_x86_64_inst(dec(Operand), !IO) :-
> + output_instr_not_imm_dest("dec", Operand, no, !IO).
> +output_x86_64_inst(div(Operand), !IO) :-
> + output_instr_not_imm_dest("div", Operand, no, !IO).
> +output_x86_64_inst(enter(StackSize, NestingLevel), !IO) :-
> StackSize = uint16(Size),
> NestingLevel = uint8(Level),
> check_unsigned_int_size(16, Size, Result0),
> @@ -693,231 +640,381 @@
> ;
> unexpected(this_file, "output_x86_64_instr: enter unexpected")
> ).
> -output_x86_64_instr(idiv(RegOrMemRef), !IO) :-
> - instr_with_rmro("idiv", RegOrMemRef, !IO).
> -output_x86_64_instr(imul(RegOrMemRef), !IO) :-
> - instr_with_rmro("idiv", RegOrMemRef, !IO).
> -output_x86_64_instr(imul(Src, Dest), !IO) :-
> - instr_with_rmro_and_reg("imul", Src, Dest, !IO).
> -output_x86_64_instr(imul(RegOrMemRefOp, Imm, Reg), !IO) :-
> - io.write_string("\timul\t", !IO),
> - rmro_type(RegOrMemRefOp, Type),
> - io.write_string(Type ++ ", ", !IO),
> - imm_op_type(Imm, ImmVal),
> - io.write_string(ImmVal ++ ", ", !IO),
> - reg_type(Reg, RegType),
> - io.write_string(RegType ++ "\t", !IO).
> -output_x86_64_instr(inc(RegOrMemRef), !IO) :-
> - instr_with_rmro("inc", RegOrMemRef, !IO).
> -output_x86_64_instr(jo(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jo", RelOffset, !IO).
> -output_x86_64_instr(jno(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jno", RelOffset, !IO).
> -output_x86_64_instr(jb(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jb", RelOffset, !IO).
> -output_x86_64_instr(jc(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jc", RelOffset, !IO).
> -output_x86_64_instr(jnae(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jnae", RelOffset, !IO).
> -output_x86_64_instr(jnb(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jnb", RelOffset, !IO).
> -output_x86_64_instr(jnc(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jnc", RelOffset, !IO).
> -output_x86_64_instr(jae(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jae", RelOffset, !IO).
> -output_x86_64_instr(jz(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jz", RelOffset, !IO).
> -output_x86_64_instr(je(RelOffset), !IO) :-
> - instr_with_rel_offset_op("je", RelOffset, !IO).
> -output_x86_64_instr(jnz(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jnz", RelOffset, !IO).
> -output_x86_64_instr(jne(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jne", RelOffset, !IO).
> -output_x86_64_instr(jbe(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jbe", RelOffset, !IO).
> -output_x86_64_instr(jna(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jna", RelOffset, !IO).
> -output_x86_64_instr(jnbe(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jnbe", RelOffset, !IO).
> -output_x86_64_instr(ja(RelOffset), !IO) :-
> - instr_with_rel_offset_op("ja", RelOffset, !IO).
> -output_x86_64_instr(js(RelOffset), !IO) :-
> - instr_with_rel_offset_op("js", RelOffset, !IO).
> -output_x86_64_instr(jns(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jns", RelOffset, !IO).
> -output_x86_64_instr(jp(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jp", RelOffset, !IO).
> -output_x86_64_instr(jpe(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jpe", RelOffset, !IO).
> -output_x86_64_instr(jnp(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jnp", RelOffset, !IO).
> -output_x86_64_instr(jpo(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jpo", RelOffset, !IO).
> -output_x86_64_instr(jl(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jl", RelOffset, !IO).
> -output_x86_64_instr(jnge(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jnge", RelOffset, !IO).
> -output_x86_64_instr(jnl(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jnl", RelOffset, !IO).
> -output_x86_64_instr(jge(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jge", RelOffset, !IO).
> -output_x86_64_instr(jle(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jle", RelOffset, !IO).
> -output_x86_64_instr(jng(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jng", RelOffset, !IO).
> -output_x86_64_instr(jnle(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jnle", RelOffset, !IO).
> -output_x86_64_instr(jg(RelOffset), !IO) :-
> - instr_with_rel_offset_op("jg", RelOffset, !IO).
> -output_x86_64_instr(jrcxz(RelOffset), !IO) :-
> - instr_with_8bit_rel_offset_op("jrcxz", RelOffset, !IO).
> -output_x86_64_instr(jmp(Target), !IO) :-
> - instr_with_rmrol("jmp", Target, !IO).
> -output_x86_64_instr(lea(Src, Dest), !IO) :-
> - instr_with_mem_ref_and_reg_op("lea", Src, Dest, !IO).
> -output_x86_64_instr(leave, !IO) :-
> +output_x86_64_inst(idiv(Operand), !IO) :-
> + output_instr_not_imm_dest("idiv", Operand, no, !IO).
> +output_x86_64_inst(imul(Src, Dest, Mult), !IO) :-
> + operand_type(Src, SrcType),
> + io.write_string("\timul\t" ++ SrcType, !IO),
> + (
> + Dest = yes(DestRes),
> + check_operand_register(DestRes, Result1),
> + (
> + Result1 = yes,
> + operand_type(DestRes, DestType),
> + io.write_string(", " ++ DestType, !IO),
> + (
> + Mult = yes(MultRes),
> + operand_type(MultRes, Op3),
> + io.write_string(", " ++ Op3 ++ " ", !IO)
> + ;
> + Mult = no,
> + io.write_string("\t", !IO)
> + )
> + ;
> +
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected:
> + second operand is not a register")
> + )
> + ;
> + Dest = no,
> + io.write_string("\t\t", !IO)
> + ).
> +output_x86_64_inst(inc(Operand), !IO) :-
> + output_instr_not_imm_dest("inc", Operand, no, !IO).
> +output_x86_64_inst(j(Offset, Cond), !IO) :-
> + output_instr_with_condition("j", Offset, no, Cond, !IO).
> +output_x86_64_inst(jrcxz(RelOffset), !IO) :-
> + output_instr_8bit_rel_offset("jrcxz", RelOffset, !IO).
> +output_x86_64_inst(jmp(Target), !IO) :-
> + operand_type(Target, Op),
> + io.write_string("\tjmp\t" ++ Op ++ "\t\t", !IO).
> +output_x86_64_inst(lea(Src, Dest), !IO) :-
> + check_operand_not_mem_ref(Src, Result1),
> + (
> + Result1 = no,
> + check_operand_register(Dest, Result2),
> + (
> + Result2 = yes,
> + operand_type(Src, Op1),
> + operand_type(Dest, Op2),
> + io.write_string("\tlea\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_inst: unexpected:
> + second operand is not a register")
> + )
> + ;
> + Result1 = yes,
> + unexpected(this_file, "output_x86_64_inst: unexpected:
> + first operand is not a memory reference")
> + ).
> +output_x86_64_inst(leave, !IO) :-
> io.write_string("\tleave\t", !IO).
> -output_x86_64_instr(loop(RelOffset), !IO) :-
> - instr_with_8bit_rel_offset_op("loop", RelOffset, !IO).
> -output_x86_64_instr(loope(RelOffset), !IO) :-
> - instr_with_8bit_rel_offset_op("loope", RelOffset, !IO).
> -output_x86_64_instr(loopne(RelOffset), !IO) :-
> - instr_with_8bit_rel_offset_op("loopne", RelOffset, !IO).
> -output_x86_64_instr(loopnz(RelOffset), !IO) :-
> - instr_with_8bit_rel_offset_op("loopnz", RelOffset, !IO).
> -output_x86_64_instr(loopz(RelOffset), !IO) :-
> - instr_with_8bit_rel_offset_op("loopz", RelOffset, !IO).
> -output_x86_64_instr(mov(Source, Dest), !IO) :-
> - instr_with_op_and_rmro("mov", Source, Dest, !IO).
> -output_x86_64_instr(mul(RegOrMemRef), !IO) :-
> - instr_with_rmro("mul", RegOrMemRef, !IO).
> -output_x86_64_instr(neg(RegOrMemRef), !IO) :-
> - instr_with_rmro("neg", RegOrMemRef, !IO).
> -output_x86_64_instr(nop, !IO) :-
> +output_x86_64_inst(loop(RelOffset), !IO) :-
> + output_instr_8bit_rel_offset("loop", RelOffset, !IO).
> +output_x86_64_inst(loope(RelOffset), !IO) :-
> + output_instr_8bit_rel_offset("loope", RelOffset, !IO).
> +output_x86_64_inst(loopne(RelOffset), !IO) :-
> + output_instr_8bit_rel_offset("loopne", RelOffset, !IO).
> +output_x86_64_inst(loopnz(RelOffset), !IO) :-
> + output_instr_8bit_rel_offset("loopnz", RelOffset, !IO).
> +output_x86_64_inst(loopz(RelOffset), !IO) :-
> + output_instr_8bit_rel_offset("loopz", RelOffset, !IO).
> +output_x86_64_inst(mov(Src, Dest), !IO) :-
> + output_instr_not_imm_dest("mov", Src, yes(Dest), !IO).
> +output_x86_64_inst(mul(Operand), !IO) :-
> + output_instr_not_imm_dest("mul", Operand, no, !IO).
> +output_x86_64_inst(neg(Operand), !IO) :-
> + output_instr_not_imm_dest("neg", Operand, no, !IO).
> +output_x86_64_inst(nop, !IO) :-
> io.write_string("nop", !IO).
> -output_x86_64_instr(not_(RegOrMemRef), !IO) :-
> - instr_with_rmro("not", RegOrMemRef, !IO).
> -output_x86_64_instr(or(Src, Dest), !IO) :-
> - instr_with_op_and_rmro("or", Src, Dest, !IO).
> -output_x86_64_instr(pop(RegOrMemRefOp), !IO) :-
> - instr_with_rmro("pop", RegOrMemRefOp, !IO).
> -output_x86_64_instr(popfq, !IO) :-
> +output_x86_64_inst(x86_64_instr_not(Operand), !IO) :-
> + output_instr_not_imm_dest("not", Operand, no, !IO).
> +output_x86_64_inst(or(Src, Dest), !IO) :-
> + output_instr_not_imm_dest("or", Src, yes(Dest), !IO).
> +output_x86_64_inst(pop(Operand), !IO) :-
> + output_instr_not_imm_dest("pop", Operand, no, !IO).
> +output_x86_64_inst(popfq, !IO) :-
> io.write_string("\tpopfq\t", !IO).
> -output_x86_64_instr(push(Operand), !IO) :-
> +output_x86_64_inst(push(Operand), !IO) :-
> io.write_string("\tpush\t", !IO),
> operand_type(Operand, OperandType),
> io.write_string(OperandType ++ "\t", !IO).
> -output_x86_64_instr(pushfq, !IO) :-
> +output_x86_64_inst(pushfq, !IO) :-
> io.write_string("\tpushfq\t", !IO).
> -output_x86_64_instr(rcl(ClRegOrImm, RegOrMemRef), !IO) :-
> - instr_with_crio_and_rmro("rcl", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(rcr(ClRegOrImm, RegOrMemRef), !IO) :-
> - instr_with_crio_and_rmro("rcr", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(ret, !IO) :-
> - io.write_string("\tret\t", !IO).
> -output_x86_64_instr(ret(uint16(NumBytes)), !IO) :-
> - check_unsigned_int_size(16, NumBytes, Result),
> +output_x86_64_inst(rc(Amnt, Dest, Cond), !IO) :-
> + check_rc_first_operand(Amnt, Result1),
> (
> + Result1 = yes,
> + check_operand_not_immediate(Dest, Result2),
> + (
> + Result2 = yes,
> + operand_type(Amnt, Op1),
> + operand_type(Dest, Op2),
> + io.write_string("\trc\t" ++ Cond, !IO),
> + io.write_string(Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected
> + rc second operand is an immediate value")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected rc
> + first operand")
> + ).
> +output_x86_64_inst(ret(Op), !IO) :-
> + (
> + Op = yes(OpRes),
> + OpRes = uint16(NumBytes)
> + ->
> + check_unsigned_int_size(16, NumBytes, Result),
> + (
> + Result = yes,
> + io.write_string("\tret\t", !IO),
> + io.write_int(NumBytes, !IO),
> + io.write_string("\t", !IO)
> + ;
> + Result = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected ret
> + uint operand size")
> + )
> + ;
> + Op = no
> + ->
> + io.write_string("\tret\t\t", !IO)
> + ;
> + unexpected(this_file, "output_x86_64_instr: unexpected ret
> operand")
> + ).
> +output_x86_64_inst(ro(Amnt, Dest, Dir), !IO) :-
> + check_operand_not_mem_ref(Amnt, Result1),
> + (
> + Result1 = yes,
> + check_operand_not_immediate(Dest, Result2),
> + (
> + Result2 = yes,
> + operand_type(Amnt, Op1),
> + operand_type(Dest, Op2),
> + io.write_string("\tro" ++ Dir ++ "\t", !IO),
> + io.write_string(Op1 ++ ", " ++ Op2 ++ "\t\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: ro unexpected")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: ro unexpected")
> + ).
> +output_x86_64_inst(sal(Amnt, Dest), !IO) :-
> + check_operand_unsigned_imm_or_reg(Amnt, Result1),
> + (
> + Result1 = yes,
> + check_operand_not_immediate(Dest, Result2),
> + (
> + Result2 = yes,
> + operand_type(Amnt, Op1),
> + operand_type(Dest, Op2),
> + io.write_string("\tsal\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected: sal
> + second operand is an immediate value")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected: sal
> + first operand")
> + ).
> +output_x86_64_inst(shl(Amnt, Dest), !IO) :-
> + check_operand_unsigned_imm_or_reg(Amnt, Result1),
> + (
> + Result1 = yes,
> + check_operand_not_immediate(Dest, Result2),
> + (
> + Result2 = yes,
> + operand_type(Amnt, Op1),
> + operand_type(Dest, Op2),
> + io.write_string("\tshl\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected: shl
> + second operand is an immediate value")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected: shl
> + first operand")
> + ).
> +output_x86_64_inst(sar(Amnt, Dest), !IO) :-
> + check_operand_unsigned_imm_or_reg(Amnt, Result1),
> + (
> + Result1 = yes,
> + check_operand_not_immediate(Dest, Result2),
> + (
> + Result2 = yes,
> + operand_type(Amnt, Op1),
> + operand_type(Dest, Op2),
> + io.write_string("\tsar\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected: sar
> + second operand is an immediate value")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected: sar
> + first operand")
> + ).
> +output_x86_64_inst(sbb(Src, Dest), !IO) :-
> + output_instr_not_imm_dest("sbb", Src, yes(Dest), !IO).
> +output_x86_64_inst(set(Operand, Cond), !IO) :-
> + check_operand_not_immediate(Operand, Result),
> + (
> Result = yes,
> - io.write_string("\tret\t", !IO),
> - io.write_int(NumBytes, !IO),
> - io.write_string("\t", !IO)
> + output_instr_with_condition("set", Operand, no, Cond, !IO)
> ;
> Result = no,
> - unexpected(this_file, "output_x86_64_instr: ret unexpected")
> + unexpected(this_file, "output_x86_64_instr: unexpected set
> operand")
> + ).
> +output_x86_64_inst(shld(Amnt, Dest1, Reg), !IO) :-
> + check_operand_unsigned_imm_or_reg(Amnt, Result1),
> + (
> + Result1 = yes,
> + check_operand_not_immediate(Dest1, Result2),
> + (
> + Result2 = yes,
> + check_operand_register(Reg, Result3),
> + (
> + Result3 = yes,
> + operand_type(Amnt, Op1),
> + operand_type(Amnt, Op2),
> + operand_type(Amnt, Op3),
> + io.write_string("\tshld\t" ++ Op1 ++ ", ", !IO),
> + io.write_string(Op2 ++ ", " ++ Op3 ++ "\t", !IO)
> + ;
> + Result3 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected shld
> + third operand is not a register")
> + )
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected shld
> + second operand is an immediate value")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected shld
> + first operand")
> ).
> -output_x86_64_instr(rol(ClRegOrImm, RegOrMemRef), !IO) :-
> - instr_with_crio_and_rmro("rol", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(ror(ClRegOrImm, RegOrMemRef), !IO) :-
> - instr_with_crio_and_rmro("ror", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(sal(ClRegOrImm, RegOrMemRef), !IO) :-
> - instr_with_crio_and_rmro("sal", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(shl(ClRegOrImm, RegOrMemRef), !IO) :-
> - instr_with_crio_and_rmro("shl", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(sar(ClRegOrImm, RegOrMemRef), !IO) :-
> - instr_with_crio_and_rmro("sar", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(sbb(Src, Dest), !IO) :-
> - instr_with_op_and_rmro("sbb", Src, Dest, !IO).
> -output_x86_64_instr(seto(RegOrMemRef), !IO) :-
> - instr_with_rmro("seto", RegOrMemRef, !IO).
> -output_x86_64_instr(setno(RegOrMemRef), !IO) :-
> - instr_with_rmro("setno", RegOrMemRef, !IO).
> -output_x86_64_instr(setb(RegOrMemRef), !IO) :-
> - instr_with_rmro("setb", RegOrMemRef, !IO).
> -output_x86_64_instr(setc(RegOrMemRef), !IO) :-
> - instr_with_rmro("setc", RegOrMemRef, !IO).
> -output_x86_64_instr(setnae(RegOrMemRef), !IO) :-
> - instr_with_rmro("setnae", RegOrMemRef, !IO).
> -output_x86_64_instr(setnb(RegOrMemRef), !IO) :-
> - instr_with_rmro("setnb", RegOrMemRef, !IO).
> -output_x86_64_instr(setnc(RegOrMemRef), !IO) :-
> - instr_with_rmro("setnc", RegOrMemRef, !IO).
> -output_x86_64_instr(setae(RegOrMemRef), !IO) :-
> - instr_with_rmro("setae", RegOrMemRef, !IO).
> -output_x86_64_instr(setz(RegOrMemRef), !IO) :-
> - instr_with_rmro("setz", RegOrMemRef, !IO).
> -output_x86_64_instr(sete(RegOrMemRef), !IO) :-
> - instr_with_rmro("sete", RegOrMemRef, !IO).
> -output_x86_64_instr(setnz(RegOrMemRef), !IO) :-
> - instr_with_rmro("setnz", RegOrMemRef, !IO).
> -output_x86_64_instr(setne(RegOrMemRef), !IO) :-
> - instr_with_rmro("setne", RegOrMemRef, !IO).
> -output_x86_64_instr(setbe(RegOrMemRef), !IO) :-
> - instr_with_rmro("setbe", RegOrMemRef, !IO).
> -output_x86_64_instr(setna(RegOrMemRef), !IO) :-
> - instr_with_rmro("setna", RegOrMemRef, !IO).
> -output_x86_64_instr(setnbe(RegOrMemRef), !IO) :-
> - instr_with_rmro("setnbe", RegOrMemRef, !IO).
> -output_x86_64_instr(seta(RegOrMemRef), !IO) :-
> - instr_with_rmro("seta", RegOrMemRef, !IO).
> -output_x86_64_instr(sets(RegOrMemRef), !IO) :-
> - instr_with_rmro("sets", RegOrMemRef, !IO).
> -output_x86_64_instr(setns(RegOrMemRef), !IO) :-
> - instr_with_rmro("setns", RegOrMemRef, !IO).
> -output_x86_64_instr(setp(RegOrMemRef), !IO) :-
> - instr_with_rmro("setp", RegOrMemRef, !IO).
> -output_x86_64_instr(setpe(RegOrMemRef), !IO) :-
> - instr_with_rmro("setpe", RegOrMemRef, !IO).
> -output_x86_64_instr(setnp(RegOrMemRef), !IO) :-
> - instr_with_rmro("setnp", RegOrMemRef, !IO).
> -output_x86_64_instr(setpo(RegOrMemRef), !IO) :-
> - instr_with_rmro("setpo", RegOrMemRef, !IO).
> -output_x86_64_instr(setl(RegOrMemRef), !IO) :-
> - instr_with_rmro("sel", RegOrMemRef, !IO).
> -output_x86_64_instr(setnge(RegOrMemRef), !IO) :-
> - instr_with_rmro("setnge", RegOrMemRef, !IO).
> -output_x86_64_instr(setnl(RegOrMemRef), !IO) :-
> - instr_with_rmro("setnl", RegOrMemRef, !IO).
> -output_x86_64_instr(setge(RegOrMemRef), !IO) :-
> - instr_with_rmro("setge", RegOrMemRef, !IO).
> -output_x86_64_instr(setle(RegOrMemRef), !IO) :-
> - instr_with_rmro("setle", RegOrMemRef, !IO).
> -output_x86_64_instr(setng(RegOrMemRef), !IO) :-
> - instr_with_rmro("setng", RegOrMemRef, !IO).
> -output_x86_64_instr(setnle(RegOrMemRef), !IO) :-
> - instr_with_rmro("setnle", RegOrMemRef, !IO).
> -output_x86_64_instr(setg(RegOrMemRef), !IO) :-
> - instr_with_rmro("setg", RegOrMemRef, !IO).
> -output_x86_64_instr(shld(ClRegOrImm, RegOrMemRef, Reg), !IO) :-
> - instr_with_crio_rmro_and_reg("shld", ClRegOrImm, RegOrMemRef, Reg,
> !IO).
> -output_x86_64_instr(shr(ClRegOrImm, RegOrMemRef), !IO) :-
> - instr_with_crio_and_rmro("shr", ClRegOrImm, RegOrMemRef, !IO).
> -output_x86_64_instr(shrd(ClRegOrImm, RegOrMemRef, Reg), !IO) :-
> - instr_with_crio_rmro_and_reg("shrd", ClRegOrImm, RegOrMemRef, Reg,
> !IO).
> -output_x86_64_instr(stc, !IO) :-
> +output_x86_64_inst(shr(Amnt, Dest), !IO) :-
> + check_operand_unsigned_imm_or_reg(Amnt, Result1),
> + (
> + Result1 = yes,
> + check_operand_not_immediate(Dest, Result2),
> + (
> + Result2 = yes,
> + operand_type(Amnt, Op1),
> + operand_type(Dest, Op2),
> + io.write_string("\tshr\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected shr
> + second operand is an immediate value")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected shr
> + first operand")
> + ).
> +output_x86_64_inst(shrd(Amnt, Dest1, Reg), !IO) :-
> + check_operand_unsigned_imm_or_reg(Amnt, Result1),
> + (
> + Result1 = yes,
> + check_operand_not_immediate(Dest1, Result2),
> + (
> + Result2 = yes,
> + check_operand_register(Reg, Result3),
> + (
> + Result3 = yes,
> + operand_type(Amnt, Op1),
> + operand_type(Amnt, Op2),
> + operand_type(Amnt, Op3),
> + io.write_string("\tshrd\t" ++ Op1 ++ ", ", !IO),
> + io.write_string(Op2 ++ ", " ++ Op3 ++ "\t", !IO)
> + ;
> + Result3 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected shrd
> + third operand is not a register")
> + )
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected shrd
> + second operand is an immediate value")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected shrd
> + first operand")
> + ).
> +output_x86_64_inst(stc, !IO) :-
> io.write_string("\tstc\t", !IO).
> -output_x86_64_instr(std, !IO) :-
> +output_x86_64_inst(std, !IO) :-
> io.write_string("\tstd\t", !IO).
> -output_x86_64_instr(sub(Src, Dest), !IO) :-
> - instr_with_op_and_rmro("sub", Src, Dest, !IO).
> -output_x86_64_instr(test(Src1, Src2), !IO) :-
> - instr_with_rmro_and_rio("test", Src1, Src2, !IO).
> -output_x86_64_instr(xadd(Src, Dest), !IO) :-
> - instr_with_reg_and_rmro("xadd", Src, Dest, !IO).
> -output_x86_64_instr(xchg(Src1, Src2), !IO) :-
> - instr_with_rmro_and_rmro("xchg", Src1, Src2, !IO).
> -output_x86_64_instr(xor(Src, Dest), !IO) :-
> - instr_with_op_and_rmro("xor", Src, Dest, !IO).
> +output_x86_64_inst(sub(Src, Dest), !IO) :-
> + output_instr_not_imm_dest("sub", Src, yes(Dest), !IO).
> +output_x86_64_inst(test(Src1, Src2), !IO) :-
> + check_operand_not_mem_ref(Src1, Result1),
> + (
> + Result1 = yes,
> + check_operand_not_immediate(Src2, Result2),
> + (
> + Result2 = yes,
> + operand_type(Src1, Op1),
> + operand_type(Src2, Op2),
> + io.write_string("\ttest\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected
> + test second operand is an immediate value")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected
> + test first operand is a memory reference")
> + ).
> +output_x86_64_inst(xadd(Src, Dest), !IO) :-
> + check_operand_register(Src, Result1),
> + (
> + Result1 = yes,
> + check_operand_not_immediate(Dest, Result2),
> + (
> + Result2 = yes,
> + operand_type(Src, Op1),
> + operand_type(Dest, Op2),
> + io.write_string("\txadd\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected
> + xadd second operand is an immediate value")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected
> + xadd first operand is not a register")
> + ).
> +output_x86_64_inst(xchg(Src1, Src2), !IO) :-
> + check_operand_reg_or_mem(Src1, Result1),
> + (
> + Result1 = yes,
> + check_operand_reg_or_mem(Src2, Result2),
> + (
> + Result2 = yes,
> + operand_type(Src1, Op1),
> + operand_type(Src2, Op2),
> + io.write_string("\txchg\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected
> + xchg second operand")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_x86_64_instr: unexpected
> + xchg second operand")
> + ).
> +output_x86_64_inst(xor(Src, Dest), !IO) :-
> + output_instr_not_imm_dest("xor", Src, yes(Dest), !IO).
>
>
> :- pred output_comment(string::in, io::di, io::uo) is det.
> @@ -947,30 +1044,14 @@
> imm_op_type(imm32(int32(Val)), ImmVal) :-
> ImmVal = "$" ++ string.int_to_string(Val).
>
> - % Output a string representation of a general-purpose register.
> - %
> -:- pred reg_type(gp_reg::in, string::out) is det.
>
> -reg_type(rax, "%rax").
> -reg_type(rbx, "%rbx").
> -reg_type(rcx, "%rcx").
> -reg_type(rdx, "%rdx").
> -reg_type(rbp, "%rbp").
> -reg_type(rsi, "%rsi").
> -reg_type(rdi, "%rdi").
> -reg_type(rsp, "%rsp").
> -reg_type(r8, "%r8").
> -reg_type(r9, "%r9").
> -reg_type(r10, "%r10").
> -reg_type(r11, "%r11").
> -reg_type(r12, "%r12").
> -reg_type(r13, "%r13").
> -reg_type(r14, "%r14").
> -reg_type(r15, "%r15").
> +:- func reg_type(gp_reg) = string.
> +
> +reg_type(gp_reg(RegNum)) = "%r" ++ string.int_to_string(RegNum).
>
> % Output a string representation of a memory reference.
> %
> -:- pred mem_ref_type(mem_ref::in, string::out) is det.
> +:- pred mem_ref_type(x86_64_mem_ref::in, string::out) is det.
>
> mem_ref_type(mem_abs(DirectMemRef), MemRefVal) :-
> base_address_type(DirectMemRef, MemRefVal).
> @@ -982,11 +1063,10 @@
> :- pred base_address_type(base_address::in, string::out) is det.
>
> base_address_type(base_reg(Offset, Reg), BaseAddress) :-
> - reg_type(Reg, RegType),
> ( Offset = 0 ->
> - BaseAddress = "(" ++ RegType ++ ")"
> + BaseAddress = "(" ++ reg_type(Reg) ++ ")"
> ;
> - BaseAddress = string.int_to_string(Offset) ++ "(" ++ RegType ++ ")"
> + BaseAddress = string.int_to_string(Offset) ++ "(" ++ reg_type(Reg)
> ++ ")"
> ).
> base_address_type(base_expr(Expr), DispType) :-
> DispType = "$" ++ Expr.
> @@ -1051,249 +1131,303 @@
> unexpected(this_file, "rel_offset_type: ro32 unexpected")
> ).
>
> - % Output a string representation of a general operand type.
> - %
> -:- pred operand_type(operand::in, string::out) is det.
>
> operand_type(operand_reg(Reg), RegType) :-
> - reg_type(Reg, RegType).
> + RegType = reg_type(Reg).
> operand_type(operand_imm(Imm), ImmVal) :-
> imm_op_type(Imm, ImmVal).
> operand_type(operand_mem_ref(MemRef), MemRefVal) :-
> mem_ref_type(MemRef, MemRefVal).
> -
> - % Output a string representation of an operand whose type is a
> register/
> - % memory reference.
> - %
> -:- pred rmro_type(reg_or_mem_ref_op::in, string::out) is det.
> -
> -rmro_type(rmro_reg(Reg), RegType) :-
> - reg_type(Reg, RegType).
> -rmro_type(rmro_mem_ref(MemRef), MemRefVal) :-
> - mem_ref_type(MemRef, MemRefVal).
> -
> - % Output a string representation of an operand whose type is a register
> - % or an immediate value.
> - %
> -:- pred rio_type(reg_or_imm_op::in, string::out) is det.
> -
> -rio_type(rio_reg(Reg), RegType) :-
> - reg_type(Reg, RegType).
> -rio_type(rio_imm(Imm), ImmVal) :-
> - imm_op_type(Imm, ImmVal).
> -
> - % Output a string representation of an operand whose type is a cl
> register
> - % or an unsigned immediate value.
> - %
> -:- pred crio_type(cl_reg_or_imm_op::in, string::out) is det.
> -
> -crio_type(crio_reg_cl(Reg), RegType) :-
> - ( Reg = rcx ->
> - RegType = "%cl"
> - ;
> - unexpected(this_file, "crio_type: crio_reg_cl unexpected")
> - ).
> -crio_type(crio_imm8(int8(Val)), ImmVal) :-
> - check_unsigned_int_size(8, Val, Result),
> - (
> - Result = yes,
> - ImmVal = "$" ++ string.int_to_string(Val)
> - ;
> - Result = no,
> - unexpected(this_file, "crio_type: crio_imm8 unexpected")
> - ).
> -
> - % Output a string representation of an operand whose type is either
> - % a register, memory reference, signed relative offset or a label.
> - %
> -:- pred rmrol_type(rmrol::in, string::out) is det.
> -
> -rmrol_type(rmrol_reg(Reg), RegType) :-
> - reg_type(Reg, RegType).
> -rmrol_type(rmrol_mem_ref(MemRef), MemRefVal) :-
> - mem_ref_type(MemRef, MemRefVal).
> -rmrol_type(rmrol_rel_offset(RelOffset), RelOffsetVal) :-
> - rel_offset_type(RelOffset, RelOffsetVal).
> -rmrol_type(rmrol_label(LabelName), LabelOut) :-
> - LabelOut = LabelName.
> +operand_type(operand_rel_offset(RelOffset), RelOffsetType) :-
> + rel_offset_type(RelOffset, RelOffsetType).
> +operand_type(operand_label(Label), (Label)).
>
>
> %-----------------------------------------------------------------------------%
> %
> % Subsection of "Output of x86_64 instructions".
> %
>
> - % Output an instruction with a register/memory reference as an operand.
> + % Output an instruction with either one or two operand(s). If the
> second
> + % operand is present, it cannot be an immediate operand.
> %
> -:- pred instr_with_rmro(string::in, reg_or_mem_ref_op::in,
> +:- pred output_instr_not_imm_dest(string::in, operand::in,
> maybe(operand)::in,
> io::di, io::uo) is det.
>
> -instr_with_rmro(InstrName, RegOrMemRef, !IO) :-
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - rmro_type(RegOrMemRef, RegOrMemRefType),
> - io.write_string(RegOrMemRefType ++ "\t\t", !IO).
> +output_instr_not_imm_dest(Instr, Op1, Op2, !IO) :-
> + operand_type(Op1, Op1Type),
> + (
> + Op2 = yes(Op2Result),
> + check_not_both_memory_ops(Op1, Op2Result, Result1),
> + (
> + Result1 = yes,
> + operand_type(Op2Result, Op2Type),
> + check_operand_not_immediate(Op2Result, Result2),
> + (
> + Result2 = yes,
> + io.write_string("\t" ++ Instr ++ "\t", !IO),
> + io.write_string(Op1Type ++ ", " ++ Op2Type ++ "\t", !IO)
> + ;
> + Result2 = no,
> + io.write_string("\tmov\t" ++ Op2Type ++ ", %r13\t", !IO),
> + io.write_string("# move immediate to temp reg\n", !IO),
> + io.write_string("\t" ++ Instr ++ "\t", !IO),
> + io.write_string(Op1Type ++ ", " ++ "%r13\t", !IO)
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_instr_not_imm_dest: unexpected:
> both
> + operands are memory references")
> + )
> + ;
> + Op2 = no,
> + io.write_string(Op1Type ++ "\t\t", !IO)
> + ).
>
> % Output an instruction with a signed offset relative to the
> instruction
> % pointer as an operand.
> - %
> -:- pred instr_with_rel_offset_op(string::in, rel_offset::in,
> - io::di, io::uo) is det.
> -
> -instr_with_rel_offset_op(InstrName, RelOffset, !IO) :-
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - rel_offset_type(RelOffset, RelOffsetType),
> - io.write_string(RelOffsetType ++ "\t\t", !IO).
> -
> % Output an instruction with a signed 8-bit offset relative to the
> % instruction pointer as an operand.
> %
> -:- pred instr_with_8bit_rel_offset_op(string::in, rel_offset::in,
> +:- pred output_instr_8bit_rel_offset(string::in, operand::in,
> io::di, io::uo) is det.
>
> -instr_with_8bit_rel_offset_op(InstrName, RelOffset, !IO) :-
> +output_instr_8bit_rel_offset(InstrName, RelOffset, !IO) :-
> + check_operand_rel_offset(RelOffset, Result1),
> (
> - RelOffset = ro8(int8(Val)),
> - check_signed_int_size(8, Val, Result),
> - Result = yes
> - ->
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - io.write_int(Val, !IO),
> - io.write_string("\t\t", !IO)
> + Result1 = yes,
> + operand_type(RelOffset, RelOffsetType),
> + ( string.to_int(RelOffsetType, Val) ->
> + check_signed_int_size(8, Val, Result2),
> + (
> + Result2 = yes,
> + io.write_string("\t" ++ InstrName ++ "\t", !IO),
> + io.write_int(Val, !IO),
> + io.write_string("\t\t", !IO)
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_instr_8bit_rel_offset:
> + unexpected relative offset operand")
> + )
> + ;
> + unexpected(this_file, "output_instr_8bit_rel_offset:
> unexpected:
> + string.to_int")
> + )
> ;
> - unexpected(this_file, "instr_with_8bit_rel_offset_op: unexpected")
> + Result1 = no,
> + unexpected(this_file, "output_instr_8bit_rel_offset: unexpected:
> + operand not a relative offset")
> ).
>
> - % Output an instruction with either a register, memory reference,
> - % relative offset or a label as its operand.
> - %
> -:- pred instr_with_rmrol(string::in, rmrol::in, io::di, io::uo) is det.
> +:- pred output_bit_test_instr(string::in, operand::in, operand::in, io::di,
> + io::uo) is det.
> +
> +output_bit_test_instr(Instr, Src, Idx, !IO) :-
> + check_operand_not_immediate(Src, Result1),
> + (
> + Result1 = yes,
> + operand_type(Src, Op1),
> + check_operand_not_mem_ref(Idx, Result2),
> + (
> + Result2 = yes,
> + operand_type(Idx, Op2),
> + ( string.to_int(Op2, IdxInt) ->
> + check_signed_int_size(8, IdxInt, Result3),
> + (
> + Result3 = yes,
> + io.write_string("\t" ++ Instr ++ "\t", !IO),
> + io.write_string(Op1 ++ ", " ++ Op2 ++ "\t", !IO)
> + ;
> + Result3 = no,
> + unexpected(this_file, "output_bit_test_instr:
> unexpected:
> + bt second operand not 8-bit immediate value")
> + )
> + ;
> + unexpected(this_file, "output_bit_test_instr: string.to_int
> + unexpected")
> + )
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_bit_test_instr: unexpected:
> + bt second operand is a memory reference")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_bit_test_instr: unexpected: bt first
> + operand is an immediate value")
> + ).
>
> -instr_with_rmrol(InstrName, Target, !IO) :-
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - rmrol_type(Target, TargetType),
> - io.write_string(TargetType ++ "\t\t", !IO).
> +:- pred output_instr_with_condition(string::in, operand::in,
> maybe(operand)::in,
> + string::in, io::di, io::uo) is det.
>
> - % Output an instruction with a general operand and a register/memory
> - % reference as the first and second operand respectively.
> - %
> -:- pred instr_with_op_and_rmro(string::in, operand::in,
> reg_or_mem_ref_op::in,
> - io::di, io::uo) is det.
> +output_instr_with_condition(Instr, Op1, Op2, Cond, !IO) :-
> + check_operand_not_immediate(Op1, Result1),
> + (
> + Result1 = yes,
> + check_instr_condition(Cond, Result2),
> + (
> + Result2 = yes,
> + io.write_string("\t" ++ Instr, !IO),
> + io.write_string(string.to_lower(Cond) ++ "\t", !IO),
> + operand_type(Op1, Op1Type),
> + io.write_string(Op1Type, !IO),
> + (
> + Op2 = yes(Op2Res),
> + check_operand_register(Op2Res, Result3),
> + (
> + Result3 = yes,
> + operand_type(Op2Res, Op2Type),
> + io.write_string(", " ++ Op2Type, !IO)
> + ;
> + Result3 = no,
> + unexpected(this_file, "output_instr_with_condition:
> + second operand is not a register")
> + )
> + ;
> + Op2 = no,
> + io.write_string("\t\t", !IO)
> + )
> + ;
> + Result2 = no,
> + unexpected(this_file, "output_instr_with_condition:
> + condition not satisfied")
> + )
> + ;
> + Result1 = no,
> + unexpected(this_file, "output_instr_with_condition:
> + unexpected: first operand is an immediate value")
> + ).
>
> -instr_with_op_and_rmro(InstrName, SrcOperand, DestRegOrMemRefOp, !IO) :-
> - (
> - SrcOperand = operand_mem_ref(_),
> - DestRegOrMemRefOp = rmro_mem_ref(_)
> +%-----------------------------------------------------------------------------%
> +
> +:- pred check_rc_first_operand(operand::in, bool::out) is det.
> +
> +check_rc_first_operand(Op, Result) :-
> + ( Op = operand_imm(_) ->
> + operand_type(Op, OpType),
> + ( string.to_int(OpType, OpInt) ->
> + check_unsigned_int_size(8, OpInt, Result1),
> + (
> + Result1 = yes,
> + Result = yes
> + ;
> + Result1 = no,
> + Result = no
> + )
> + ;
> + unexpected(this_file, "check_rc_first_operand: string.to_int
> + unexpected")
> + )
> + ;
> + Op = operand_reg(_) ->
> + check_operand_register(Op, Result2),
> + (
> + Result2 = yes,
> + Result = yes
> + ;
> + Result2 = no,
> + Result = no
> + )
> + ;
> + unexpected(this_file, "check_rc_first_operand: unexpected")
> + ).
> +
> +:- pred check_not_both_memory_ops(operand::in, operand::in, bool::out) is
> det.
> +
> +check_not_both_memory_ops(Op1, Op2, Result) :-
> + (
> + Op1 = operand_mem_ref(_),
> + Op2 = operand_mem_ref(_)
> ->
> - % Both operands cannot be of type memory reference.
> - unexpected(this_file, "instr_with_op_and_rmro: unexpected")
> + Result = no
> ;
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - operand_type(SrcOperand, OperandType),
> - io.write_string(OperandType ++ ", ", !IO),
> - rmro_type(DestRegOrMemRefOp, DestType),
> - io.write_string(DestType ++ "\t", !IO)
> + Result = yes
> ).
>
> - % Output an instruction with a register/memory reference and a
> register as
> - % the first and second operand respectively.
> - %
> -:- pred instr_with_rmro_and_reg(string::in, reg_or_mem_ref_op::in,
> gp_reg::in,
> - io::di, io::uo) is det.
> +:- pred check_operand_not_immediate(operand::in, bool::out) is det.
>
> -instr_with_rmro_and_reg(InstrName, SrcRegOrMemRefOp, DestReg, !IO) :-
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - rmro_type(SrcRegOrMemRefOp, SrcType),
> - io.write_string(SrcType ++ ", ", !IO),
> - reg_type(DestReg, RegType),
> - io.write_string(RegType ++ "\t", !IO).
> +check_operand_not_immediate(Operand, Result) :-
> + ( Operand = operand_imm(_) ->
> + Result = no
> + ;
> + Result = yes
> + ).
>
> - % Output an instruction with a register/memory reference and a
> register/
> - % immediate value as the first and second operand respectively.
> - %
> -:- pred instr_with_rmro_and_rio(string::in, reg_or_mem_ref_op::in,
> - reg_or_imm_op::in, io::di, io::uo) is det.
> +:- pred check_operand_reg_or_mem(operand::in, bool::out) is det.
>
> -instr_with_rmro_and_rio(InstrName, SrcRegOrMemRefOp, DestRegOrImmOp, !IO)
> :-
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - rmro_type(SrcRegOrMemRefOp, SrcType),
> - io.write_string(SrcType ++ ",", !IO),
> - rio_type(DestRegOrImmOp, DestType),
> - io.write_string(DestType ++ "\t", !IO).
> +check_operand_reg_or_mem(Operand, Result) :-
> + ( Operand = operand_reg(_) ->
> + Result = yes
> + ;
> + Operand = operand_mem_ref(_) ->
> + Result = yes
> + ;
> + Result = no
> + ).
>
> - % Output an instruction with a register/memory reference as the first
> and
> - % second operand respectively.
> - %
> -:- pred instr_with_rmro_and_rmro(string::in, reg_or_mem_ref_op::in,
> - reg_or_mem_ref_op::in, io::di, io::uo) is det.
> +:- pred check_operand_unsigned_imm_or_reg(operand::in, bool::out) is det.
>
> -instr_with_rmro_and_rmro(InstrName, RegOrMemRefOp0, RegOrMemRefOp1, !IO)
> :-
> - (
> - RegOrMemRefOp0 = rmro_mem_ref(_),
> - RegOrMemRefOp1 = rmro_mem_ref(_)
> - ->
> - unexpected(this_file, "instr_with_rmro_and_rmro: unexpected")
> +check_operand_unsigned_imm_or_reg(Operand, Result) :-
> + ( Operand = operand_imm(Imm) ->
> + imm_op_type(Imm, ImmType),
> + ( string.to_int(ImmType, ImmInt) ->
> + (
> + check_unsigned_int_size(32, ImmInt, Result1),
> + (
> + Result1 = yes,
> + Result = yes
> + ;
> + Result1 = no,
> + Result = no
> + )
> + )
> + ;
> + unexpected(this_file, "check_operand_unsigned_imm_or_reg:
> + unexpected")
> + )
> ;
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - rmro_type(RegOrMemRefOp0, Type0),
> - io.write_string(Type0 ++ ", ", !IO),
> - rmro_type(RegOrMemRefOp1, Type1),
> - io.write_string(Type1 ++ "\t", !IO)
> + Result = no
> ).
>
> - % Output an instruction with a register and a register/memory
> reference as
> - % the first and second operand respectively.
> - %
> -:- pred instr_with_reg_and_rmro(string::in, gp_reg::in,
> reg_or_mem_ref_op::in,
> - io::di, io::uo) is det.
> +:- pred check_operand_register(operand::in, bool::out) is det.
>
> -instr_with_reg_and_rmro(InstrName, SrcReg, DestRegOrMemRefOp, !IO) :-
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - reg_type(SrcReg, RegType),
> - io.write_string(RegType ++ ", ", !IO),
> - rmro_type(DestRegOrMemRefOp, DestType),
> - io.write_string(DestType ++ "\t", !IO).
> +check_operand_register(Operand, Result) :-
> + ( Operand = operand_reg(_) ->
> + Result = yes
> + ;
> + Result = no
> + ).
>
> - % Output an instruction with a cl register/immediate value and a
> register/
> - % memory reference as the first and second operand respectively.
> - %
> -:- pred instr_with_crio_and_rmro(string::in, cl_reg_or_imm_op::in,
> - reg_or_mem_ref_op::in, io::di, io::uo) is det.
> +:- pred check_operand_not_mem_ref(operand::in, bool::out) is det.
>
> -instr_with_crio_and_rmro(InstrName, ClRegOrImm, RegOrMemRef, !IO) :-
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - crio_type(ClRegOrImm, ClRegOrImmType),
> - io.write_string(ClRegOrImmType ++ ", ", !IO),
> - rmro_type(RegOrMemRef, RegOrMemRefType),
> - io.write_string(RegOrMemRefType ++ "\t", !IO).
> -
> - % Output an instruction with a cl register/immediate value, a register/
> - % memory reference and a register as the first, second and third
> operand
> - % respectively.
> - %
> -:- pred instr_with_crio_rmro_and_reg(string::in, cl_reg_or_imm_op::in,
> - reg_or_mem_ref_op::in, gp_reg::in, io::di, io::uo) is det.
> +check_operand_not_mem_ref(Operand, Result) :-
> + ( Operand = operand_mem_ref(_) ->
> + Result = no
> + ;
> + Result = yes
> + ).
>
> -instr_with_crio_rmro_and_reg(InstrName, ClRegOrImm, RegOrMemRef, Reg, !IO)
> :-
> - io.write_string("\t" ++ InstrName ++ "\t", !IO),
> - crio_type(ClRegOrImm, ClRegOrImmType),
> - io.write_string(ClRegOrImmType ++ "\t", !IO),
> - rmro_type(RegOrMemRef, RegOrMemRefType),
> - io.write_string(RegOrMemRefType ++ ", ", !IO),
> - reg_type(Reg, RegType),
> - io.write_string(RegType ++ "\t", !IO).
> +:- pred check_operand_rel_offset(operand::in, bool::out) is det.
>
> - % Output an instruction with a memory reference and a register as the
> first
> - % and second operand respectively.
> - %
> -:- pred instr_with_mem_ref_and_reg_op(string::in, mem_ref::in,
> - gp_reg::in, io::di, io::uo) is det.
> +check_operand_rel_offset(Operand, Result) :-
> + ( Operand = operand_rel_offset(_) ->
> + Result = yes
> + ;
> + Result = no
> + ).
>
> -instr_with_mem_ref_and_reg_op(InstrName, SrcMemRef, DestReg, !IO) :-
> - mem_ref_type(SrcMemRef, MemRefType),
> - io.write_string("\t" ++ InstrName ++ "\t" ++ MemRefType, !IO),
> - reg_type(DestReg, DestRegType),
> - io.write_string(", " ++ DestRegType ++ "\t", !IO).
> + % Check if the argument for a conditional instruction is valid.
> + %
> +:- pred check_instr_condition(string::in, bool::out) is det.
>
> -%-----------------------------------------------------------------------------%
> +check_instr_condition(Condition, Result) :-
> + List = ["O", "NO", "B", "C", "NAE", "NB", "NC", "AE", "Z", "E", "NZ",
> + "NE", "BE", "NA", "NBE", "A", "S", "NS", "P", "PE", "NP", "PO",
> + "L", "NGE", "NL", "GE", "LE", "NG", "NLE", "G"],
> + ( list.member(string.to_upper(Condition), List) ->
> + Result = yes
> + ;
> + Result = no
> + ).
>
> % Check whether an unsigned int (Val) with n bits (BitSize) is within
> the
> % range of 0 and (2^n)-1.
>
> --------------------------------------------------------------------------
> mercury-reviews mailing list
> Post messages to: mercury-reviews at csse.unimelb.edu.au
> Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
> Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
> --------------------------------------------------------------------------
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list