Implement stack_addr, stack_load, stack_store for x86-64. (#370)

This commit is contained in:
Dan Gohman
2018-06-26 06:15:21 -07:00
committed by GitHub
parent fbd637e142
commit 7d2b44289c
6 changed files with 179 additions and 1 deletions

View File

@@ -0,0 +1,45 @@
; binary emission of stack address instructions on x86-64.
test binemit
set opt_level=fastest
target x86_64 haswell
; The binary encodings can be verified with the command:
;
; sed -ne 's/^ *; asm: *//p' filetests/isa/x86/stack-addr64.cton | llvm-mc -show-encoding -triple=x86_64
;
function %stack_addr() {
ss0 = incoming_arg 8, offset 0
ss1 = incoming_arg 1024, offset -1024
ss2 = incoming_arg 1024, offset -2048
ss3 = incoming_arg 8, offset -2056
ss4 = explicit_slot 8, offset 0
ss5 = explicit_slot 8, offset 1024
ebb0:
[-,%rcx] v0 = stack_addr.i64 ss0 ; bin: 48 8d 8c 24 00000808
[-,%rcx] v1 = stack_addr.i64 ss1 ; bin: 48 8d 8c 24 00000408
[-,%rcx] v2 = stack_addr.i64 ss2 ; bin: 48 8d 8c 24 00000008
[-,%rcx] v3 = stack_addr.i64 ss3 ; bin: 48 8d 8c 24 00000000
[-,%rcx] v4 = stack_addr.i64 ss4 ; bin: 48 8d 8c 24 00000808
[-,%rcx] v5 = stack_addr.i64 ss5 ; bin: 48 8d 8c 24 00000c08
[-,%rcx] v20 = stack_addr.i64 ss4+1 ; bin: 48 8d 8c 24 00000809
[-,%rcx] v21 = stack_addr.i64 ss4+2 ; bin: 48 8d 8c 24 0000080a
[-,%rcx] v22 = stack_addr.i64 ss4+2048 ; bin: 48 8d 8c 24 00001008
[-,%rcx] v23 = stack_addr.i64 ss4-4096 ; bin: 48 8d 8c 24 fffff808
[-,%r8] v50 = stack_addr.i64 ss0 ; bin: 4c 8d 84 24 00000808
[-,%r8] v51 = stack_addr.i64 ss1 ; bin: 4c 8d 84 24 00000408
[-,%r8] v52 = stack_addr.i64 ss2 ; bin: 4c 8d 84 24 00000008
[-,%r8] v53 = stack_addr.i64 ss3 ; bin: 4c 8d 84 24 00000000
[-,%r8] v54 = stack_addr.i64 ss4 ; bin: 4c 8d 84 24 00000808
[-,%r8] v55 = stack_addr.i64 ss5 ; bin: 4c 8d 84 24 00000c08
[-,%r8] v70 = stack_addr.i64 ss4+1 ; bin: 4c 8d 84 24 00000809
[-,%r8] v71 = stack_addr.i64 ss4+2 ; bin: 4c 8d 84 24 0000080a
[-,%r8] v72 = stack_addr.i64 ss4+2048 ; bin: 4c 8d 84 24 00001008
[-,%r8] v73 = stack_addr.i64 ss4-4096 ; bin: 4c 8d 84 24 fffff808
return
}

View File

@@ -0,0 +1,21 @@
; legalization of stack load and store instructions on x86-64.
test legalizer
set opt_level=fastest
target x86_64 haswell
function %stack_load_and_store() {
ss0 = explicit_slot 8, offset 0
ebb0:
v0 = stack_load.i64 ss0
; check: v1 = stack_addr.i64 ss0
; check: v0 = load.i64 notrap aligned v1
stack_store.i64 v0, ss0
; check: v2 = stack_addr.i64 ss0
; check: store notrap aligned v0, v2
return
}

View File

@@ -80,6 +80,10 @@ expand.custom_legalize(insts.select, 'expand_select')
expand.custom_legalize(insts.f32const, 'expand_fconst')
expand.custom_legalize(insts.f64const, 'expand_fconst')
# Custom expansions for stack memory accesses.
expand.custom_legalize(insts.stack_load, 'expand_stack_load')
expand.custom_legalize(insts.stack_store, 'expand_stack_store')
x = Var('x')
y = Var('y')
a = Var('a')

View File

@@ -436,6 +436,15 @@ X86_64.enc(base.globalsym_addr.i64, *r.pcrel_gvaddr8.rex(0x8d, w=1),
X86_64.enc(base.globalsym_addr.i64, *r.got_gvaddr8.rex(0x8b, w=1),
isap=is_pic)
#
# Stack addresses.
#
# TODO: Add encoding rules for stack_load and stack_store, so that they
# don't get legalized to stack_addr + load/store.
#
X86_32.enc(base.stack_addr.i32, *r.spaddr4_id(0x8d))
X86_64.enc(base.stack_addr.i64, *r.spaddr8_id.rex(0x8d, w=1))
#
# Call/return
#

View File

@@ -17,6 +17,7 @@ from base.formats import Jump, Branch, BranchInt, BranchFloat
from base.formats import Ternary, FuncAddr, UnaryGlobalValue
from base.formats import RegMove, RegSpill, RegFill, CopySpecial
from base.formats import LoadComplex, StoreComplex
from base.formats import StackLoad
from .registers import GPR, ABCD, FPR, GPR_DEREF_SAFE, GPR_ZERO_DEREF_SAFE
from .registers import GPR8, FPR8, GPR8_DEREF_SAFE, GPR8_ZERO_DEREF_SAFE, FLAG
from .registers import StackGPR32, StackFPR32
@@ -751,6 +752,36 @@ got_gvaddr8 = TailRecipe(
sink.put4(0);
''')
#
# Stack addresses.
#
# TODO: Alternative forms for 8-bit immediates, when applicable.
#
spaddr4_id = TailRecipe(
'spaddr4_id', StackLoad, size=6, ins=(), outs=GPR,
emit='''
let sp = StackRef::sp(stack_slot, &func.stack_slots);
let base = stk_base(sp.base);
PUT_OP(bits, rex2(out_reg0, base), sink);
modrm_sib_disp8(out_reg0, sink);
sib_noindex(base, sink);
let imm : i32 = offset.into();
sink.put4(sp.offset.checked_add(imm).unwrap() as u32);
''')
spaddr8_id = TailRecipe(
'spaddr8_id', StackLoad, size=6, ins=(), outs=GPR,
emit='''
let sp = StackRef::sp(stack_slot, &func.stack_slots);
let base = stk_base(sp.base);
PUT_OP(bits, rex2(base, out_reg0), sink);
modrm_sib_disp32(out_reg0, sink);
sib_noindex(base, sink);
let imm : i32 = offset.into();
sink.put4(sp.offset.checked_add(imm).unwrap() as u32);
''')
#
# Store recipes.

View File

@@ -16,7 +16,7 @@
use bitset::BitSet;
use cursor::{Cursor, FuncCursor};
use flowgraph::ControlFlowGraph;
use ir::{self, InstBuilder};
use ir::{self, InstBuilder, MemFlags};
use isa::TargetIsa;
use timing;
@@ -269,3 +269,71 @@ fn expand_fconst(
};
pos.func.dfg.replace(inst).bitcast(ty, ival);
}
/// Expand illegal `stack_load` instructions.
fn expand_stack_load(
inst: ir::Inst,
func: &mut ir::Function,
_cfg: &mut ControlFlowGraph,
isa: &TargetIsa,
) {
let ty = func.dfg.value_type(func.dfg.first_result(inst));
let addr_ty = isa.pointer_type();
let mut pos = FuncCursor::new(func).at_inst(inst);
pos.use_srcloc(inst);
let (stack_slot, offset) = match pos.func.dfg[inst] {
ir::InstructionData::StackLoad {
opcode: _opcode,
stack_slot,
offset,
} => (stack_slot, offset),
_ => panic!(
"Expected stack_load: {}",
pos.func.dfg.display_inst(inst, None)
),
};
let addr = pos.ins().stack_addr(addr_ty, stack_slot, offset);
let mut mflags = MemFlags::new();
// Stack slots are required to be accessible and aligned.
mflags.set_notrap();
mflags.set_aligned();
pos.func.dfg.replace(inst).load(ty, mflags, addr, 0);
}
/// Expand illegal `stack_store` instructions.
fn expand_stack_store(
inst: ir::Inst,
func: &mut ir::Function,
_cfg: &mut ControlFlowGraph,
isa: &TargetIsa,
) {
let addr_ty = isa.pointer_type();
let mut pos = FuncCursor::new(func).at_inst(inst);
pos.use_srcloc(inst);
let (val, stack_slot, offset) = match pos.func.dfg[inst] {
ir::InstructionData::StackStore {
opcode: _opcode,
arg,
stack_slot,
offset,
} => (arg, stack_slot, offset),
_ => panic!(
"Expected stack_store: {}",
pos.func.dfg.display_inst(inst, None)
),
};
let addr = pos.ins().stack_addr(addr_ty, stack_slot, offset);
let mut mflags = MemFlags::new();
// Stack slots are required to be accessible and aligned.
mflags.set_notrap();
mflags.set_aligned();
pos.func.dfg.replace(inst).store(mflags, val, addr, 0);
}