Introduce globalsym_addr.

This is an instruction used in legalization of GlobalVarData::Sym global
variables.
This commit is contained in:
Dan Gohman
2017-10-30 10:02:29 -07:00
parent cb805f704d
commit 9c54c3fff0
11 changed files with 96 additions and 9 deletions

View File

@@ -12,6 +12,8 @@ function %I32() {
fn0 = function %foo()
sig0 = ()
gv0 = globalsym %some_gv
ss0 = incoming_arg 8, offset 0
ss1 = incoming_arg 1024, offset -1024
ss2 = incoming_arg 1024, offset -2048
@@ -342,9 +344,9 @@ ebb0:
; asm: call foo
call fn0() ; bin: e8 PCRel4(fn0) 00000000
; asm: movl $-1, %ecx
; asm: movl $0, %ecx
[-,%rcx] v400 = func_addr.i32 fn0 ; bin: b9 Abs4(fn0) 00000000
; asm: movl $-1, %esi
; asm: movl $0, %esi
[-,%rsi] v401 = func_addr.i32 fn0 ; bin: be Abs4(fn0) 00000000
; asm: call *%ecx
@@ -352,6 +354,11 @@ ebb0:
; asm: call *%esi
call_indirect sig0, v401() ; bin: ff d6
; asm: movl $0, %ecx
[-,%rcx] v450 = globalsym_addr.i32 gv0 ; bin: b9 Abs4(gv0) 00000000
; asm: movl $0, %esi
[-,%rsi] v451 = globalsym_addr.i32 gv0 ; bin: be Abs4(gv0) 00000000
; Spill / Fill.
; asm: movl %ecx, 1032(%esp)

View File

@@ -14,6 +14,8 @@ function %I64() {
fn0 = function %foo()
sig0 = ()
gv0 = globalsym %some_gv
; Use incoming_arg stack slots because they won't be relocated by the frame
; layout.
ss0 = incoming_arg 8, offset 0
@@ -429,11 +431,11 @@ ebb0:
; asm: call foo
call fn0() ; bin: e8 PCRel4(fn0) 00000000
; asm: movabsq $-1, %rcx
; asm: movabsq $0, %rcx
[-,%rcx] v400 = func_addr.i64 fn0 ; bin: 48 b9 Abs8(fn0) 0000000000000000
; asm: movabsq $-1, %rsi
; asm: movabsq $0, %rsi
[-,%rsi] v401 = func_addr.i64 fn0 ; bin: 48 be Abs8(fn0) 0000000000000000
; asm: movabsq $-1, %r10
; asm: movabsq $0, %r10
[-,%r10] v402 = func_addr.i64 fn0 ; bin: 49 ba Abs8(fn0) 0000000000000000
; asm: call *%rcx
@@ -443,6 +445,13 @@ ebb0:
; asm: call *%r10
call_indirect sig0, v402() ; bin: 41 ff d2
; asm: movabsq $-1, %rcx
[-,%rcx] v450 = globalsym_addr.i64 gv0 ; bin: 48 b9 Abs8(gv0) 0000000000000000
; asm: movabsq $-1, %rsi
[-,%rsi] v451 = globalsym_addr.i64 gv0 ; bin: 48 be Abs8(gv0) 0000000000000000
; asm: movabsq $-1, %r10
[-,%r10] v452 = globalsym_addr.i64 gv0 ; bin: 49 ba Abs8(gv0) 0000000000000000
; Spill / Fill.
; asm: movq %rcx, 1032(%rsp)

View File

@@ -29,6 +29,19 @@ ebb1(v1: i64):
; check: return $v2
}
function %sym() -> i64 {
gv0 = globalsym %something
gv1 = globalsym #d0bad180d0b5d182d0bed0bd
ebb1:
v0 = global_addr.i64 gv0
; check: $v0 = globalsym_addr.i64 gv0
v1 = global_addr.i64 gv1
; check: $v1 = globalsym_addr.i64 gv1
v2 = bxor v0, v1
return v2
}
; SpiderMonkey VM-style static 4+2 GB heap.
; This eliminates bounds checks completely for offsets < 2GB.
function %staticheap_sm64(i32, i64 vmctx) -> f32 spiderwasm {

View File

@@ -79,6 +79,10 @@ impl binemit::CodeSink for TextSink {
write!(self.text, "{}({}) ", self.rnames[reloc.0 as usize], fref).unwrap();
}
fn reloc_globalsym(&mut self, reloc: binemit::Reloc, global: ir::GlobalVar) {
write!(self.text, "{}({}) ", self.rnames[reloc.0 as usize], global).unwrap();
}
fn reloc_jt(&mut self, reloc: binemit::Reloc, jt: ir::JumpTable) {
write!(self.text, "{}({}) ", self.rnames[reloc.0 as usize], jt).unwrap();
}

View File

@@ -99,5 +99,6 @@ impl binemit::CodeSink for SizeSink {
fn reloc_ebb(&mut self, _reloc: binemit::Reloc, _ebb: ir::Ebb) {}
fn reloc_func(&mut self, _reloc: binemit::Reloc, _fref: ir::FuncRef) {}
fn reloc_globalsym(&mut self, _reloc: binemit::Reloc, _global: ir::GlobalVar) {}
fn reloc_jt(&mut self, _reloc: binemit::Reloc, _jt: ir::JumpTable) {}
}

View File

@@ -389,6 +389,14 @@ global_addr = Instruction(
""",
ins=GV, outs=addr)
# A specialized form of global_addr instructions that only handles
# symbolic names.
globalsym_addr = Instruction(
'globalsym_addr', r"""
Compute the address of global variable GV, which is a symbolic name.
""",
ins=GV, outs=addr)
#
# WebAssembly bounds-checked heap accesses.
#

View File

@@ -271,6 +271,13 @@ I32.enc(base.func_addr.i32, *r.allones_fnaddr4(0xb8),
I64.enc(base.func_addr.i64, *r.allones_fnaddr8.rex(0xb8, w=1),
isap=allones_funcaddrs)
#
# Global addresses.
#
I32.enc(base.globalsym_addr.i32, *r.gvaddr4(0xb8))
I64.enc(base.globalsym_addr.i64, *r.gvaddr8.rex(0xb8, w=1))
#
# Call/return
#

View File

@@ -9,7 +9,7 @@ from base.formats import Unary, UnaryImm, Binary, BinaryImm, MultiAry
from base.formats import Trap, Call, IndirectCall, Store, Load
from base.formats import IntCompare, FloatCompare, IntCond, FloatCond
from base.formats import Jump, Branch, BranchInt, BranchFloat
from base.formats import Ternary, FuncAddr
from base.formats import Ternary, FuncAddr, UnaryGlobalVar
from base.formats import RegMove, RegSpill, RegFill
from .registers import GPR, ABCD, FPR, GPR8, FPR8, FLAG, StackGPR32, StackFPR32
from .defs import supported_floatccs
@@ -510,6 +510,24 @@ allones_fnaddr8 = TailRecipe(
sink.put8(!0);
''')
# XX+rd id with Abs4 globalsym relocation.
gvaddr4 = TailRecipe(
'gvaddr4', UnaryGlobalVar, size=4, ins=(), outs=GPR,
emit='''
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
sink.reloc_globalsym(RelocKind::Abs4.into(), global_var);
sink.put4(0);
''')
# XX+rd iq with Abs8 globalsym relocation.
gvaddr8 = TailRecipe(
'gvaddr8', UnaryGlobalVar, size=8, ins=(), outs=GPR,
emit='''
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
sink.reloc_globalsym(RelocKind::Abs8.into(), global_var);
sink.put8(0);
''')
#
# Store recipes.
#

View File

@@ -14,7 +14,7 @@
//! relocations to a `RelocSink` trait object. Relocations are less frequent than the
//! `CodeSink::put*` methods, so the performance impact of the virtual callbacks is less severe.
use ir::{Ebb, FuncRef, JumpTable};
use ir::{Ebb, FuncRef, GlobalVar, JumpTable};
use super::{CodeSink, CodeOffset, Reloc};
use std::ptr::write_unaligned;
@@ -54,6 +54,11 @@ pub trait RelocSink {
/// Add a relocation referencing an external function at the current offset.
fn reloc_func(&mut self, CodeOffset, Reloc, FuncRef);
/// Add a relocation referencing an external global variable symbol at the
/// current offset.
fn reloc_globalsym(&mut self, CodeOffset, Reloc, GlobalVar);
/// Add a relocation referencing a jump table.
/// Add a relocation referencing a jump table.
fn reloc_jt(&mut self, CodeOffset, Reloc, JumpTable);
}
@@ -101,6 +106,11 @@ impl<'a> CodeSink for MemoryCodeSink<'a> {
self.relocs.reloc_func(ofs, rel, func);
}
fn reloc_globalsym(&mut self, rel: Reloc, global: GlobalVar) {
let ofs = self.offset();
self.relocs.reloc_globalsym(ofs, rel, global);
}
fn reloc_jt(&mut self, rel: Reloc, jt: JumpTable) {
let ofs = self.offset();
self.relocs.reloc_jt(ofs, rel, jt);

View File

@@ -9,7 +9,7 @@ mod memorysink;
pub use self::relaxation::relax_branches;
pub use self::memorysink::{MemoryCodeSink, RelocSink};
use ir::{Ebb, FuncRef, JumpTable, Function, Inst};
use ir::{Ebb, FuncRef, GlobalVar, JumpTable, Function, Inst};
use regalloc::RegDiversions;
/// Offset in bytes from the beginning of the function.
@@ -47,6 +47,10 @@ pub trait CodeSink {
/// Add a relocation referencing an external function at the current offset.
fn reloc_func(&mut self, Reloc, FuncRef);
/// Add a relocation referencing an external global variable symbol at the
/// current offset. This is only used for `GlobalVarData::Sym` globals.
fn reloc_globalsym(&mut self, Reloc, GlobalVar);
/// Add a relocation referencing a jump table.
fn reloc_jt(&mut self, Reloc, JumpTable);
}

View File

@@ -21,7 +21,7 @@ pub fn expand_global_addr(inst: ir::Inst, func: &mut ir::Function, _cfg: &mut Co
match func.global_vars[gv] {
ir::GlobalVarData::VmCtx { offset } => vmctx_addr(inst, func, offset.into()),
ir::GlobalVarData::Deref { base, offset } => deref_addr(inst, func, base, offset.into()),
ir::GlobalVarData::Sym { .. } => (),
ir::GlobalVarData::Sym { .. } => globalsym(inst, func, gv),
}
}
@@ -50,3 +50,9 @@ fn deref_addr(inst: ir::Inst, func: &mut ir::Function, base: ir::GlobalVar, offs
let base_ptr = pos.ins().load(ptr_ty, ir::MemFlags::new(), base_addr, 0);
pos.func.dfg.replace(inst).iadd_imm(base_ptr, offset);
}
/// Expand a `global_addr` instruction for a symbolic name global.
fn globalsym(inst: ir::Inst, func: &mut ir::Function, gv: ir::GlobalVar) {
let ptr_ty = func.dfg.value_type(func.dfg.first_result(inst));
func.dfg.replace(inst).globalsym_addr(ptr_ty, gv);
}