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