mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-11 03:45:33 +00:00
Estimated hours taken: 40
Branches: main
Add a mechanism for mapping between MVM registers and x86_64 registers
or fake reg array slots. This is needed by the x86_64 asm code generator.
At the momment the mapping is the same as that used by (non .par) grades
that use global register variables on the x86_64.
Modify the x86_64 code generator to emit additional instructions to
perform loads and store to the fake ref array when a virtual machine
registers is not mapped to a physical register.
compiler/x86_64_regs.m:
Defines a mapping of MVM registers to x86_64 registers.
compiler/x86_64_out.m:
Fixes some predicates to output asm codes to conform with the changes
in x86_64_instrs.m.
compiler/llds_to_x86_64.m:
Applies the register mapping during the code generation.
Add instructions to access values in the fake reg array.
(XXX this is still incomplete).
compiler/x86_64_instrs.m:
Adds discriminated union types and fixes some predicates to make the code
easier for modification.
compiler/mercury_compile.m:
Imports x86_64_regs and x86_64_out modules.
compiler/ll_backend.m:
Includes the x86_64_regs module.
Index: compiler/ll_backend.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ll_backend.m,v
retrieving revision 1.19
diff -u -r1.19 ll_backend.m
--- compiler/ll_backend.m 5 Feb 2007 22:30:32 -0000 1.19
+++ compiler/ll_backend.m 9 Feb 2007 04:57:45 -0000
@@ -97,6 +97,7 @@
:- include_module llds_to_x86_64_out.
:- include_module x86_64_instrs.
:- include_module x86_64_out.
+:- include_module x86_64_regs.
:- implementation.
Index: compiler/llds_to_x86_64.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/llds_to_x86_64.m,v
retrieving revision 1.1
diff -u -r1.1 llds_to_x86_64.m
--- compiler/llds_to_x86_64.m 5 Feb 2007 22:30:32 -0000 1.1
+++ compiler/llds_to_x86_64.m 19 Feb 2007 06:10:47 -0000
@@ -10,7 +10,13 @@
% Main author: fhandoko.
%
% This module implements the LLDS->x86_64 asm code generator.
-%
+%
+% NOTE:
+% There are a number of placeholders. It appears as a string like this:
+% <<placeholder>>. The code generator places them as either x86_64_comment
+% or operand_label type. For example:
+% x86_64_comment("<<placeholder>>") or
+% operand_label("<<placeholder>>").
%-----------------------------------------------------------------------------%
:- module ll_backend.llds_to_x86_64.
@@ -37,6 +43,7 @@
:- import_module libs.compiler_util.
:- import_module ll_backend.llds_out.
:- import_module ll_backend.x86_64_out.
+:- import_module ll_backend.x86_64_regs.
:- import_module mdbcomp.prim_data.
:- import_module bool.
@@ -72,15 +79,17 @@
%
llds_to_x86_64_asm(_, CProcs, AsmProcs) :-
- transform_c_proc_list(CProcs, AsmProcs).
+ ll_backend.x86_64_regs.llds_reg_locn(RegLocnList),
+ RegMap = ll_backend.x86_64_regs.reg_map_init(RegLocnList),
+ transform_c_proc_list(RegMap, CProcs, AsmProcs).
% Transform a list of c procedures into a list of x86_64 procedures.
%
-:- pred transform_c_proc_list(list(c_procedure)::in,
+:- pred transform_c_proc_list(reg_map::in, list(c_procedure)::in,
list(x86_64_procedure)::out) is det.
-transform_c_proc_list([], []).
-transform_c_proc_list([CProc | CProcs], [AsmProc | AsmProcs]) :-
+transform_c_proc_list(_, [], []).
+transform_c_proc_list(RegMap, [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,
%
@@ -89,65 +98,64 @@
%
ProcStr = backend_libs.name_mangle.proc_label_to_c_string(
AsmProc0 ^ x86_64_proc_label, no),
- ProcName = x86_64_directive(x86_64_pseudo_type(ProcStr, "@function")),
+ ProcName = x86_64_directive(x86_64_pseudo_type(ProcStr, function)),
ProcInstr = ProcInstr0 ^ x86_64_inst := [ProcName],
- transform_c_instr_list(CProc ^ cproc_code, AsmInstr0),
+ transform_c_instr_list(RegMap, CProc ^ cproc_code, AsmInstr0),
list.append([ProcInstr], AsmInstr0, AsmInstr),
AsmProc = AsmProc0 ^ x86_64_code := AsmInstr,
- transform_c_proc_list(CProcs, AsmProcs).
+ transform_c_proc_list(RegMap, CProcs, AsmProcs).
% Transform a list of c instructions into a list of x86_64 instructions.
%
-:- pred transform_c_instr_list(list(instruction)::in,
+:- pred transform_c_instr_list(reg_map::in, list(instruction)::in,
list(x86_64_instruction)::out) is det.
-transform_c_instr_list([], []).
-transform_c_instr_list([CInstr0 | CInstr0s], [AsmInstr | AsmInstrs]) :-
+transform_c_instr_list(_, [], []).
+transform_c_instr_list(RegMap, [CInstr0 | CInstr0s], [AsmInstr | AsmInstrs]) :-
CInstr0 = llds_instr(CInstr1, Comment),
- instr_to_x86_64(CInstr1, AsmInstrList),
+ instr_to_x86_64(RegMap, CInstr1, RegMap1, AsmInstrList),
+ ll_backend.x86_64_regs.reg_map_reset_scratch_reg_info(RegMap1, RegMap2),
AsmInstr0 = ll_backend.x86_64_instrs.init_x86_64_instruction,
AsmInstr1 = AsmInstr0 ^ x86_64_inst := AsmInstrList,
AsmInstr = AsmInstr1 ^ x86_64_inst_comment := Comment,
- transform_c_instr_list(CInstr0s, AsmInstrs).
+ transform_c_instr_list(RegMap2, CInstr0s, AsmInstrs).
% Transform a block instruction of an llds instruction into a list of
% x86_64 instructions.
%
-:- pred transform_block_instr(list(instruction)::in, list(x86_64_instr)::out)
- is det.
+:- pred transform_block_instr(reg_map::in, list(instruction)::in,
+ list(x86_64_instr)::out) is det.
-transform_block_instr(CInstrs, Instrs) :-
- transform_block_instr_list(CInstrs, ListInstrs),
+transform_block_instr(RegMap, CInstrs, Instrs) :-
+ transform_block_instr_list(RegMap, CInstrs, ListInstrs),
list.condense(ListInstrs, Instrs).
-:- pred transform_block_instr_list(list(instruction)::in,
+:- pred transform_block_instr_list(reg_map::in, list(instruction)::in,
list(list(x86_64_instr))::out) is det.
-transform_block_instr_list([], []).
-transform_block_instr_list([CInstr0 | CInstr0s], [Instr0 | Instr0s]) :-
+transform_block_instr_list(_, [], []).
+transform_block_instr_list(RegMap, [CInstr0 | CInstr0s], [Instr0 | Instr0s]) :-
CInstr0 = llds_instr(CInstr, _),
- instr_to_x86_64(CInstr, Instr0),
- transform_block_instr_list(CInstr0s, Instr0s).
+ instr_to_x86_64(RegMap, CInstr, RegMap1, Instr0),
+ ll_backend.x86_64_regs.reg_map_reset_scratch_reg_info(RegMap1, RegMap2),
+ transform_block_instr_list(RegMap2, CInstr0s, Instr0s).
% Transform livevals of llds instruction into a list of x86_64 instructions.
%
-:- pred transform_livevals(list(lval)::in, list(x86_64_instr)::out) is det.
+:- pred transform_livevals(reg_map::in, list(lval)::in, list(x86_64_instr)::out)
+ is det.
-transform_livevals([], []).
-transform_livevals([Lval | Lvals], [Instr | Instrs]) :-
- transform_lval(Lval, Res0, Res1),
+transform_livevals(_, [], []).
+transform_livevals(RegMap, [Lval | Lvals], [Instr | Instrs]) :-
+ transform_lval(RegMap, Lval, RegMap1, Res0, Res1),
(
- Res0 = yes(LvalOp),
- Instr = x86_64_instr(mov(operand_label("<<livevals>>"), LvalOp)),
- transform_livevals(Lvals, Instrs)
+ Res0 = yes(LvalOp)
;
Res0 = no,
(
Res1 = yes(LvalInstrs),
( get_last_instr_opand(LvalInstrs, LastOp) ->
- Instr = x86_64_instr(mov(operand_label("<<livevals>>"),
- LastOp)),
- transform_livevals(Lvals, Instrs)
+ LvalOp = LastOp
;
unexpected(this_file, "transform_livevals: unexpected:"
++ " get_last_instr_opand failed")
@@ -157,22 +165,25 @@
unexpected(this_file, "transform_livevals: unexpected:"
++ " get_last_instr_opand failed")
)
- ).
+ ),
+ Instr = x86_64_instr(mov(operand_label("<<liveval>>"), LvalOp)),
+ transform_livevals(RegMap1, Lvals, Instrs).
% Given an llds instruction, transform it into equivalent x86_64
% instructions.
%
-:- pred instr_to_x86_64(instr::in, list(x86_64_instr)::out) is det.
+:- pred instr_to_x86_64(reg_map::in, instr::in, reg_map::out,
+ list(x86_64_instr)::out) is det.
-instr_to_x86_64(comment(Comment), [x86_64_comment(Comment)]).
-instr_to_x86_64(livevals(RegsAndStackLocs), Instrs) :-
+instr_to_x86_64(RegMap, comment(Comment), RegMap, [x86_64_comment(Comment)]).
+instr_to_x86_64(RegMap, livevals(RegsAndStackLocs), RegMap, Instrs) :-
set.to_sorted_list(RegsAndStackLocs, List),
- transform_livevals(List, Instrs).
-instr_to_x86_64(block(_, _, CInstrs), Instrs) :-
- transform_block_instr(CInstrs, Instrs).
-instr_to_x86_64(assign(Lval, Rval), Instrs) :-
- transform_lval(Lval, Res0, Res1),
- transform_rval(Rval, Res2, Res3),
+ transform_livevals(RegMap, List, Instrs).
+instr_to_x86_64(RegMap, block(_, _, CInstrs), RegMap, Instrs) :-
+ transform_block_instr(RegMap, CInstrs, Instrs).
+instr_to_x86_64(RegMap0, assign(Lval, Rval), RegMap, Instrs) :-
+ transform_lval(RegMap0, Lval, RegMap1, Res0, Res1),
+ transform_rval(RegMap1, Rval, RegMap, Res2, Res3),
(
Res0 = yes(LvalOp),
(
@@ -184,7 +195,7 @@
Res3 = yes(RvalInstrs),
( get_last_instr_opand(RvalInstrs, LastOp) ->
LastInstr = x86_64_instr(mov(LastOp, LvalOp)),
- list.append(RvalInstrs, [LastInstr], Instrs)
+ Instrs = RvalInstrs ++ [LastInstr]
;
unexpected(this_file, "instr_to_x86_64: assign: unexpected:"
++ " get_last_instr_opand failed")
@@ -202,16 +213,15 @@
( get_last_instr_opand(LvalInstrs, LvalLastOp) ->
(
Res2 = yes(RvalOp),
- Instr0 = x86_64_instr(mov(RvalOp, LvalLastOp)),
- list.append(LvalInstrs, [Instr0], Instrs)
-
+ Instr1 = x86_64_instr(mov(RvalOp, LvalLastOp)),
+ Instrs = LvalInstrs ++ [Instr1]
;
Res2 = no,
(
Res3 = yes(RvalInstrs),
( get_last_instr_opand(RvalInstrs, RvalLastOp) ->
- Instr0 = x86_64_instr(mov(RvalLastOp, LvalLastOp)),
- Instrs = LvalInstrs ++ [Instr0] ++ RvalInstrs
+ Instr1 = x86_64_instr(mov(RvalLastOp, LvalLastOp)),
+ Instrs = LvalInstrs ++ RvalInstrs ++ [Instr1]
;
unexpected(this_file, "instr_to_x86_64: assign:"
++ " unexpected:get_last_instr_opand failed")
@@ -232,22 +242,42 @@
++ "Lval")
)
).
-instr_to_x86_64(llcall(Target0, Continuation0, _, _, _, _), Instrs) :-
+instr_to_x86_64(RegMap0, llcall(Target0, Continuation0, _, _, _, _), RegMap,
+ Instrs) :-
code_addr_type(Target0, Target1),
code_addr_type(Continuation0, Continuation1),
- Instr1 = x86_64_instr(mov(operand_label(Continuation1),
- operand_label("<<succip>>"))),
+ lval_reg_locn(RegMap0, succip, Op0, Instr0),
+ ll_backend.x86_64_regs.reg_map_remove_scratch_reg(RegMap0, RegMap),
+ (
+ Op0 = yes(Op)
+ ;
+ Op0 = no,
+ (
+ Instr0 = yes(Instr),
+ ( get_last_instr_opand(Instr, LastOpand) ->
+ Op = LastOpand
+ ;
+ unexpected(this_file, "instr_to_x86_64: llcall: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Instr0 = no,
+ unexpected(this_file, "instr_to_x86_64: llcall: unexpected:" ++
+ " lval_reg_locn failed")
+ )
+ ),
+ Instr1 = x86_64_instr(mov(operand_label(Continuation1), Op)),
Instr2 = x86_64_instr(jmp(operand_label(Target1))),
Instrs = [Instr1, Instr2].
-instr_to_x86_64(mkframe(_, _), [x86_64_comment("<<mkframe>>")]).
-instr_to_x86_64(label(Label), Instrs) :-
+instr_to_x86_64(RegMap, mkframe(_, _), RegMap, [x86_64_comment("<<mkframe>>")]).
+instr_to_x86_64(RegMap, label(Label), RegMap, Instrs) :-
LabelStr = ll_backend.llds_out.label_to_c_string(Label, no),
Instrs = [x86_64_label(LabelStr)].
-instr_to_x86_64(goto(CodeAddr), Instrs) :-
+instr_to_x86_64(RegMap, goto(CodeAddr), RegMap, Instrs) :-
code_addr_type(CodeAddr, Label),
Instrs = [x86_64_instr(jmp(operand_label(Label)))].
-instr_to_x86_64(computed_goto(Rval, Labels), Instrs) :-
- transform_rval(Rval, Res0, Res1),
+instr_to_x86_64(RegMap0, computed_goto(Rval, Labels), RegMap, Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap1, Res0, Res1),
(
Res0 = yes(RvalOp),
RvalInstrs = []
@@ -268,17 +298,19 @@
)
),
labels_to_string(Labels, "", LabelStr),
- TempReg = operand_reg(gp_reg(13)),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap1),
+ ll_backend.x86_64_regs.reg_map_remove_scratch_reg(RegMap1, RegMap),
+ TempReg = operand_reg(ScratchReg),
Instr0 = x86_64_instr(mov(operand_mem_ref(mem_abs(base_expr(LabelStr))),
TempReg)),
Instr1 = x86_64_instr(add(RvalOp, TempReg)),
Instr2 = x86_64_instr(jmp(TempReg)),
Instrs = RvalInstrs ++ [Instr0] ++ [Instr1] ++ [Instr2].
-instr_to_x86_64(arbitrary_c_code(_, _, _), Instrs) :-
+instr_to_x86_64(RegMap, arbitrary_c_code(_, _, _), RegMap, Instrs) :-
Instrs = [x86_64_comment("<<arbitrary_c_code>>")].
-instr_to_x86_64(if_val(Rval, CodeAddr), Instrs) :-
+instr_to_x86_64(RegMap0, if_val(Rval, CodeAddr), RegMap, Instrs) :-
code_addr_type(CodeAddr, Target),
- transform_rval(Rval, Res0, Res1),
+ transform_rval(RegMap0, Rval, RegMap, Res0, Res1),
(
Res0 = yes(RvalOp)
;
@@ -297,14 +329,17 @@
++ " Rval")
)
),
- ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ ll_backend.x86_64_out.operand_to_string(RvalOp, RvalStr),
Instrs = [x86_64_directive(x86_64_pseudo_if(RvalStr)), x86_64_instr(j(
operand_label(Target), e)), x86_64_directive(endif)].
-instr_to_x86_64(save_maxfr(_), [x86_64_comment("<<save_maxfr>>")]).
-instr_to_x86_64(restore_maxfr(_), [x86_64_comment("<<restore_maxfr>>")]).
-instr_to_x86_64(incr_hp(Lval, Tag0, Words0, Rval, _, _), Instrs) :-
- transform_rval(Rval, Res0, Res1),
- transform_lval(Lval, Res2, Res3),
+instr_to_x86_64(RegMap, save_maxfr(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<save_maxfr>>")].
+instr_to_x86_64(RegMap, restore_maxfr(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<restore_maxfr>>")].
+instr_to_x86_64(RegMap0, incr_hp(Lval, Tag0, Words0, Rval, _, _), RegMap,
+ Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap1, Res0, Res1),
+ transform_lval(RegMap1, Lval, RegMap2, Res2, Res3),
(
Res0 = yes(RvalOp)
;
@@ -344,14 +379,17 @@
(
Words0 = yes(Words),
IncrVal = operand_imm(imm32(int32(Words))),
- TempReg = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ ScratchReg0 = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap2),
+ reg_map_remove_scratch_reg(RegMap2, RegMap3),
+ TempReg1 = operand_reg(ScratchReg0),
+ ll_backend.x86_64_out.operand_to_string(RvalOp, RvalStr),
MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
- LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
- IncrAddInstr = x86_64_instr(add(IncrVal, TempReg)),
+ LoadAddr = x86_64_instr(lea(MemRef, TempReg1)),
+ IncrAddInstr = x86_64_instr(add(IncrVal, TempReg1)),
list.append([LoadAddr], [IncrAddInstr], IncrAddrInstrs)
;
Words0 = no,
+ RegMap3 = RegMap2,
IncrAddrInstrs = []
),
(
@@ -360,86 +398,141 @@
Tag0 = no,
Tag = 0
),
- TempReg = operand_reg(gp_reg(13)),
- ImmToReg = x86_64_instr(mov(RvalOp, TempReg)),
- SetTag = x86_64_instr(or(operand_imm(imm32(int32(Tag))), TempReg)),
- Instr0 = x86_64_instr(mov(TempReg, LvalOp)),
- Instrs = IncrAddrInstrs ++ [ImmToReg] ++ [SetTag] ++ [Instr0].
-instr_to_x86_64(mark_hp(_), [x86_64_comment("<<mark_hp>>")]).
-instr_to_x86_64(restore_hp(_), [x86_64_comment("<<restore_hp>>")]).
-instr_to_x86_64(free_heap(_), [x86_64_comment("<<free_heap>>")]).
-instr_to_x86_64(store_ticket(_), [x86_64_comment("<<store_ticket>>")]).
-instr_to_x86_64(reset_ticket(_, _), [x86_64_comment("<<reset_ticket>>")]).
-instr_to_x86_64(prune_ticket, [x86_64_comment("<<prune_ticket>>")]).
-instr_to_x86_64(discard_ticket, [x86_64_comment("<<discard_ticket>>")]).
-instr_to_x86_64(mark_ticket_stack(_), [x86_64_comment("<<mark_ticket_stack>>")]).
-instr_to_x86_64(prune_tickets_to(_), [x86_64_comment("<<prune_tickets_to>>")]).
-instr_to_x86_64(incr_sp(NumSlots, ProcName, _), Instrs) :-
+ ScratchReg1 = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap3),
+ reg_map_remove_scratch_reg(RegMap3, RegMap),
+ TempReg2 = operand_reg(ScratchReg1),
+ ImmToReg = x86_64_instr(mov(RvalOp, TempReg2)),
+ SetTag = x86_64_instr(or(operand_imm(imm32(int32(Tag))), TempReg2)),
+ Instr1 = x86_64_instr(mov(TempReg2, LvalOp)),
+ Instrs = IncrAddrInstrs ++ [ImmToReg] ++ [SetTag] ++ [Instr1].
+instr_to_x86_64(RegMap, mark_hp(_), RegMap, [x86_64_comment("<<mark_hp>>")]).
+instr_to_x86_64(RegMap, restore_hp(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<restore_hp>>")].
+instr_to_x86_64(RegMap, free_heap(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<free_heap>>")].
+instr_to_x86_64(RegMap, store_ticket(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<store_ticket>>")].
+instr_to_x86_64(RegMap, reset_ticket(_, _), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<reset_ticket>>")].
+instr_to_x86_64(RegMap, prune_ticket, RegMap, Instr) :-
+ Instr = [x86_64_comment("<<prune_ticket>>")].
+instr_to_x86_64(RegMap, discard_ticket, RegMap, Instr) :-
+ Instr = [x86_64_comment("<<discard_ticket>>")].
+instr_to_x86_64(RegMap, mark_ticket_stack(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<mark_ticket_stack>>")].
+instr_to_x86_64(RegMap, prune_tickets_to(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<prune_tickets_to>>")].
+instr_to_x86_64(RegMap, incr_sp(NumSlots, ProcName, _), RegMap, Instrs) :-
Instr1 = x86_64_comment("<<incr_sp>> " ++ ProcName),
Instr2 = x86_64_instr(enter(uint16(NumSlots), uint8(0))),
Instrs = [Instr1, Instr2].
-instr_to_x86_64(decr_sp(NumSlots), Instrs) :-
+instr_to_x86_64(RegMap0, decr_sp(NumSlots), RegMap, Instrs) :-
DecrOp = operand_imm(imm32(int32(NumSlots))),
- Instr = x86_64_instr(sub(DecrOp, operand_reg(gp_reg(13)))),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap0),
+ ll_backend.x86_64_regs.reg_map_remove_scratch_reg(RegMap0, RegMap),
+ Instr = x86_64_instr(sub(DecrOp, operand_reg(ScratchReg))),
list.append([x86_64_comment("<<decr_sp>> ")], [Instr], Instrs).
-instr_to_x86_64(decr_sp_and_return(NumSlots), Instrs) :-
+instr_to_x86_64(RegMap, decr_sp_and_return(NumSlots), RegMap, Instrs) :-
Instrs = [x86_64_comment("<<decr_sp_and_return>> " ++
string.int_to_string(NumSlots))].
-instr_to_x86_64(foreign_proc_code(_, _, _, _, _, _, _, _, _),
- [x86_64_comment("<<foreign_proc_code>>")]).
-instr_to_x86_64(init_sync_term(_, _), [x86_64_comment("<<init_sync_term>>")]).
-instr_to_x86_64(fork(_), [x86_64_comment("<<fork>>")]).
-instr_to_x86_64(join_and_continue(_, _), [x86_64_comment("<<join_and_continue>>")]).
-
+instr_to_x86_64(RegMap, foreign_proc_code(_, _, _, _, _, _, _, _, _), RegMap,
+ Instr) :-
+ Instr = [x86_64_comment("<<foreign_proc_code>>")].
+instr_to_x86_64(RegMap, init_sync_term(_, _), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<init_sync_term>>")].
+instr_to_x86_64(RegMap, fork(_), RegMap, [x86_64_comment("<<fork>>")]).
+instr_to_x86_64(RegMap, join_and_continue(_, _), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<join_and_continue>>")].
% Transform lval into either an x86_64 operand or x86_64 instructions.
%
-:- pred transform_lval(lval::in, maybe(operand)::out,
+:- pred transform_lval(reg_map::in, lval::in, reg_map::out, maybe(operand)::out,
maybe(list(x86_64_instr))::out) is det.
-transform_lval(reg(CReg, CRegNum), Op, no) :-
- (
+transform_lval(RegMap0, reg(CReg, CRegNum), RegMap, Op, Instr) :-
+ (
CReg = reg_r,
- Op = yes(operand_reg(gp_reg(CRegNum)))
+ lval_reg_locn(RegMap, reg(CReg, CRegNum), Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap)
;
CReg = reg_f,
- Op = no
+ unexpected(this_file, "transform_lval: unexpected: llds reg_f")
).
-transform_lval(succip, yes(operand_label("<<succip>>")), no).
-transform_lval(maxfr, yes(operand_label("<<maxfr>>")), no).
-transform_lval(curfr, yes(operand_label("<<curfr>>")), no).
-transform_lval(hp, yes(operand_label("<<hp>>")), no).
-transform_lval(sp, yes(operand_label("<<sp>>")), no).
-transform_lval(parent_sp, yes(operand_label("<<parent_sp>>")), no).
-transform_lval(temp(CReg, CRegNum), Op, no) :-
- (
- CReg = reg_r,
- Op = yes(operand_reg(gp_reg(CRegNum)))
+transform_lval(RegMap0, succip, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, succip, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, maxfr, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, maxfr, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, curfr, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, curfr, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, hp, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, hp, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, sp, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, sp, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap, parent_sp, RegMap, Op, no) :-
+ Op = yes(operand_label("<<parent_sp>>")).
+transform_lval(RegMap, temp(CReg, CRegNum), RegMap1, Op, Instr) :-
+ transform_lval(RegMap, reg(CReg, CRegNum), RegMap1, Op, Instr).
+transform_lval(RegMap0, stackvar(Offset), RegMap, Op, Instr) :-
+ RegLocn = reg_map_lookup_reg_locn(RegMap, sp),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap0),
+ reg_map_remove_scratch_reg(RegMap0, RegMap),
+ (
+ RegLocn = actual(Reg),
+ Op = no,
+ Instr = yes([x86_64_instr(mov(operand_mem_ref(
+ mem_abs(base_reg(Offset, Reg))), operand_reg(ScratchReg) ))])
;
- CReg = reg_f,
- Op = no
+ RegLocn = virtual(SlotNum),
+ Op = no,
+ FakeRegVal = "$" ++ "virtual_reg(" ++ string.int_to_string(SlotNum)
+ ++ ") + " ++ string.int_to_string(Offset),
+ Instr = yes([x86_64_instr(mov(
+ operand_label(FakeRegVal), operand_reg(ScratchReg)))])
).
-transform_lval(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),
+transform_lval(RegMap, parent_stackvar(_), RegMap, Op, no) :-
+ Op = yes(operand_label("<<parent_stackvar>>")).
+transform_lval(RegMap0, framevar(Offset), RegMap, Op, Instr) :-
+ ScratchReg= ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap),
+ reg_map_remove_scratch_reg(RegMap0, RegMap),
+ RegLocn = reg_map_lookup_reg_locn(RegMap, curfr),
+ % framevar(Int) refers to an offset Int relative to the current value of
+ % 'curfr'
+ (
+ RegLocn = actual(Reg),
+ Op = no,
+ Instr = yes([x86_64_instr(mov(operand_mem_ref(
+ mem_abs(base_reg(Offset, Reg))), operand_reg(ScratchReg) ))])
+ ;
+ RegLocn = virtual(SlotNum),
+ Op = no,
+ FakeRegVal = "$" ++ "virtual_reg(" ++ string.int_to_string(SlotNum)
+ ++ ") + " ++ string.int_to_string(Offset),
+ Instr = yes([x86_64_instr(mov(
+ operand_label(FakeRegVal), operand_reg(ScratchReg)))])
+ ).
+transform_lval(RegMap0, succip_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, redoip_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, redofr_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, succfr_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, prevfr_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, mem_ref(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap, global_var_ref(env_var_ref(Name)), RegMap, Op, no) :-
+ Op = yes(operand_label(Name)).
+transform_lval(RegMap, lvar(_), RegMap, yes(operand_label("<<lvar>>")), no).
+transform_lval(RegMap0, field(Tag0, Rval1, Rval2), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval1, RegMap1, Res0, Res1),
+ transform_rval(RegMap1, Rval2, RegMap2, Res2, Res3),
(
Res0 = yes(RvalOp1),
Instrs1 = []
@@ -478,8 +571,10 @@
unexpected(this_file, "lval_instrs: field: unexpected: Rval2")
)
),
- TempReg1 = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(RvalOp1, RvalStr1),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap2),
+ reg_map_remove_scratch_reg(RegMap2, RegMap),
+ TempReg1 = operand_reg(ScratchReg),
+ ll_backend.x86_64_out.operand_to_string(RvalOp1, RvalStr1),
MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr1))),
LoadAddr = x86_64_instr(lea(MemRef, TempReg1)),
FieldNum = x86_64_instr(add(RvalOp2, TempReg1)),
@@ -495,14 +590,14 @@
% Translates rval into its corresponding x86_64 operand.
%
-:- pred transform_rval(rval::in, maybe(operand)::out, maybe(list(x86_64_instr))
- ::out) is det.
+:- pred transform_rval(reg_map::in, rval::in, reg_map::out, maybe(operand)::out,
+ maybe(list(x86_64_instr)) ::out) is det.
-transform_rval(lval(Lval0), Op, Instrs) :-
- transform_lval(Lval0, Op, Instrs).
-transform_rval(var(_), yes(operand_label("<<var>>")), no).
-transform_rval(mkword(Tag, Rval), no, Instrs) :-
- transform_rval(Rval, Res0, Res1),
+transform_rval(RegMap0, lval(Lval0), RegMap, Op, Instrs) :-
+ transform_lval(RegMap0, Lval0, RegMap, Op, Instrs).
+transform_rval(RegMap, var(_), RegMap, yes(operand_label("<<var>>")), no).
+transform_rval(RegMap0, mkword(Tag, Rval), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap1, Res0, Res1),
(
Res0 = yes(RvalOp),
list.append([x86_64_comment("<<mkword>>")], [], Instr0)
@@ -522,27 +617,33 @@
unexpected(this_file, "transform_rval: mkword unexpected: Rval")
)
),
- TempReg = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap1),
+ reg_map_remove_scratch_reg(RegMap1, RegMap),
+ TempReg = operand_reg(ScratchReg),
+ ll_backend.x86_64_out.operand_to_string(RvalOp, RvalStr),
MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
SetTag = x86_64_instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
Instrs = yes(Instr0 ++ [LoadAddr] ++ [SetTag]).
-transform_rval(const(llconst_true), yes(operand_label("<<llconst_true>>")), no).
-transform_rval(const(llconst_false), yes(operand_label("<<llconst_false>>")), no).
-transform_rval(const(llconst_int(Val)), yes(operand_imm(imm32(int32(Val)))), no).
-transform_rval(const(llconst_float(_)), yes(operand_label("<<llconst_float>>")), no).
-transform_rval(const(llconst_string(String)), no, yes(Op)) :-
+transform_rval(RegMap, const(llconst_true), RegMap, Op, no) :-
+ Op = yes(operand_label("<<llconst_true>>")).
+transform_rval(RegMap, const(llconst_false), RegMap, Op, no) :-
+ Op = yes(operand_label("<<llconst_false>>")).
+transform_rval(RegMap, const(llconst_int(Val)), RegMap, Op, no) :-
+ Op = yes(operand_imm(imm32(int32(Val)))).
+transform_rval(RegMap, const(llconst_float(_)), RegMap, Op, no) :-
+ Op = yes(operand_label("<<llconst_float>>")).
+transform_rval(RegMap, const(llconst_string(String)), RegMap, no, yes(Op)) :-
Op = [x86_64_directive(string([String]))].
-transform_rval(const(llconst_multi_string(_, _)), Op, no) :-
+transform_rval(RegMap, const(llconst_multi_string(_, _)), RegMap, Op, no) :-
Op = yes(operand_label("<<llconst_multi_string>>")).
-transform_rval(const(llconst_code_addr(CodeAddr)), Op, no) :-
+transform_rval(RegMap, const(llconst_code_addr(CodeAddr)), RegMap, Op, no) :-
code_addr_type(CodeAddr, CodeAddrType),
- Op = yes(operand_label("<<llconst_code_addr>>" ++ CodeAddrType)).
-transform_rval(const(llconst_data_addr(_, _)), Op, no) :-
+ Op = yes(operand_label(CodeAddrType)).
+transform_rval(RegMap, const(llconst_data_addr(_, _)), RegMap, Op, no) :-
Op = yes(operand_label("<<llconst_data_addr>>")).
-transform_rval(unop(Op, Rval), no, Instrs) :-
- transform_rval(Rval, Res0, Res1),
+transform_rval(RegMap0, unop(Op, Rval), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap, Res0, Res1),
(
Res0 = yes(_),
unop_instrs(Op, Res0, no, Instrs0),
@@ -558,9 +659,9 @@
unexpected(this_file, "transform_rval: unop: unexpected: Rval")
)
).
-transform_rval(binop(Op, Rval1, Rval2), no, Instrs) :-
- transform_rval(Rval1, Res1, Res2),
- transform_rval(Rval2, Res3, Res4),
+transform_rval(RegMap0, binop(Op, Rval1, Rval2), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval1, RegMap1, Res1, Res2),
+ transform_rval(RegMap1, Rval2, RegMap, Res3, Res4),
(
Res1 = yes(Val1),
(
@@ -606,13 +707,14 @@
unexpected(this_file, "rval_instrs: binop: unexpected: Rval1")
)
).
-transform_rval(mem_addr(stackvar_ref(Rval)), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_rval(mem_addr(framevar_ref(Rval)), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_rval(mem_addr(heap_ref(Rval1, Tag, Rval2)), no, Instrs) :-
- transform_rval(Rval1, Res0, Res1),
- transform_rval(Rval2, Res2, Res3),
+transform_rval(RegMap0, mem_addr(stackvar_ref(Rval)), RegMap, Op, no) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, _).
+transform_rval(RegMap0, mem_addr(framevar_ref(Rval)), RegMap, Op, no) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, _).
+transform_rval(RegMap0, mem_addr(heap_ref(Rval1, Tag, Rval2)), RegMap,
+ no, Instrs) :-
+ transform_rval(RegMap0, Rval1, RegMap1, Res0, Res1),
+ transform_rval(RegMap1, Rval2, RegMap2, Res2, Res3),
(
Res0 = yes(Rval1Op),
(
@@ -672,14 +774,42 @@
++ " unexpected: Rval1")
)
),
- TempReg = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(Rval1Op, Rval1Str),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap2),
+ reg_map_remove_scratch_reg(RegMap2, RegMap),
+ TempReg = operand_reg(ScratchReg),
+ ll_backend.x86_64_out.operand_to_string(Rval1Op, Rval1Str),
MemRef = operand_mem_ref(mem_abs(base_expr(Rval1Str))),
LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
Instr0 = x86_64_instr(sub(Rval2Op, TempReg)),
Instr1 = x86_64_instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
Instrs = yes(Instrs0 ++ [LoadAddr] ++ [Instr0] ++ [Instr1]).
+
+ % Given an llds-lval, returns either an operand or instructions (actually,
+ % it only a single move instruction. It returns a list so that the calling
+ % predicate won't have to do any rearrangements for the return value). If
+ % lval is located in an actual register, returns the actual register which
+ % corresponds to that lval. Otherwise, move lval from the fake-reg array
+ % to a temporary register.
+ %
+:- pred lval_reg_locn(reg_map::in, lval::in, maybe(operand)::out,
+ maybe(list(x86_64_instr))::out) is det.
+
+lval_reg_locn(RegMap, Lval, Op, Instr) :-
+ RegLocn = reg_map_lookup_reg_locn(RegMap, Lval),
+ (
+ RegLocn = actual(Reg),
+ Op = yes(operand_reg(Reg)),
+ Instr = no
+ ;
+ RegLocn = virtual(SlotNum),
+ Op = no,
+ FakeRegVal = "fake_reg(" ++ string.int_to_string(SlotNum) ++ ")",
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap),
+ Instr = yes([x86_64_instr(mov(operand_mem_ref(mem_abs(
+ base_expr(FakeRegVal))), operand_reg(ScratchReg)))])
+ ).
+
% x86_64 instructions for binary operation with either an operand or an
% expression (given as a list of x86_64 instructions) or a combination of
% both.
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.429
diff -u -r1.429 mercury_compile.m
--- compiler/mercury_compile.m 9 Feb 2007 04:05:16 -0000 1.429
+++ compiler/mercury_compile.m 12 Feb 2007 22:47:47 -0000
@@ -127,6 +127,8 @@
:- import_module ll_backend.llds_to_x86_64.
:- import_module ll_backend.llds_to_x86_64_out.
:- import_module ll_backend.x86_64_instrs.
+:- import_module ll_backend.x86_64_out.
+:- import_module ll_backend.x86_64_regs.
% the MLDS back-end
:- import_module ml_backend.add_trail_ops. % HLDS -> HLDS
Index: compiler/x86_64_instrs.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/x86_64_instrs.m,v
retrieving revision 1.2
diff -u -r1.2 x86_64_instrs.m
--- compiler/x86_64_instrs.m 5 Feb 2007 22:30:34 -0000 1.2
+++ compiler/x86_64_instrs.m 19 Feb 2007 05:57:50 -0000
@@ -11,6 +11,9 @@
%
% This module contains the representations of the x86_64 instructions.
%
+% NOTE:
+% Instructions that make use of segment registers and string operations
+% (such as compare_strings) have not been implemented.
%-----------------------------------------------------------------------------%
:- module ll_backend.x86_64_instrs.
@@ -146,6 +149,27 @@
; nle % Not Less or Equal (ZF = 0 and SF = OF).
; g. % Greater (ZF = 0 and SF = OF).
+ % Optional flags argument of .section pseudo_op.
+ %
+:- type pseudo_section_flag
+ ---> a % section is allocatable.
+ ; w % section is writable.
+ ; x % section is executable.
+ ; m % section is mergeable.
+ ; s. % section contains zero terminated string.
+
+ % An optional type of '.section' pseudo-op.
+ %
+:- type pseudo_section_type
+ ---> progbits % section contains data.
+ ; nobits. % section does not contain data.
+
+ % type_desc field of .section pseudo-op.
+ %
+:- type pseudo_section_type_desc
+ ---> function
+ ; object.
+
%-----------------------------------------------------------------------------%
%
% x86_64 pseudo-ops.
@@ -530,8 +554,8 @@
; section(
section_name :: string,
- section_flags :: maybe(string),
- section_type :: maybe(string),
+ section_flags :: maybe(list(pseudo_section_flag)),
+ section_type :: maybe(pseudo_section_type),
section_entsize :: maybe(int)
)
% ELF section stack manipulation directive.
@@ -618,7 +642,7 @@
; x86_64_pseudo_type(
type_name :: string,
- type_desc :: string
+ type_desc :: pseudo_section_type_desc
)
% Set the type of symbol'type_name' to be either a function or an
% object symbol.
@@ -666,8 +690,26 @@
% General purpose registers on the x86_64.
% Details on amd64-prog-man-vol1 manual p27.
%
-:- type gp_reg
- ---> gp_reg(int).
+
+:- type offset == int.
+
+:- type x86_64_reg
+ ---> rax
+ ; rbx
+ ; rcx
+ ; rdx
+ ; rbp
+ ; rsi
+ ; rdi
+ ; rsp
+ ; r8
+ ; r9
+ ; r10
+ ; r11
+ ; r12(offset) % offset(r12) in x86_64 = offset(sp) in llds.
+ ; r13
+ ; r14
+ ; r15.
% 64-bit instruction pointer register on the x86_64. Instruction pointer
% RIP is used as a base register for relative addressing. x86_64
@@ -719,7 +761,7 @@
:- type base_address
---> base_reg(
base_offset :: int,
- base_reg :: gp_reg
+ base_reg :: x86_64_reg
)
; base_expr(
@@ -729,7 +771,7 @@
% All operands for the x86_64 instructions.
%
:- type operand
- ---> operand_reg(gp_reg)
+ ---> operand_reg(x86_64_reg)
; operand_imm(imm_operand)
; operand_mem_ref(x86_64_mem_ref)
; operand_rel_offset(rel_offset)
@@ -751,7 +793,7 @@
% signed relative offset or a label.
%
:- type rmrol
- ---> rmrol_reg(gp_reg)
+ ---> rmrol_reg(x86_64_reg)
; rmrol_mem_ref(x86_64_mem_ref)
; rmrol_rel_offset(rel_offset)
; rmrol_label(
@@ -1277,6 +1319,12 @@
% Details on amd64-prog-man-vol3 manual p272.
%-----------------------------------------------------------------------------%
+
+ % Returns the number of x86_64 general-purpose registers.
+ %
+:- func num_x86_64_regs = int.
+
+%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
@@ -1291,4 +1339,8 @@
init_x86_64_instruction = x86_64_instr([], "").
+num_x86_64_regs = 16.
+
%-----------------------------------------------------------------------------%
+:- end_module ll_backend.x86_64_instrs.
+%----------------------------------------------------------------------------%
Index: compiler/x86_64_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/x86_64_out.m,v
retrieving revision 1.3
diff -u -r1.3 x86_64_out.m
--- compiler/x86_64_out.m 8 Feb 2007 01:02:53 -0000 1.3
+++ compiler/x86_64_out.m 19 Feb 2007 06:06:56 -0000
@@ -13,6 +13,11 @@
% to string writer streams that are attached to the I/O state.
% (There's no particularly good reason for this latter restriction so
% it can safely be dropped if necessary.)
+%
+% NOTE:
+% The module calls unexpected/2 if there is an instruction which expects
+% a different type of operand (For example: an instruction expecting a
+% register operand but supplied with an immediate operand type).
%
%-----------------------------------------------------------------------------%
@@ -31,9 +36,7 @@
:- pred output_x86_64_instruction(Stream::in, x86_64_instruction::in,
io::di, io::uo) is det <= stream.writer(Stream, string, io).
- % XXX this is misnamed: it should be operand_to_string.
- %
-:- pred operand_type(operand::in, string::out) is det.
+:- pred operand_to_string(operand::in, string::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -41,6 +44,7 @@
:- implementation.
:- import_module libs.compiler_util.
+:- import_module ll_backend.x86_64_regs.
:- import_module bool.
:- import_module char.
@@ -233,13 +237,10 @@
Result0 = yes,
Type0 = yes(Type1)
->
- put(Stream, ",\"" ++ Flags1 ++ "\"", !IO),
- ( check_pseudo_section_type(Type1) ->
- put(Stream, "," ++ Type1, !IO)
- ;
- unexpected(this_file, "output_x86_64_pseudo_op: section:"
- ++ " check_section_type unexpected")
- )
+ pseudo_section_flags_to_string(Flags1, "", FlagsStr),
+ put(Stream, ",\"" ++ FlagsStr ++ "\"", !IO),
+ check_pseudo_section_type(Type1, Type1Str),
+ put(Stream, "," ++ Type1Str, !IO)
;
unexpected(this_file, "output_x86_64_pseudo_op: section:"
++ " check_section_flags_and_type unexpected")
@@ -291,12 +292,8 @@
output_x86_64_pseudo_op(Stream, title(Heading), !IO) :-
put(Stream, "\t.title\t" ++ Heading ++ "\n", !IO).
output_x86_64_pseudo_op(Stream, x86_64_pseudo_type(Name, Desc), !IO) :-
- ( check_pseudo_type_desc(Desc) ->
- put(Stream, "\t.type\t" ++ Name ++ "," ++ Desc ++ "\n", !IO)
- ;
- unexpected(this_file, "output_x86_64_pseudo_op: x86_64_pseudo_type:"
- ++ " unexpected: check_pseudo_type_desc failed")
- ).
+ check_pseudo_type_desc(Desc, DescType),
+ put(Stream, "\t.type\t" ++ Name ++ "," ++ DescType ++ "\n", !IO).
output_x86_64_pseudo_op(Stream, uleb128(ExprList), !IO) :-
output_pseudo_op_str_args(Stream, ".uleb128", ExprList, !IO).
output_x86_64_pseudo_op(Stream, val(Addr), !IO) :-
@@ -394,74 +391,96 @@
% Check if the FLAGS and TYPE argumentis of '.section' pseudo-op
% are valid.
%
-:- pred check_section_flags_and_type(string::in, maybe(string)::in,
- bool::out) is det.
+:- pred check_section_flags_and_type(list(pseudo_section_flag)::in,
+ maybe(pseudo_section_type)::in, bool::out) is det.
check_section_flags_and_type(Flags, Type0, Result) :-
- ( string.contains_char(Flags, 'M') ->
+ check_pseudo_section_m_flag(Flags, Result0),
+ (
+ Result0 = yes,
(
Type0 = yes(Type1),
- string.length(Type1) > 0
+ check_pseudo_section_type(Type1, _)
->
true
;
unexpected(this_file, "check_section_flags_and_type:"
- ++ " unexpected: flag")
+ ++ " unexpected: flag 'm' has to have 'type' arguments")
)
;
+ Result0 = no,
true
),
- string.to_char_list(Flags, CharList),
- check_pseudo_section_flags(CharList, Result0),
+ check_pseudo_section_flags(Flags, Result1),
(
- Result0 = yes,
+ Result1 = yes,
Result = yes
;
- Result0 = no,
+ Result1 = no,
Result = no
).
% Check if the FLAGS argument of '.section' pseudo-op is valid.
%
-:- pred check_pseudo_section_flags(list(char)::in, bool::out) is det.
+:- pred check_pseudo_section_flags(list(pseudo_section_flag)::in, bool::out)
+ is det.
check_pseudo_section_flags([], yes).
-check_pseudo_section_flags([Char | Chars], Result) :-
- ( string.contains_char(section_pseudo_op_flags, Char) ->
- check_pseudo_section_flags(Chars, Result)
- ;
- Result = no
- ).
+check_pseudo_section_flags([Flag | Flags], Result) :-
+ pseudo_section_flag(Flag, _),
+ check_pseudo_section_flags(Flags, Result).
- % The optional FLAGS argument of '.section' pseudo-op contains any
- % combination of:
- % 'a' - section is allocatable
- % 'w' - section is writable
- % 'x' - section is executable
- % 'M' - section is mergeable
- % 'S' - section contains zero terminated string
+ % Returns a string representation of optional flag arguments of
+ % .section pseudo instruction.
%
-:- func section_pseudo_op_flags = string.
+:- pred pseudo_section_flags_to_string(list(pseudo_section_flag)::in,
+ string::in, string::out) is det.
+
+pseudo_section_flags_to_string([], Result, Result).
+pseudo_section_flags_to_string([Flag | Flags], Result0, Result) :-
+ pseudo_section_flag(Flag, FlagString),
+ pseudo_section_flags_to_string(Flags, FlagString ++ Result0, Result).
+
+ % Returns a string representation of a .section pseudo-instruction flag.
+ %
+:- pred pseudo_section_flag(pseudo_section_flag::in, string::out) is det.
+
+pseudo_section_flag(a, "a").
+pseudo_section_flag(w, "w").
+pseudo_section_flag(x, "x").
+pseudo_section_flag(m, "m").
+pseudo_section_flag(s, "s").
-section_pseudo_op_flags = "awxMS".
+ % If a .section pseudo-instruction has 'm' flag, there has to be
+ % 'type' argument as its second argument.
+ %
+:- pred check_pseudo_section_m_flag(list(pseudo_section_flag)::in,
+ bool::out) is det.
+
+check_pseudo_section_m_flag([], no).
+check_pseudo_section_m_flag([Flag | Flags], Result) :-
+ pseudo_section_flag(Flag, FlagType),
+ ( FlagType = "m" ->
+ Result = yes
+ ;
+ check_pseudo_section_m_flag(Flags, Result)
+ ).
- % The optional type of '.section' pseudo-op may contain:
- % @progbits - section contains data
- % @nobits - section does not contain data
+ % Checks if .type argument of .section pseudo-instruction is valid.
%
-:- pred check_pseudo_section_type(string::in) is semidet.
+:- pred check_pseudo_section_type(pseudo_section_type::in, string::out)
+ is det.
-check_pseudo_section_type("@progbits").
-check_pseudo_section_type("@nobits").
+check_pseudo_section_type(progbits, "@progbits").
+check_pseudo_section_type(nobits, "@nobits").
- % Two valid values of 'type_desc' field in pseudo-op '.type':
- % @function
- % @object
+ % Checks if type_desc argument of .section pseudo-instruction is valid.
%
-:- pred check_pseudo_type_desc(string::in) is semidet.
+:- pred check_pseudo_type_desc(pseudo_section_type_desc::in, string::out)
+ is det.
-check_pseudo_type_desc("@function").
-check_pseudo_type_desc("@function").
+check_pseudo_type_desc(function, "@function").
+check_pseudo_type_desc(object, "@object").
:- func comment_length = int.
@@ -532,7 +551,7 @@
check_operand_not_immediate(Src, Result1),
(
Result1 = yes,
- operand_type(Src, SrcType),
+ operand_to_string(Src, SrcType),
check_operand_register(Dest, DestRes),
(
DestRes = yes,
@@ -546,7 +565,7 @@
++ " invalid condition third operand")
),
put(Stream, "\t" ++ Instr ++ "\t", !IO),
- operand_type(Dest, DestType),
+ operand_to_string(Dest, DestType),
put(Stream, SrcType ++ ", " ++ DestType ++ "\t", !IO)
;
DestRes = no,
@@ -562,7 +581,7 @@
check_operand_register(Op, Result),
(
Result = yes,
- operand_type(Op, RegType),
+ operand_to_string(Op, RegType),
put(Stream, "\tbswap\t" ++ RegType ++ "\t\t", !IO)
;
Result = no,
@@ -581,7 +600,7 @@
check_operand_not_immediate(Target, Result),
(
Result = yes,
- operand_type(Target, TargetType),
+ operand_to_string(Target, TargetType),
put(Stream, "\tcall\t" ++ TargetType ++ "\t\t", !IO)
;
Result = no,
@@ -617,8 +636,8 @@
check_operand_register(Dest, Result2),
(
Result2 = yes,
- operand_type(Src, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Src, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tcmp\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -634,7 +653,7 @@
check_operand_not_mem_ref(Op, Result),
(
Result = no,
- operand_type(Op, OpType),
+ operand_to_string(Op, OpType),
put(Stream, "\tcmpxchg8b" ++ OpType, !IO)
;
Result = yes,
@@ -666,23 +685,23 @@
output_x86_64_inst(Stream, idiv(Operand), !IO) :-
output_instr_not_imm_dest(Stream, "idiv", Operand, no, !IO).
output_x86_64_inst(Stream, imul(Src, Dest, Mult), !IO) :-
- operand_type(Src, SrcType),
+ operand_to_string(Src, SrcType),
put(Stream, "\timul\t" ++ SrcType, !IO),
(
Dest = yes(DestRes),
check_operand_register(DestRes, Result1),
(
Result1 = yes,
- operand_type(DestRes, DestType)
+ operand_to_string(DestRes, DestType)
;
Result1 = no,
- TempReg = operand_reg(gp_reg(13)),
- operand_type(TempReg, DestType)
+ TempReg = operand_reg(get_scratch_reg),
+ operand_to_string(TempReg, DestType)
),
put(Stream, ", " ++ DestType, !IO),
(
Mult = yes(MultRes),
- operand_type(MultRes, Op3),
+ operand_to_string(MultRes, Op3),
put(Stream, ", " ++ Op3 ++ " ", !IO)
;
Mult = no,
@@ -699,7 +718,7 @@
output_x86_64_inst(Stream, jrcxz(RelOffset), !IO) :-
output_instr_8bit_rel_offset(Stream, "jrcxz", RelOffset, !IO).
output_x86_64_inst(Stream, jmp(Target), !IO) :-
- operand_type(Target, Op),
+ operand_to_string(Target, Op),
put(Stream, "\tjmp\t" ++ Op ++ "\t\t", !IO).
output_x86_64_inst(Stream, lea(Src, Dest), !IO) :-
check_operand_not_mem_ref(Src, Result1),
@@ -708,8 +727,8 @@
check_operand_register(Dest, Result2),
(
Result2 = yes,
- operand_type(Src, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Src, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tlea\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -751,7 +770,7 @@
put(Stream, "\tpopfq\t", !IO).
output_x86_64_inst(Stream, push(Operand), !IO) :-
put(Stream, "\tpush\t", !IO),
- operand_type(Operand, OperandType),
+ operand_to_string(Operand, OperandType),
put(Stream, OperandType ++ "\t", !IO).
output_x86_64_inst(Stream, pushfq, !IO) :-
put(Stream, "\tpushfq\t", !IO).
@@ -762,8 +781,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\trc\t" ++ Cond, !IO),
put(Stream, Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
@@ -807,8 +826,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tro" ++ Dir ++ "\t", !IO),
put(Stream, Op1 ++ ", " ++ Op2 ++ "\t\t", !IO)
;
@@ -828,8 +847,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tsal\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -848,8 +867,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tshl\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -868,8 +887,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tsar\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -903,9 +922,9 @@
check_operand_register(Reg, Result3),
(
Result3 = yes,
- operand_type(Amnt, Op1),
- operand_type(Amnt, Op2),
- operand_type(Amnt, Op3),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Amnt, Op2),
+ operand_to_string(Amnt, Op3),
put(Stream, "\tshld\t" ++ Op1 ++ ", ", !IO),
put(Stream, Op2 ++ ", " ++ Op3 ++ "\t", !IO)
;
@@ -930,8 +949,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tshr\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -953,9 +972,9 @@
check_operand_register(Reg, Result3),
(
Result3 = yes,
- operand_type(Amnt, Op1),
- operand_type(Amnt, Op2),
- operand_type(Amnt, Op3),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Amnt, Op2),
+ operand_to_string(Amnt, Op3),
put(Stream, "\tshrd\t" ++ Op1 ++ ", ", !IO),
put(Stream, Op2 ++ ", " ++ Op3 ++ "\t", !IO)
;
@@ -986,8 +1005,8 @@
check_operand_not_immediate(Src2, Result2),
(
Result2 = yes,
- operand_type(Src1, Op1),
- operand_type(Src2, Op2),
+ operand_to_string(Src1, Op1),
+ operand_to_string(Src2, Op2),
put(Stream, "\ttest\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -1006,8 +1025,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Src, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Src, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\txadd\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -1026,8 +1045,8 @@
check_operand_reg_or_mem(Src2, Result2),
(
Result2 = yes,
- operand_type(Src1, Op1),
- operand_type(Src2, Op2),
+ operand_to_string(Src1, Op1),
+ operand_to_string(Src2, Op2),
put(Stream, "\txchg\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -1062,26 +1081,46 @@
% Output a string representation of an immediate value.
%
-:- pred imm_op_type(imm_operand::in, string::out) is det.
+:- pred imm_op_to_string(imm_operand::in, string::out) is det.
-imm_op_type(imm8(int8(Val)), ImmVal) :-
+imm_op_to_string(imm8(int8(Val)), ImmVal) :-
ImmVal = "$" ++ string.int_to_string(Val).
-imm_op_type(imm16(int16(Val)), ImmVal) :-
+imm_op_to_string(imm16(int16(Val)), ImmVal) :-
ImmVal = "$" ++ string.int_to_string(Val).
-imm_op_type(imm32(int32(Val)), ImmVal) :-
+imm_op_to_string(imm32(int32(Val)), ImmVal) :-
ImmVal = "$" ++ string.int_to_string(Val).
-:- func reg_type(gp_reg) = string.
+:- pred reg_to_string(x86_64_reg::in, string::out) is det.
-reg_type(gp_reg(RegNum)) = "%r" ++ string.int_to_string(RegNum).
+reg_to_string(rax, "%rax").
+reg_to_string(rbx, "%rbx").
+reg_to_string(rcx, "%rcx").
+reg_to_string(rdx, "%rdx").
+reg_to_string(rbp, "%rbp").
+reg_to_string(rsi, "%rsi").
+reg_to_string(rdi, "%rdi").
+reg_to_string(rsp, "%rsp").
+reg_to_string(r8, "%r8").
+reg_to_string(r9, "%r9").
+reg_to_string(r10, "%r10").
+reg_to_string(r11, "%11").
+reg_to_string(r12(Offset), RegStr) :-
+ ( Offset > 0 ->
+ RegStr = string.int_to_string(Offset) ++ "(%r12)"
+ ;
+ RegStr = "%r12"
+ ).
+reg_to_string(r13, "%r13").
+reg_to_string(r14, "%r14").
+reg_to_string(r15, "%r15").
% Output a string representation of a memory reference.
%
-:- pred mem_ref_type(x86_64_mem_ref::in, string::out) is det.
+:- pred mem_ref_to_string(x86_64_mem_ref::in, string::out) is det.
-mem_ref_type(mem_abs(DirectMemRef), MemRefVal) :-
+mem_ref_to_string(mem_abs(DirectMemRef), MemRefVal) :-
base_address_type(DirectMemRef, MemRefVal).
-mem_ref_type(mem_rip(InstrPtr), MemRefVal) :-
+mem_ref_to_string(mem_rip(InstrPtr), MemRefVal) :-
instr_ptr_type(InstrPtr, MemRefVal).
% Output a string representation of a base address in a memory reference.
@@ -1089,11 +1128,12 @@
:- pred base_address_type(base_address::in, string::out) is det.
base_address_type(base_reg(Offset, Reg), BaseAddress) :-
+ reg_to_string(Reg, RegStr),
( Offset = 0 ->
- BaseAddress = "(" ++ reg_type(Reg) ++ ")"
+ BaseAddress = "(" ++ RegStr ++ ")"
;
BaseAddress = string.int_to_string(Offset) ++
- "(" ++ reg_type(Reg) ++ ")"
+ "(" ++ RegStr ++ ")"
).
base_address_type(base_expr(Expr), DispType) :-
DispType = "$" ++ Expr.
@@ -1117,9 +1157,9 @@
% Output a string representation of a relative offset.
%
-:- pred rel_offset_type(rel_offset::in, string::out) is det.
+:- pred rel_offset_to_string(rel_offset::in, string::out) is det.
-rel_offset_type(ro8(int8(Val)), RelOffsetVal) :-
+rel_offset_to_string(ro8(int8(Val)), RelOffsetVal) :-
check_signed_int_size(8, Val, Result),
(
Result = yes,
@@ -1130,10 +1170,10 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro8(int8): unexpected:"
+ unexpected(this_file, "rel_offset_to_string: ro8(int8): unexpected:"
++ " check_signed_int_size failed")
).
-rel_offset_type(ro16(int16(Val)), RelOffsetVal) :-
+rel_offset_to_string(ro16(int16(Val)), RelOffsetVal) :-
check_signed_int_size(16, Val, Result),
(
Result = yes,
@@ -1144,10 +1184,10 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro16(int16): unexpected"
+ unexpected(this_file, "rel_offset_to_string: ro16(int16): unexpected"
++ " check_signed_int_size failed")
).
-rel_offset_type(ro32(int32(Val)), RelOffsetVal) :-
+rel_offset_to_string(ro32(int32(Val)), RelOffsetVal) :-
check_signed_int_size(32, Val, Result),
(
Result = yes,
@@ -1158,20 +1198,20 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro32(int32): unexpected"
+ unexpected(this_file, "rel_offset_to_string: ro32(int32): unexpected"
++ " check_signed_int_size failed")
).
-operand_type(operand_reg(Reg), RegType) :-
- RegType = reg_type(Reg).
-operand_type(operand_imm(Imm), ImmVal) :-
- imm_op_type(Imm, ImmVal).
-operand_type(operand_mem_ref(MemRef), MemRefVal) :-
- mem_ref_type(MemRef, MemRefVal).
-operand_type(operand_rel_offset(RelOffset), RelOffsetType) :-
- rel_offset_type(RelOffset, RelOffsetType).
-operand_type(operand_label(Label), (Label)).
+operand_to_string(operand_reg(Reg), RegType) :-
+ reg_to_string(Reg, RegType).
+operand_to_string(operand_imm(Imm), ImmVal) :-
+ imm_op_to_string(Imm, ImmVal).
+operand_to_string(operand_mem_ref(MemRef), MemRefVal) :-
+ mem_ref_to_string(MemRef, MemRefVal).
+operand_to_string(operand_rel_offset(RelOffset), RelOffsetType) :-
+ rel_offset_to_string(RelOffset, RelOffsetType).
+operand_to_string(operand_label(Label), (Label)).
%-----------------------------------------------------------------------------%
%
@@ -1186,13 +1226,13 @@
is det <= stream.writer(Stream, string, io).
output_instr_not_imm_dest(Stream, Instr, Op1, Op2, !IO) :-
- operand_type(Op1, Op1Type),
+ operand_to_string(Op1, Op1Type),
(
Op2 = yes(Op2Result),
check_not_both_memory_ops(Op1, Op2Result, Result1),
(
Result1 = yes,
- operand_type(Op2Result, Op2Type),
+ operand_to_string(Op2Result, Op2Type),
check_operand_not_immediate(Op2Result, Result2),
(
Result2 = yes,
@@ -1225,7 +1265,7 @@
check_operand_rel_offset(RelOffset, Result1),
(
Result1 = yes,
- operand_type(RelOffset, RelOffsetType),
+ operand_to_string(RelOffset, RelOffsetType),
( string.to_int(RelOffsetType, Val) ->
check_signed_int_size(8, Val, Result2),
(
@@ -1255,11 +1295,11 @@
check_operand_not_immediate(Src, Result1),
(
Result1 = yes,
- operand_type(Src, Op1),
+ operand_to_string(Src, Op1),
check_operand_not_mem_ref(Idx, Result2),
(
Result2 = yes,
- operand_type(Idx, Op2),
+ operand_to_string(Idx, Op2),
( string.to_int(Op2, IdxInt) ->
check_signed_int_size(8, IdxInt, Result3),
(
@@ -1297,14 +1337,14 @@
instr_condition(Cond, CondRes),
put(Stream, "\t" ++ Instr, !IO),
put(Stream, CondRes ++ "\t", !IO),
- operand_type(Op1, Op1Type),
+ operand_to_string(Op1, Op1Type),
put(Stream, Op1Type, !IO),
(
Op2 = yes(Op2Res),
check_operand_register(Op2Res, Result3),
(
Result3 = yes,
- operand_type(Op2Res, Op2Type),
+ operand_to_string(Op2Res, Op2Type),
put(Stream, ", " ++ Op2Type, !IO)
;
Result3 = no,
@@ -1327,7 +1367,7 @@
check_rc_first_operand(Op, Result) :-
( Op = operand_imm(_) ->
- operand_type(Op, OpType),
+ operand_to_string(Op, OpType),
( string.to_int(OpType, OpInt) ->
check_unsigned_int_size(8, OpInt, Result1),
(
@@ -1393,7 +1433,7 @@
check_operand_unsigned_imm_or_reg(Operand, Result) :-
( Operand = operand_imm(Imm) ->
- imm_op_type(Imm, ImmType),
+ imm_op_to_string(Imm, ImmType),
( string.to_int(ImmType, ImmInt) ->
(
check_unsigned_int_size(32, ImmInt, Result1),
Index: compiler/x86_64_regs.m
===================================================================
RCS file: compiler/x86_64_regs.m
diff -N compiler/x86_64_regs.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/x86_64_regs.m 19 Feb 2007 06:05:32 -0000
@@ -0,0 +1,258 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2007 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: x86_64_regs.m.
+% Main author: fhandoko.
+%
+% llds.lval ===> reg_locn
+%
+% NOTE:
+% The first field of reg_map type is a list of available scratch registers.
+% Although the reg_map is updated everytime a scratch register is used in an
+% instruction (updated here means that the new reg_map is equivalent to the
+% old reg_map with the first element (the used scratch register) being
+% removed), it does not seem to work well. It seems to always get the first
+% scratch register. So, there are instructions in which the next instruction
+% overrides the value in a scratch register being used by a previous
+% instruction.
+%-----------------------------------------------------------------------------%
+
+:- module ll_backend.x86_64_regs.
+:- interface.
+
+:- import_module ll_backend.llds.
+:- import_module ll_backend.x86_64_instrs.
+
+:- import_module assoc_list.
+
+%----------------------------------------------------------------------------%
+
+ % This type stores information about the mapping from MVM registers
+ % to x86_64 registers. MVM registers will correspond to either
+ % (1) a physical x86_64 register
+ % or (2) a slot in the fake_reg array (see runtime/mercury_engine.h).
+ %
+:- type reg_map.
+
+ % This type represents the location of an MVM register on x86_64
+ % hardware. `actual/1' is a phyical x86_64 register. `virtual/1'
+ % is the slot in the fake reg array given by the argument.
+ %
+:- type reg_locn
+ ---> actual(x86_64_reg)
+ ; virtual(int). % Index into fake reg array.
+
+ % Create an association list of lvals and reg_lcons.
+ %
+:- pred llds_reg_locn(assoc_list(llds.lval, reg_locn)::out) is det.
+
+ % Create a reg_map given an association list of lvals and reg_locns.
+ % Throws an exception if an l-value in the association list does not
+ % correspond to a MVM register.
+ %
+:- func reg_map_init(assoc_list(llds.lval, reg_locn)) = reg_map.
+
+ % Given an LLDS lval that corresponds to a virtual machine register
+ % look up it's actual location according to the current register mapping.
+ % Throws an exception for l-values that do not correspond to virtual
+ % machine registers.
+ %
+:- func reg_map_lookup_reg_locn(reg_map, llds.lval) = reg_locn.
+
+ % Reset the contents of scratch registers. As a result, all scratch
+ % registers will be available.
+ %
+:- pred reg_map_reset_scratch_reg_info(reg_map::in, reg_map::out) is det.
+
+ % Given a reg_map, get the first available scratch register.
+ %
+:- func reg_map_get_scratch_reg(reg_map) = x86_64_reg.
+
+ % Get an x86_64_register.
+ %
+:- func get_scratch_reg = x86_64_reg.
+
+ % Remove the first index of scratch register list (which is the first
+ % field of reg_map).
+ %
+:- pred reg_map_remove_scratch_reg(reg_map::in, reg_map::out) is det.
+
+%----------------------------------------------------------------------------%
+%----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module libs.compiler_util.
+
+:- import_module bool.
+:- import_module list.
+:- import_module map.
+:- import_module pair.
+:- import_module string.
+
+:- import_module io.
+
+%----------------------------------------------------------------------------%
+%
+% LLDS -> x86_64 register mapping.
+%
+
+:- type reg_map
+ ---> reg_map(
+ scratch_reg_info :: list(x86_64_reg),
+ % A list of available scratch registers.
+ map(llds.lval, reg_locn)
+ % Mapping lval to an actual or virtual register.
+ ).
+
+%----------------------------------------------------------------------------%
+
+llds_reg_locn([
+ sp - actual(r12(0)), % The top of non-det stack frame.
+ succip - actual(r13),
+ reg(reg_r, 1) - actual(r14),
+ reg(reg_r, 2) - actual(r15),
+ reg(reg_r, 3) - virtual(4),
+ hp - virtual(5),
+ reg(reg_r, 4) - virtual(6),
+ reg(reg_r, 5) - virtual(7),
+ curfr - virtual(8),
+ maxfr - virtual(9),
+ reg(reg_r, 6) - virtual(10),
+ reg(reg_r, 7) - virtual(11),
+ reg(reg_r, 8) - virtual(12),
+ reg(reg_r, 9) - virtual(13),
+ reg(reg_r, 10) - virtual(14),
+ reg(reg_r, 11) - virtual(15),
+ reg(reg_r, 12) - virtual(16),
+ reg(reg_r, 13) - virtual(17),
+ reg(reg_r, 14) - virtual(18),
+ reg(reg_r, 15) - virtual(19),
+ reg(reg_r, 16) - virtual(20),
+ reg(reg_r, 17) - virtual(21),
+ reg(reg_r, 18) - virtual(22),
+ reg(reg_r, 19) - virtual(23),
+ reg(reg_r, 20) - virtual(24),
+ reg(reg_r, 21) - virtual(25),
+ reg(reg_r, 22) - virtual(26),
+ reg(reg_r, 23) - virtual(27),
+ reg(reg_r, 24) - virtual(28),
+ reg(reg_r, 25) - virtual(29),
+ reg(reg_r, 26) - virtual(30),
+ reg(reg_r, 27) - virtual(31),
+ reg(reg_r, 28) - virtual(32),
+ reg(reg_r, 29) - virtual(33),
+ reg(reg_r, 30) - virtual(34),
+ reg(reg_r, 31) - virtual(35),
+ reg(reg_r, 32) - virtual(36)
+ ]).
+
+reg_map_init(AssocRegMap) = RegMap :-
+ map.init(Map0),
+ assoc_list.keys(AssocRegMap, ListOfKeys),
+ check_if_all_mvm_registers(ListOfKeys, Result),
+ (
+ Result = yes,
+ map.det_insert_from_assoc_list(Map0, AssocRegMap, Map1),
+ RegMap = reg_map(init_scratch_regs, Map1)
+ ;
+ Result = no,
+ unexpected(this_file, "reg_map_init: unexpected: non-MVM register"
+ ++ " found in the association list")
+ ).
+
+reg_map_lookup_reg_locn(Map, Lval) = RegLocn :-
+ Map = reg_map(_, RegMap),
+ (
+ ( Lval = parent_stackvar(_)
+ ; Lval = succip_slot(_)
+ ; Lval = redoip_slot(_)
+ ; Lval = redofr_slot(_)
+ ; Lval = succfr_slot(_)
+ ; Lval = prevfr_slot(_)
+ ; Lval = mem_ref(_)
+ ; Lval = global_var_ref(_)
+ )
+ ->
+ unexpected(this_file, "reg_map_lookup_reg_locn: unexpected: "
+ ++ "lval is not a virtual machine register")
+ ;
+ Lval = lvar(_)
+ ->
+ unexpected(this_file, "reg_map_lookup_reg_locn: unexpected: "
+ ++ "lvar/1 during x86_64 code generation")
+ ;
+ map.lookup(RegMap, Lval, RegLocn)
+ ).
+
+reg_map_reset_scratch_reg_info(RegMap0, RegMap) :-
+ ScratchRegs = init_scratch_regs,
+ RegMap = RegMap0 ^ scratch_reg_info := ScratchRegs.
+
+reg_map_get_scratch_reg(RegMap) = ScratchReg :-
+ ScratchRegs = RegMap ^ scratch_reg_info,
+ ( list.index0(ScratchRegs, first_list_idx, ScratchReg0) ->
+ ScratchReg = ScratchReg0
+ ;
+ unexpected(this_file, "reg_map_get_scratch_reg: unexpected:"
+ ++ " scratch registers exhausted")
+ ).
+
+reg_map_remove_scratch_reg(RegMap0, RegMap) :-
+ ScratchRegs0 = RegMap0 ^ scratch_reg_info,
+ ( list.drop(first_list_idx, ScratchRegs0, ScratchRegs1) ->
+ RegMap = RegMap0 ^ scratch_reg_info := ScratchRegs1
+ ;
+ unexpected(this_file, "reg_map_remove_scratch_reg: unexpected:"
+ ++ " scratch registers exhausted")
+ ).
+
+ % Check if all l-values in the association list correspond to MVM
+ % registers.
+ %
+:- pred check_if_all_mvm_registers(list(llds.lval)::in, bool::out) is det.
+
+check_if_all_mvm_registers([], yes).
+check_if_all_mvm_registers([Lval | Lvals], Result) :-
+ (
+ ( Lval = reg(reg_r, _)
+ ; Lval = succip
+ ; Lval = maxfr
+ ; Lval = curfr
+ ; Lval = hp
+ ; Lval = sp
+ )
+ ->
+ check_if_all_mvm_registers(Lvals, Result)
+ ;
+ Result = no
+ ).
+
+ % Initialize scratch registers to be used in an instruction.
+ %
+:- func init_scratch_regs = list(x86_64_reg).
+
+init_scratch_regs = [r9, r10, r11].
+
+get_scratch_reg = r9.
+
+ % Returns the index of the first element in the list.
+ %
+:- func first_list_idx = int.
+
+first_list_idx = 0.
+
+%----------------------------------------------------------------------------%
+
+:- func this_file = string.
+
+this_file = "x86_64_regs.m".
+
+%----------------------------------------------------------------------------%
+:- end_module ll_backend.x86_64_regs.
+%----------------------------------------------------------------------------%
1347 lines
48 KiB
Mathematica
1347 lines
48 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2007 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: x86_64_instrs.m.
|
|
% Main author: fhandoko.
|
|
%
|
|
% This module contains the representations of the x86_64 instructions.
|
|
%
|
|
% NOTE:
|
|
% Instructions that make use of segment registers and string operations
|
|
% (such as compare_strings) have not been implemented.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend.x86_64_instrs.
|
|
:- 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_inst :: list(x86_64_instr),
|
|
x86_64_inst_comment :: string
|
|
).
|
|
|
|
:- type label_name == string.
|
|
|
|
:- type x86_64_instr
|
|
---> x86_64_comment(string)
|
|
; x86_64_label(label_name)
|
|
; x86_64_directive(pseudo_op)
|
|
; x86_64_instr(x86_64_inst).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Signed integers of various sizes.
|
|
%
|
|
:- type int8 ---> int8(int). % In bottom 8 bits.
|
|
:- type int16 ---> int16(int). % In bottom 16 bits.
|
|
:- type int32 ---> int32(int). % in bottom 32 bits.
|
|
|
|
% Unsigned integers of various sizes.
|
|
%
|
|
:- type uint8 ---> uint8(int). % In bottom 8 bits.
|
|
:- type uint16 ---> uint16(int). % In bottom 16 bits.
|
|
:- type uint32 ---> uint32(int). % In bottom 32 bits.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Conditional direction.
|
|
%
|
|
:- type direction
|
|
---> f % Forward.
|
|
; r. % Reverse.
|
|
|
|
% Condition of flags register.
|
|
%
|
|
:- type condition
|
|
---> o % Overflow (OF = 1).
|
|
; no % Not Overflow (OF = 0).
|
|
; b % Below (CF = 1).
|
|
; c % Carry (CF = 1).
|
|
; nae % Not Above or Equal (CF = 1).
|
|
; nb % Not Below (CF = 0).
|
|
; nc % Not Carry (CF = 0).
|
|
; ae % Above or Equal (CF = 0).
|
|
; z % Zero (ZF = 1).
|
|
; e % Equal (ZF = 1).
|
|
; nz % Not Zero (ZF = 0).
|
|
; ne % Not Equal (ZF = 0).
|
|
; be % Below or Equal (CF = 1 or ZF = 1).
|
|
; na % Not Above (CF = 1 or ZF = 1).
|
|
; nbe % Not Below or Equal (CF = 0 or ZF = 0).
|
|
; a % Above (CF = 0 or ZF = 0).
|
|
; s % Sign (SF = 1).
|
|
; ns % Not Sign (SF = 0).
|
|
; p % Parity (PF = 1).
|
|
; pe % Parity even (PF = 1).
|
|
; np % Not parity (PF = 0).
|
|
; po % Parity odd (PF = 0).
|
|
; l % Less (SF <> OF).
|
|
; nge % Not Greater or Equal (SF <> OF).
|
|
; nl % Not Less (SF = OF).
|
|
; ge % Greater or Equal (SF = OF).
|
|
; le % Less or Equal (ZF = 1 or SF <> OF).
|
|
; ng % Not Greater (ZF = 1 or SF <> OF).
|
|
; nle % Not Less or Equal (ZF = 0 and SF = OF).
|
|
; g. % Greater (ZF = 0 and SF = OF).
|
|
|
|
% Optional flags argument of .section pseudo_op.
|
|
%
|
|
:- type pseudo_section_flag
|
|
---> a % section is allocatable.
|
|
; w % section is writable.
|
|
; x % section is executable.
|
|
; m % section is mergeable.
|
|
; s. % section contains zero terminated string.
|
|
|
|
% An optional type of '.section' pseudo-op.
|
|
%
|
|
:- type pseudo_section_type
|
|
---> progbits % section contains data.
|
|
; nobits. % section does not contain data.
|
|
|
|
% type_desc field of .section pseudo-op.
|
|
%
|
|
:- type pseudo_section_type_desc
|
|
---> function
|
|
; object.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% x86_64 pseudo-ops.
|
|
%
|
|
|
|
% GNU assembler pseudo-ops for the x86_64.
|
|
% Details on GNU assembler 'as' documentation in the section entitled
|
|
% "Pseudo Ops".
|
|
%
|
|
:- type pseudo_op
|
|
---> abort
|
|
% stop the assembly immediately.
|
|
|
|
; align(
|
|
align_bits :: int,
|
|
align_fill_value :: maybe(int),
|
|
align_skip_bytes :: maybe(int)
|
|
)
|
|
% Advance the location counter until it is a multiple of
|
|
% 'align_bits'. The second and third arguments are optional.
|
|
% 'align_fill_value': value to be stored in the padding bytes.
|
|
% 'align_skip_bytes': maximum number of bytes to be skipped.
|
|
|
|
; ascii(
|
|
ascii_literals :: list(string)
|
|
)
|
|
% 'ascii_literals' contain zero or more string literals. Assembles
|
|
% each literal into consecutive addresses.
|
|
|
|
; asciiz(
|
|
asciiz_literals :: list(string)
|
|
)
|
|
% Simiar to '.ascii', but each string is followed by a zero byte.
|
|
|
|
; balign(
|
|
balign_bits :: int,
|
|
balign_fill_value :: maybe(int),
|
|
balign_skip_bytes :: maybe(int)
|
|
)
|
|
% Similar to 'align'.
|
|
|
|
; byte(
|
|
byte_exprs :: list(string)
|
|
)
|
|
% 'byte_exprs' contains zero or more expressions. Each expression is
|
|
% assembled into the next byte.
|
|
|
|
; comm(
|
|
comm_symbol :: string,
|
|
comm_length :: int,
|
|
comm_align :: maybe(int)
|
|
)
|
|
% Declare a common symbol 'comm_symbol'. Allocate 'comm_length'
|
|
% bytes if the symbol has not been defined.
|
|
% (optional) 'comm_align' is the desired alignment of the symbol.
|
|
|
|
; data(
|
|
data_subsection :: maybe(int)
|
|
)
|
|
% Tells assembler to assemble the following statements onto the end
|
|
% of the data subsection numbered 'data_subsection'.
|
|
|
|
; desc(
|
|
desc_symbol :: string,
|
|
desc_abs_expr :: string
|
|
)
|
|
% Set the descriptor of the symbol to the low 16 bits of
|
|
% 'desc_abs_expr'.
|
|
|
|
; def(
|
|
def_name :: string
|
|
)
|
|
% Begin defining debugging information for a symbol 'def_name'.
|
|
|
|
; dim
|
|
% Tell to include auxiliary debugging information in the symbol
|
|
% table.
|
|
|
|
; double(
|
|
double_nums :: list(float)
|
|
)
|
|
% 'double_nums' contains zero or more floating point numbers.
|
|
|
|
; eject
|
|
% Force a page break.
|
|
|
|
; x86_64_pseudo_else
|
|
% As in 'if-then-else' conditional expression.
|
|
|
|
; elseif
|
|
% Shorthand for the beginning a new '.if' block.
|
|
|
|
; end
|
|
% Mark the end of the assembly file.
|
|
|
|
; endef
|
|
% End of a symbol definition begun with '.def'.
|
|
|
|
; endfunc
|
|
% End of a function specified with '.func'.
|
|
|
|
; endif
|
|
% End of a block of conditional code.
|
|
|
|
; endm
|
|
% End of assembly macro.
|
|
|
|
; equ(
|
|
equ_symbol :: string,
|
|
equ_expr :: string
|
|
)
|
|
% Set the value of 'equ_symbol' to 'equ_expr'.
|
|
|
|
; equiv(
|
|
equiv_symbol :: string,
|
|
equiv_expr :: string
|
|
)
|
|
% Like '.equ' except that the assembler will signal an error
|
|
% if 'equiv_symbol' is already defined.
|
|
|
|
; err
|
|
% Print an error message.
|
|
|
|
; exitm
|
|
% Exit early from the current macro definition.
|
|
|
|
; extern
|
|
% Ignored. '.extern' is accepted for compatibility only.
|
|
|
|
; fail_(
|
|
fail_expr :: string
|
|
)
|
|
% Generate an error or a warning. If 'fail_expr' is 500 or more, it
|
|
% prints a warning message. Otherwise, it prints an error message.
|
|
|
|
; file(
|
|
file_name :: string
|
|
)
|
|
% Start a new logical file.
|
|
|
|
; fill(
|
|
fill_repeat :: int,
|
|
fill_size :: maybe(int),
|
|
fill_value :: maybe(int)
|
|
)
|
|
% Emits 'fill_repeat' copies of 'fill_size' byte. The contents of
|
|
% each 'fil_repeat' bytes is taken from an 8-byte number. The
|
|
% highest order 4 bytes are zero. The lowest order 4 bytes are
|
|
% 'fill_value'. The last 2 arguments are optional.
|
|
|
|
; float(
|
|
float_nums :: list(float)
|
|
)
|
|
% 'float_nums' contains zero or more floating point numbers.
|
|
|
|
; func_(
|
|
func_name :: string,
|
|
func_label :: string
|
|
)
|
|
% Emits debugging information to denote function 'func_name' and
|
|
% is ignored unless the file is assembled with debugging enabled.
|
|
% 'func_label' is the entry point of the function.
|
|
|
|
; global(
|
|
global_symbol :: string
|
|
)
|
|
% makes the global_symbol' visible to other programs that are linked
|
|
% with it.
|
|
|
|
; globl(
|
|
globl_symbol :: string
|
|
)
|
|
% makes the globl_symbol' visible to other programs that are linked
|
|
|
|
; hidden(
|
|
hidden_name :: string
|
|
)
|
|
% Override the named symbol default visibility (which is set by
|
|
% their binding: local, global or weak).
|
|
|
|
; hword(
|
|
hword_exprs :: list(string)
|
|
)
|
|
% 'hword_exprs' contains zero or more expressions and emit a 16-bit
|
|
% number for each. Synonym for '.short'.
|
|
|
|
; ident
|
|
% To place tags in object files.
|
|
|
|
; x86_64_pseudo_if(
|
|
if_expr :: string
|
|
)
|
|
% Mark the beginning of a conditional section.
|
|
|
|
; ifdef(
|
|
ifdef_symbol :: string
|
|
)
|
|
% Assemble the following section of code if 'ifdef_symbol' has been
|
|
% defined.
|
|
|
|
; ifc(
|
|
ifc_string1 :: string,
|
|
ifc_string2 :: string
|
|
)
|
|
% Assemble the following section of code if the two strings are the
|
|
% same.
|
|
|
|
; ifeq(
|
|
ifeq_expr :: string
|
|
)
|
|
% Assemble the following section of code if the argument is zero.
|
|
|
|
; ifge(
|
|
ifge_expr :: string
|
|
)
|
|
% Assemble the following section of code if the argument is greater
|
|
% than equal to zero.
|
|
|
|
; ifgt(
|
|
ifgt_expr :: string
|
|
)
|
|
% Assemble the following section of code if the argument is greater
|
|
% than zero.
|
|
|
|
; ifle(
|
|
ifle_expr :: string
|
|
)
|
|
% Assemble the following section of code if the argument is less
|
|
% than equal to zero.
|
|
|
|
; iflt(
|
|
iflt_expr :: string
|
|
)
|
|
% Assemble the following section of code if the argument is less
|
|
% than zero.
|
|
|
|
; ifnc(
|
|
ifnc_string1 :: string,
|
|
ifnc_string2 :: string
|
|
)
|
|
% Assemble the following section of code if the two strings are not
|
|
% the same.
|
|
|
|
; ifndef(
|
|
ifndef_symbol :: string
|
|
)
|
|
% Assemble the following section of code if 'ifndef_symbol' has not
|
|
% been defined.
|
|
|
|
; ifnotdef(
|
|
ifnotdef_symbol :: string
|
|
)
|
|
% Synonym for ifndef.
|
|
|
|
; ifne(
|
|
ifne_expr :: string
|
|
)
|
|
% Assemble the following section of code if the argument is not
|
|
% equal to zero.
|
|
|
|
; ifnes(
|
|
ifnes_string1 :: string,
|
|
ifnes_string2 :: string
|
|
)
|
|
% Assemble the following section of code if the two strings are not
|
|
% the same.
|
|
|
|
; include(
|
|
include_file :: string
|
|
)
|
|
% Include supporting 'include_file'.
|
|
|
|
; int(
|
|
int_exprs :: list(string)
|
|
)
|
|
% 'int_exprs' contains zero or more expressions. For each
|
|
% expression, emit a number that, at run time, is the value of that
|
|
% expression.
|
|
|
|
; internal(
|
|
internal_name :: string
|
|
)
|
|
% Like '.hidden' pseudo-op.
|
|
|
|
; lcomm(
|
|
lcomm_symbol :: string,
|
|
lcomm_length :: int
|
|
)
|
|
% Reserve 'lcomm_length' bytes for a local common denoted by
|
|
% 'lcomm_symbol'.
|
|
|
|
; line(
|
|
line_number :: int
|
|
)
|
|
% Change the logical line number.
|
|
|
|
; list
|
|
% Control whether or not assembly listings are generated. This
|
|
% increments the internal counter.
|
|
|
|
; long(
|
|
long_exprs :: list(string)
|
|
)
|
|
% Same as '.int'.
|
|
|
|
; macro
|
|
% Define macro to generate assembly output.
|
|
|
|
; nolist
|
|
% Control whether or not assembly listings are generated. It
|
|
% decrements an internal counter.
|
|
|
|
; p2align(
|
|
p2align_pow_bit :: int,
|
|
p2align_fill_value :: maybe(int),
|
|
p2align_skip_bytes :: maybe(int)
|
|
)
|
|
% Advances the location counter until it is a multiple of
|
|
% 2 ^ ('p2align_pow_bit')
|
|
% p2align_fill_value: value to be stored in padding bytes.
|
|
% 'p2align_skip_bytes: maximum bytes to be skipped.
|
|
|
|
; popsection
|
|
% Replace the current section (and subsection) with the top section
|
|
% (and subsection) on the section stack.
|
|
|
|
; previous
|
|
% Swap the current section (and subsection) with most recently
|
|
% referenced secction (and subsection) prior to this one.
|
|
|
|
; print(string)
|
|
% print string on the standard output.
|
|
|
|
; protected(
|
|
protected_name :: string
|
|
)
|
|
% Like '.hidden' or '.internal'
|
|
|
|
; psize(
|
|
psize_lines :: int,
|
|
psize_cols :: maybe(int)
|
|
)
|
|
% Declare the number of lines specified by 'psize_lines' and
|
|
% an optional number of columns specified by 'psize_cols'.
|
|
|
|
; purgem(
|
|
purgem_name :: string
|
|
)
|
|
% Undefine the macro 'purgem_name' so that later uses of the string
|
|
% will not be expanded.
|
|
|
|
; pushsection(
|
|
pushsection_name :: string,
|
|
pushsection_subsect :: int
|
|
)
|
|
% Push the current section (and subsection) onto the top of the
|
|
% section stack and then replace the current section and subsection
|
|
% with 'pushsection_name' and 'pushsection_subsect'.
|
|
|
|
; quad(
|
|
quad_bignums :: list(string)
|
|
)
|
|
% 'quad_bignums' contains zero or more bignums. For each bignum, it
|
|
% emits an 8-byte-integer.
|
|
|
|
; rept(
|
|
rept_count :: int
|
|
)
|
|
% Repeat the sequence of lines between the '.rept' directive and the
|
|
% next '.endr' directive 'rept_count' times.
|
|
|
|
; sbttl(
|
|
sbttl_subheading :: string
|
|
)
|
|
% Use 'subttl_subheading' as the title (immediately after the title
|
|
% line).
|
|
|
|
; scl(
|
|
scl_class :: string
|
|
)
|
|
% Set the storage-class value for a symbol.
|
|
|
|
; section(
|
|
section_name :: string,
|
|
section_flags :: maybe(list(pseudo_section_flag)),
|
|
section_type :: maybe(pseudo_section_type),
|
|
section_entsize :: maybe(int)
|
|
)
|
|
% ELF section stack manipulation directive.
|
|
|
|
; set(
|
|
set_symbol :: string,
|
|
set_expression :: string
|
|
)
|
|
% Set the value of 'set_symbol' to 'set_expression'
|
|
|
|
; short(
|
|
short_exprs :: list(string)
|
|
)
|
|
|
|
; single(
|
|
single_nums :: list(float)
|
|
)
|
|
% Has the same effect as '.float'.
|
|
|
|
; size(
|
|
size_name :: string,
|
|
size_exprs :: string
|
|
)
|
|
% Set the size associated with symbol'size_name'. The size in bytes
|
|
% is computed from 'size_expr'.
|
|
|
|
; skip(
|
|
skip_size :: int,
|
|
skip_value :: maybe(int)
|
|
)
|
|
% Emit 'skip_size' bytes, each of value 'skip_value' (optional).
|
|
|
|
; sleb128(
|
|
sleb128_exprs :: list(string)
|
|
)
|
|
% Stand for "signed little endian base 128". It is a variable length
|
|
% representation of numbers used by the DWARF symbolic.
|
|
|
|
; space(
|
|
space_size :: int,
|
|
space_fill :: maybe(int)
|
|
)
|
|
% Emit 'space_size' bytes, each of value 'space_fill' (optional).
|
|
|
|
; string(
|
|
string_str :: list(string)
|
|
)
|
|
% Copy the characters in each string inside 'string_strs' to the
|
|
% object file.
|
|
|
|
; struct(
|
|
struct_expr :: string
|
|
)
|
|
% Switch to the absolute section and set the section offset to
|
|
% 'struct_expr'.
|
|
|
|
; subsection(
|
|
subsection_name :: string
|
|
)
|
|
% Replace the current subsection with 'subsection_name'.
|
|
|
|
; symver(
|
|
symver_name :: string,
|
|
symver_alias :: string
|
|
)
|
|
% If 'symver_name' is defined within the file being assembled, it
|
|
% creates a symbol alias with the name 'symver_alias'
|
|
|
|
; tag(
|
|
tag_struct_name :: string
|
|
)
|
|
% Include auxiliary debugging information in the symbol table.
|
|
|
|
; text(
|
|
text_subsection :: maybe(int)
|
|
)
|
|
% Assemble the following statements onto the end of the text
|
|
% subsection numbered zero or 'text_subsection' (if present).
|
|
|
|
; title(
|
|
title_heading :: string
|
|
)
|
|
% Use 'title_heading' as the title when generating assembly listing.
|
|
|
|
; x86_64_pseudo_type(
|
|
type_name :: string,
|
|
type_desc :: pseudo_section_type_desc
|
|
)
|
|
% Set the type of symbol'type_name' to be either a function or an
|
|
% object symbol.
|
|
|
|
; uleb128(
|
|
uleb128_exprs :: list(string)
|
|
)
|
|
% Stands for "unsigned little endian base 128". It is a variable
|
|
% length representation of numbers used by the DWARF symbolic
|
|
% debugging format.
|
|
|
|
; val(
|
|
val_addr :: string
|
|
)
|
|
% Record 'val_addr' as the value attribute of a symbol table entry.
|
|
|
|
; version(
|
|
version_note :: string
|
|
)
|
|
% Create a '.note' section and places into it an ELF formatted note
|
|
% of type NT_VERSION>
|
|
|
|
; weak(
|
|
weak_names :: list(string)
|
|
)
|
|
% Set the weak attribute on the list of symbol in 'weak_names'. If
|
|
% the symbol has not existed, it will be created.
|
|
|
|
; word(
|
|
word_exprs :: list(string)
|
|
).
|
|
% 'word_exprs' contains zero or more expressions.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% x86_64 registers.
|
|
%
|
|
|
|
% 64-bit RFLAGS register holding various status flags and one control flag.
|
|
% Details on amd64-prog-man-vol1 manual p38.
|
|
%
|
|
:- type flags_reg
|
|
---> rflags(int).
|
|
|
|
% General purpose registers on the x86_64.
|
|
% Details on amd64-prog-man-vol1 manual p27.
|
|
%
|
|
|
|
:- type offset == int.
|
|
|
|
:- type x86_64_reg
|
|
---> rax
|
|
; rbx
|
|
; rcx
|
|
; rdx
|
|
; rbp
|
|
; rsi
|
|
; rdi
|
|
; rsp
|
|
; r8
|
|
; r9
|
|
; r10
|
|
; r11
|
|
; r12
|
|
; r13
|
|
; r14
|
|
; r15.
|
|
|
|
% 64-bit instruction pointer register on the x86_64. Instruction pointer
|
|
% RIP is used as a base register for relative addressing. x86_64
|
|
% instructions using RIP can be:
|
|
% rip_constant(%rip)
|
|
% rip_expr(%rip)
|
|
% Details on GNU assembler 'as' documentation in the section entitled
|
|
% "Machine Dependencies: i386-Dependent: i386-Memory".
|
|
%
|
|
:- type instr_ptr
|
|
---> rip_constant(
|
|
rip_byte_offset :: int32
|
|
)
|
|
|
|
; rip_expr(
|
|
rip_expr :: string
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Operands for x86_64 instructions.
|
|
%
|
|
|
|
% Immediate operands for the x86_64 instruction.
|
|
%
|
|
:- type imm_operand
|
|
---> imm8(int8)
|
|
; imm16(int16)
|
|
; imm32(int32).
|
|
|
|
% Memory reference operands for the x86_64 instruction can be an absolute
|
|
% address (given as a displacement from the base address of a data segment)
|
|
% or an instruction-relative address.
|
|
% Details on amd64-prog-man-vol1 p19.
|
|
%
|
|
:- type x86_64_mem_ref
|
|
---> mem_abs(
|
|
mem_abs_address :: base_address
|
|
)
|
|
|
|
; mem_rip(
|
|
instr_rel_address :: instr_ptr
|
|
).
|
|
|
|
% Base address can be relative to the content of a general-purpose register
|
|
% or relative value of an expression (such as arithmetic expression
|
|
% containing labels in data segment).
|
|
%
|
|
:- type base_address
|
|
---> base_reg(
|
|
base_offset :: int,
|
|
base_reg :: x86_64_reg
|
|
)
|
|
|
|
; base_expr(
|
|
base_expr :: string
|
|
).
|
|
|
|
% All operands for the x86_64 instructions.
|
|
%
|
|
:- type operand
|
|
---> operand_reg(x86_64_reg)
|
|
; operand_imm(imm_operand)
|
|
; 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 an offset relative to the instruction
|
|
% pointer.
|
|
%
|
|
:- type rel_offset
|
|
---> ro8(int8) % Signed 8-bit offset (in bottom 8 bits).
|
|
; ro16(int16) % Signed 16-bit offset (in bottom 16 bits).
|
|
; ro32(int32). % Signed 32-bit offset (in bottom 32 bits).
|
|
|
|
% x86_64 instruction's operand can be a register, memory reference,
|
|
% signed relative offset or a label.
|
|
%
|
|
:- type rmrol
|
|
---> rmrol_reg(x86_64_reg)
|
|
; rmrol_mem_ref(x86_64_mem_ref)
|
|
; rmrol_rel_offset(rel_offset)
|
|
; rmrol_label(
|
|
rmrol_label_name :: string
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% x86_64 instructions.
|
|
%
|
|
|
|
% We use At&T style instructions where the source comes before the
|
|
% destination.
|
|
%
|
|
:- type x86_64_inst
|
|
---> adc(
|
|
adc_src :: operand,
|
|
% 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,
|
|
% 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,
|
|
% 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.
|
|
|
|
; bs(
|
|
bs_src :: operand,
|
|
% register or memory location
|
|
bs_dst :: operand,
|
|
% register
|
|
bs_cond :: direction
|
|
% "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(
|
|
bswap_reg :: operand
|
|
)
|
|
% Byte swap. Reverses the byte order of the specified 'operand'.
|
|
% Details on amd64-prog-man-vol3 manual p76.
|
|
|
|
; bt(
|
|
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 :: 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 :: 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 :: 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(
|
|
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
|
|
% Sign-extend AL into AX.
|
|
% Details on amd64-prog-man-vol3 manual p94.
|
|
|
|
; cwde
|
|
% Sign-extend AX into EAX.
|
|
% Details on amd64-prog-man-vol3 manual p94.
|
|
|
|
; cdqe
|
|
% Sign-extend EAX into RAX.
|
|
% Details on amd64-prog-man-vol3 manual p94.
|
|
|
|
; cwd
|
|
% Sign-extend AX into DX:AX.
|
|
% Details on amd64-prog-man-vol3 manual p95.
|
|
|
|
; cdq
|
|
% Sign-extend EAX into EDX:EAX.
|
|
% Details on amd64-prog-man-vol3 manual p95.
|
|
|
|
; cqo
|
|
% Sign-extend RAX into RDX:RAX.
|
|
% Details on amd64-prog-man-vol3 manual p95.
|
|
|
|
; clc
|
|
% Clears the carry flag (CF) in the rFLAGS register to zero.
|
|
% Details on amd64-prog-man-vol3 manual p96.
|
|
|
|
; cld
|
|
% Clears the direction flag (DF) in the rFLAGS register to zero.
|
|
% Details on amd64-prog-man-vol3 manual p97.
|
|
|
|
; cmc
|
|
% Complements the carry flag bit (CF) bit in the rFLAGS register.
|
|
% Details on amd64-prog-man-vol3 manual p100.
|
|
|
|
; cmov(
|
|
cmov_src :: operand,
|
|
% memory or register
|
|
cmov_dest :: operand,
|
|
% register
|
|
cmov_cmp_op :: condition
|
|
)
|
|
% Moves with comparison operation defined in 'cmov_cmp_op'.
|
|
% Details on amd64-prog-man-vol3 manual p(101-103).
|
|
|
|
; cmp(
|
|
cmp_src :: operand,
|
|
% 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_src :: operand,
|
|
% register or memory location
|
|
cmpxchg_dest :: operand
|
|
% register
|
|
)
|
|
% 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(
|
|
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(
|
|
dec_op :: operand
|
|
% register or memory reference
|
|
)
|
|
% Decrements the contents of 'dec_op'.
|
|
% Details on amd64-prog-man-vol3 manual p120.
|
|
|
|
; 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(
|
|
enter_stack_size :: uint16,
|
|
enter_nesting_level :: uint8
|
|
)
|
|
% Creates a procedure stack frame with a stack size specified in
|
|
% 'enter_stack_size' and nesting level specified in
|
|
% 'enter_nesting_level'(0 to 31).
|
|
% Details on amd64-prog-man-vol3 manual p124.
|
|
|
|
; idiv(
|
|
idiv_op :: operand
|
|
% register or memory reference
|
|
)
|
|
% Signed divide RDX:RAX by the value in 'operand'.
|
|
% Details on amd64-prog-man-vol3 manual p126.
|
|
|
|
; imul(
|
|
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
|
|
)
|
|
% Increments the contents of 'inc_op'.
|
|
% Details on amd64-prog-man-vol3 manual p133.
|
|
|
|
; j(
|
|
j_target :: operand,
|
|
% relative offset
|
|
j_condition :: condition
|
|
)
|
|
% Conditional jump.
|
|
% 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(
|
|
jmp_op :: operand
|
|
)
|
|
% Jumps with target specified in 'jmp_op'
|
|
% Details on amd64-prog-man-vol3 manual p152.
|
|
|
|
; lea(
|
|
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.
|
|
|
|
; leave
|
|
% Sets RSP to the value in RBP and pop RBP.
|
|
% Details on amd64-prog-man-vol3 manual p164.
|
|
|
|
; loop(
|
|
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 :: 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 :: 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 :: 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 :: 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,
|
|
% register, memory location or immediate value
|
|
mov_dest :: operand
|
|
% register or memory location
|
|
)
|
|
% Copies 'mov_src' to 'mov_dest'. 'mov_dest' cannot be immediate op.
|
|
% Details on amd64-prog-man-vol3 manual p173.
|
|
|
|
; mul(
|
|
mul_op :: operand
|
|
% register or memory location
|
|
)
|
|
% Unsigned multiply 'mul_op' by RAX.
|
|
% Details on amd64-prog-man-vol3 manual p190.
|
|
|
|
; 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.
|
|
|
|
; 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,
|
|
% 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(
|
|
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(
|
|
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.
|
|
|
|
; pushfq
|
|
% Pushes the RFLAGS quadword onto the stack.
|
|
% Details on amd64-prog-man-vol3 manual p218.
|
|
|
|
; 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(
|
|
ret_op :: maybe(uint16)
|
|
)
|
|
% Near return to the calling procedure, then pop the specified
|
|
% number of bytes from stack (if specified).
|
|
% Details on amd64-prog-man-vol3 manual p224.
|
|
|
|
; 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 :: 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 :: operand,
|
|
% unsigned immediate value or register
|
|
shl_dest :: operand
|
|
% register or memory location
|
|
)
|
|
% Alias to 'sal'.
|
|
% Details on amd64-prog-man-vol3 manual p235.
|
|
|
|
; sar(
|
|
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,
|
|
% 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.
|
|
|
|
; set(
|
|
set_dest :: operand,
|
|
% register or memory location
|
|
set_cond :: condition
|
|
)
|
|
% 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'.
|
|
% Details on amd64-prog-man-vol3 manual p(246-247).
|
|
|
|
; shld(
|
|
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 :: 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 :: 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.
|
|
% Details on amd64-prog-man-vol3 manual p255.
|
|
|
|
; stc
|
|
% Sets the carry flag (CF) in the RFLAGS register to 1.
|
|
% Details on amd64-prog-man-vol3 manual p257.
|
|
|
|
; std
|
|
% Sets the direction flag (DF) in the rflags register to 1.
|
|
% Details on amd64-prog-man-vol3 manual p258.
|
|
|
|
; sub(
|
|
sub_src :: operand,
|
|
% 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 :: 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 :: 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 :: 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 :: 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.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Returns the number of x86_64 general-purpose registers.
|
|
%
|
|
:- func num_x86_64_regs = int.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- 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([], "").
|
|
|
|
num_x86_64_regs = 16.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module ll_backend.x86_64_instrs.
|
|
%----------------------------------------------------------------------------%
|