diff --git a/cranelift/docs/langref.rst b/cranelift/docs/langref.rst index fb9f35fd94..b5471d2a0c 100644 --- a/cranelift/docs/langref.rst +++ b/cranelift/docs/langref.rst @@ -563,6 +563,16 @@ runtime data structures. variable. :result GV: Global variable. +.. inst:: GV = globalsym name + + Declare a global variable at a symbolic address. + + The address of GV is symbolic and will be assigned a relocation, so that + it can be resolved by a later linking phase. + + :arg name: External name. + :result GV: Global variable. + .. autoinst:: global_addr diff --git a/cranelift/filetests/parser/memory.cton b/cranelift/filetests/parser/memory.cton index fc26169961..6fa594c4c1 100644 --- a/cranelift/filetests/parser/memory.cton +++ b/cranelift/filetests/parser/memory.cton @@ -36,6 +36,20 @@ ebb0: return v1 } +function %sym() -> i32 { + gv0 = globalsym %something + ; check: $gv0 = globalsym %something + gv1 = globalsym #d0bad180d0b5d182d0bed0bd + ; check: $gv1 = globalsym #d0bad180d0b5d182d0bed0bd +ebb0: + v0 = global_addr.i32 gv0 + ; check: $v0 = global_addr.i32 $gv0 + v1 = global_addr.i32 gv1 + ; check: $v1 = global_addr.i32 $gv1 + v2 = bxor v0, v1 + return v2 +} + ; Declare static heaps. function %sheap(i32) -> i64 { heap1 = static reserved_reg, min 0x1_0000, bound 0x1_0000_0000, guard 0x8000_0000 diff --git a/lib/cretonne/src/ir/globalvar.rs b/lib/cretonne/src/ir/globalvar.rs index 110cf687ce..1e7fa2efe0 100644 --- a/lib/cretonne/src/ir/globalvar.rs +++ b/lib/cretonne/src/ir/globalvar.rs @@ -1,6 +1,6 @@ //! Global variables. -use ir::GlobalVar; +use ir::{ExternalName, GlobalVar}; use ir::immediates::Offset32; use std::fmt; @@ -25,6 +25,14 @@ pub enum GlobalVarData { /// Byte offset to be added to the pointer loaded from `base`. offset: Offset32, }, + + /// Variable is at an address identified by a symbolic name. Cretonne itself + /// does not interpret this name; it's used by embedders to link with other + /// data structures. + Sym { + /// The symbolic name. + name: ExternalName, + }, } impl fmt::Display for GlobalVarData { @@ -32,6 +40,7 @@ impl fmt::Display for GlobalVarData { match *self { GlobalVarData::VmCtx { offset } => write!(f, "vmctx{}", offset), GlobalVarData::Deref { base, offset } => write!(f, "deref({}){}", base, offset), + GlobalVarData::Sym { ref name } => write!(f, "globalsym {}", name), } } } diff --git a/lib/cretonne/src/legalizer/globalvar.rs b/lib/cretonne/src/legalizer/globalvar.rs index c51a8b8cfc..73855f4410 100644 --- a/lib/cretonne/src/legalizer/globalvar.rs +++ b/lib/cretonne/src/legalizer/globalvar.rs @@ -21,6 +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 { .. } => (), } } diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index 2162b167c5..dd08b0ddcb 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -877,7 +877,7 @@ impl<'a> Parser<'a> { let location = self.loc; // function-spec ::= "function" * name signature - let name = self.parse_function_name()?; + let name = self.parse_external_name()?; // function-spec ::= "function" name * signature let sig = self.parse_signature(unique_isa)?; @@ -885,11 +885,13 @@ impl<'a> Parser<'a> { Ok((location, name, sig)) } - // Parse a function name. + // Parse an external name. + // + // For example, in a function spec, the parser would be in this state: // // function ::= "function" * name signature { ... } // - fn parse_function_name(&mut self) -> Result { + fn parse_external_name(&mut self) -> Result { match self.token() { Some(Token::Name(s)) => { self.consume(); @@ -899,7 +901,7 @@ impl<'a> Parser<'a> { if s.len() % 2 != 0 { return err!( self.loc, - "expected binary function name to have length multiple of two" + "expected binary external name to have length multiple of two" ); } let mut bin_name = Vec::with_capacity(s.len() / 2); @@ -912,7 +914,7 @@ impl<'a> Parser<'a> { self.consume(); Ok(ExternalName::new(bin_name)) } - _ => err!(self.loc, "expected function name"), + _ => err!(self.loc, "expected external name"), } } @@ -1142,6 +1144,7 @@ impl<'a> Parser<'a> { // global-var-decl ::= * GlobalVar(gv) "=" global-var-desc // global-var-desc ::= "vmctx" offset32 // | "deref" "(" GlobalVar(base) ")" offset32 + // | "globalsym" name // fn parse_global_var_decl(&mut self) -> Result<(u32, GlobalVarData)> { let number = self.match_gv("expected global variable number: gv«n»")?; @@ -1168,6 +1171,10 @@ impl<'a> Parser<'a> { let offset = self.optional_offset32()?; GlobalVarData::Deref { base, offset } } + "globalsym" => { + let name = self.parse_external_name()?; + GlobalVarData::Sym { name } + } other => return err!(self.loc, "Unknown global variable kind '{}'", other), }; @@ -1292,7 +1299,7 @@ impl<'a> Parser<'a> { Some(Token::SigRef(sig_src)) => { let sig = ctx.get_sig(sig_src, &self.loc)?; self.consume(); - let name = self.parse_function_name()?; + let name = self.parse_external_name()?; ExtFuncData { name, signature: sig,