diff --git a/cranelift/filetests/isa/intel/binary32.cton b/cranelift/filetests/isa/intel/binary32.cton index ab0f060488..c37079b063 100644 --- a/cranelift/filetests/isa/intel/binary32.cton +++ b/cranelift/filetests/isa/intel/binary32.cton @@ -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) diff --git a/cranelift/filetests/isa/intel/binary64.cton b/cranelift/filetests/isa/intel/binary64.cton index a770416e30..7ad9d47c4d 100644 --- a/cranelift/filetests/isa/intel/binary64.cton +++ b/cranelift/filetests/isa/intel/binary64.cton @@ -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) diff --git a/cranelift/filetests/isa/intel/legalize-memory.cton b/cranelift/filetests/isa/intel/legalize-memory.cton index c7d5ed3617..b9e8e99696 100644 --- a/cranelift/filetests/isa/intel/legalize-memory.cton +++ b/cranelift/filetests/isa/intel/legalize-memory.cton @@ -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 { diff --git a/cranelift/src/filetest/binemit.rs b/cranelift/src/filetest/binemit.rs index ae1c741d13..67bdac475c 100644 --- a/cranelift/src/filetest/binemit.rs +++ b/cranelift/src/filetest/binemit.rs @@ -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(); } diff --git a/cranelift/src/filetest/compile.rs b/cranelift/src/filetest/compile.rs index 799bcc0a0a..8d6c8e726c 100644 --- a/cranelift/src/filetest/compile.rs +++ b/cranelift/src/filetest/compile.rs @@ -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) {} } diff --git a/lib/cretonne/meta/base/instructions.py b/lib/cretonne/meta/base/instructions.py index 76682d2dff..26a6f66077 100644 --- a/lib/cretonne/meta/base/instructions.py +++ b/lib/cretonne/meta/base/instructions.py @@ -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. # diff --git a/lib/cretonne/meta/isa/intel/encodings.py b/lib/cretonne/meta/isa/intel/encodings.py index 9ae4601a57..f9c7f041c8 100644 --- a/lib/cretonne/meta/isa/intel/encodings.py +++ b/lib/cretonne/meta/isa/intel/encodings.py @@ -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 # diff --git a/lib/cretonne/meta/isa/intel/recipes.py b/lib/cretonne/meta/isa/intel/recipes.py index 89f0e00ac0..0a3d05d096 100644 --- a/lib/cretonne/meta/isa/intel/recipes.py +++ b/lib/cretonne/meta/isa/intel/recipes.py @@ -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. # diff --git a/lib/cretonne/src/binemit/memorysink.rs b/lib/cretonne/src/binemit/memorysink.rs index f3fd5cebba..610fd9666d 100644 --- a/lib/cretonne/src/binemit/memorysink.rs +++ b/lib/cretonne/src/binemit/memorysink.rs @@ -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); diff --git a/lib/cretonne/src/binemit/mod.rs b/lib/cretonne/src/binemit/mod.rs index 5715b1a86d..0ba7ea5668 100644 --- a/lib/cretonne/src/binemit/mod.rs +++ b/lib/cretonne/src/binemit/mod.rs @@ -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); } diff --git a/lib/cretonne/src/legalizer/globalvar.rs b/lib/cretonne/src/legalizer/globalvar.rs index 73855f4410..717be0d4f0 100644 --- a/lib/cretonne/src/legalizer/globalvar.rs +++ b/lib/cretonne/src/legalizer/globalvar.rs @@ -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); +}