Add global variables to Cretonne IL.
See #144 for discussion. - Add a new GlobalVar entity type both in Python and Rust. - Define a UnaryGlobalVar instruction format containing a GlobalVar reference. - Add a globalvar.rs module defining the GlobalVarData with support for 'vmctx' and 'deref' global variable kinds. Langref: Add a section about global variables and the global_addr instruction. Parser: Add support for the UnaryGlobalVar instruction format as well as global variable declarations in the preamble.
This commit is contained in:
@@ -37,6 +37,7 @@ pub enum Token<'a> {
|
||||
Value(Value), // v12, v7
|
||||
Ebb(Ebb), // ebb3
|
||||
StackSlot(u32), // ss3
|
||||
GlobalVar(u32), // gv3
|
||||
JumpTable(u32), // jt2
|
||||
FuncRef(u32), // fn2
|
||||
SigRef(u32), // sig2
|
||||
@@ -308,6 +309,7 @@ impl<'a> Lexer<'a> {
|
||||
"v" => Value::with_number(number).map(Token::Value),
|
||||
"ebb" => Ebb::with_number(number).map(Token::Ebb),
|
||||
"ss" => Some(Token::StackSlot(number)),
|
||||
"gv" => Some(Token::GlobalVar(number)),
|
||||
"jt" => Some(Token::JumpTable(number)),
|
||||
"fn" => Some(Token::FuncRef(number)),
|
||||
"sig" => Some(Token::SigRef(number)),
|
||||
|
||||
@@ -11,7 +11,8 @@ use std::{u16, u32};
|
||||
use std::mem;
|
||||
use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, CallConv, StackSlotData,
|
||||
JumpTable, JumpTableData, Signature, ArgumentType, ArgumentExtension,
|
||||
ExtFuncData, SigRef, FuncRef, StackSlot, ValueLoc, ArgumentLoc, MemFlags};
|
||||
ExtFuncData, SigRef, FuncRef, StackSlot, ValueLoc, ArgumentLoc, MemFlags,
|
||||
GlobalVar, GlobalVarData};
|
||||
use cretonne::ir::types::VOID;
|
||||
use cretonne::ir::immediates::{Imm64, Offset32, Uoffset32, Ieee32, Ieee64};
|
||||
use cretonne::ir::entities::AnyEntity;
|
||||
@@ -127,6 +128,20 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a global variable slot and add a mapping number -> GlobalVar.
|
||||
fn add_gv(&mut self, number: u32, data: GlobalVarData, loc: &Location) -> Result<()> {
|
||||
self.map
|
||||
.def_gv(number, self.function.global_vars.push(data), loc)
|
||||
}
|
||||
|
||||
// Resolve a reference to a global variable.
|
||||
fn get_gv(&self, number: u32, loc: &Location) -> Result<GlobalVar> {
|
||||
match self.map.get_gv(number) {
|
||||
Some(gv) => Ok(gv),
|
||||
None => err!(loc, "undefined stack slot ss{}", number),
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a new signature and add a mapping number -> SigRef.
|
||||
fn add_sig(&mut self, number: u32, data: Signature, loc: &Location) -> Result<()> {
|
||||
self.map
|
||||
@@ -228,6 +243,18 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite base references in `deref` globals. Other `GlobalVar` references are already
|
||||
// resolved.
|
||||
for gv in self.function.global_vars.keys() {
|
||||
let loc = gv.into();
|
||||
match self.function.global_vars[gv] {
|
||||
GlobalVarData::Deref { ref mut base, .. } => {
|
||||
self.map.rewrite_gv(base, loc)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -344,6 +371,16 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Match and consume a global variable reference.
|
||||
fn match_gv(&mut self, err_msg: &str) -> Result<u32> {
|
||||
if let Some(Token::GlobalVar(gv)) = self.token() {
|
||||
self.consume();
|
||||
Ok(gv)
|
||||
} else {
|
||||
err!(self.loc, err_msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Match and consume a function reference.
|
||||
fn match_fn(&mut self, err_msg: &str) -> Result<u32> {
|
||||
if let Some(Token::FuncRef(fnref)) = self.token() {
|
||||
@@ -903,6 +940,11 @@ impl<'a> Parser<'a> {
|
||||
self.parse_stack_slot_decl()
|
||||
.and_then(|(num, dat)| ctx.add_ss(num, dat, &loc))
|
||||
}
|
||||
Some(Token::GlobalVar(..)) => {
|
||||
self.gather_comments(ctx.function.global_vars.next_key());
|
||||
self.parse_global_var_decl()
|
||||
.and_then(|(num, dat)| ctx.add_gv(num, dat, &self.loc))
|
||||
}
|
||||
Some(Token::SigRef(..)) => {
|
||||
self.gather_comments(ctx.function.dfg.signatures.next_key());
|
||||
self.parse_signature_decl(ctx.unique_isa)
|
||||
@@ -959,6 +1001,40 @@ impl<'a> Parser<'a> {
|
||||
Ok((number, data))
|
||||
}
|
||||
|
||||
// Parse a global variable decl.
|
||||
//
|
||||
// global-var-decl ::= * GlobalVar(gv) "=" global-var-desc
|
||||
// global-var-desc ::= "vmctx" offset32
|
||||
// | "deref" "(" GlobalVar(base) ")" offset32
|
||||
//
|
||||
fn parse_global_var_decl(&mut self) -> Result<(u32, GlobalVarData)> {
|
||||
let number = self.match_gv("expected global variable number: gv«n»")?;
|
||||
self.match_token(Token::Equal, "expected '=' in global variable declaration")?;
|
||||
|
||||
let data = match self.match_any_identifier("expected global variable kind")? {
|
||||
"vmctx" => {
|
||||
let offset = self.optional_offset32()?;
|
||||
GlobalVarData::VmCtx { offset }
|
||||
}
|
||||
"deref" => {
|
||||
self.match_token(Token::LPar, "expected '(' in 'deref' global variable decl")?;
|
||||
let base_num = self.match_gv("expected global variable: gv«n»")?;
|
||||
// The base global variable may not have been declared yet, so create a fake
|
||||
// reference using the source number. We'll rewrite these later.
|
||||
let base = match GlobalVar::with_number(base_num) {
|
||||
Some(gv) => gv,
|
||||
None => return err!(self.loc, "Invalid global variable number for deref base"),
|
||||
};
|
||||
self.match_token(Token::RPar, "expected ')' in 'deref' global variable decl")?;
|
||||
let offset = self.optional_offset32()?;
|
||||
GlobalVarData::Deref { base, offset }
|
||||
}
|
||||
other => return err!(self.loc, "Unknown global variable kind '{}'", other),
|
||||
};
|
||||
|
||||
Ok((number, data))
|
||||
}
|
||||
|
||||
// Parse a signature decl.
|
||||
//
|
||||
// signature-decl ::= SigRef(sigref) "=" signature
|
||||
@@ -1517,6 +1593,13 @@ impl<'a> Parser<'a> {
|
||||
imm: self.match_bool("expected immediate boolean operand")?,
|
||||
}
|
||||
}
|
||||
InstructionFormat::UnaryGlobalVar => {
|
||||
InstructionData::UnaryGlobalVar {
|
||||
opcode,
|
||||
global_var: self.match_gv("expected global variable")
|
||||
.and_then(|num| ctx.get_gv(num, &self.loc))?,
|
||||
}
|
||||
}
|
||||
InstructionFormat::Binary => {
|
||||
let lhs = self.match_value("expected SSA value first operand")?;
|
||||
self.match_token(Token::Comma, "expected ',' between operands")?;
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
//! The `SourceMap` struct defined in this module makes the same mapping available to parser
|
||||
//! clients.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use cretonne::ir::{StackSlot, JumpTable, Ebb, Value, SigRef, FuncRef};
|
||||
use cretonne::entity_ref::EntityRef;
|
||||
use cretonne::ir::entities::AnyEntity;
|
||||
use cretonne::ir::{StackSlot, GlobalVar, JumpTable, Ebb, Value, SigRef, FuncRef};
|
||||
use error::{Result, Location};
|
||||
use lexer::split_entity_name;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Mapping from source entity names to entity references that are valid in the parsed function.
|
||||
#[derive(Debug)]
|
||||
@@ -19,6 +20,7 @@ pub struct SourceMap {
|
||||
values: HashMap<Value, Value>, // vNN
|
||||
ebbs: HashMap<Ebb, Ebb>, // ebbNN
|
||||
stack_slots: HashMap<u32, StackSlot>, // ssNN
|
||||
global_vars: HashMap<u32, GlobalVar>, // gvNN
|
||||
signatures: HashMap<u32, SigRef>, // sigNN
|
||||
functions: HashMap<u32, FuncRef>, // fnNN
|
||||
jump_tables: HashMap<u32, JumpTable>, // jtNN
|
||||
@@ -44,6 +46,11 @@ impl SourceMap {
|
||||
self.stack_slots.get(&src_num).cloned()
|
||||
}
|
||||
|
||||
/// Look up a global variable entity by its source number.
|
||||
pub fn get_gv(&self, src_num: u32) -> Option<GlobalVar> {
|
||||
self.global_vars.get(&src_num).cloned()
|
||||
}
|
||||
|
||||
/// Look up a signature entity by its source number.
|
||||
pub fn get_sig(&self, src_num: u32) -> Option<SigRef> {
|
||||
self.signatures.get(&src_num).cloned()
|
||||
@@ -74,6 +81,7 @@ impl SourceMap {
|
||||
.map(AnyEntity::Ebb)
|
||||
}
|
||||
"ss" => self.get_ss(num).map(AnyEntity::StackSlot),
|
||||
"gv" => self.get_gv(num).map(AnyEntity::GlobalVar),
|
||||
"sig" => self.get_sig(num).map(AnyEntity::SigRef),
|
||||
"fn" => self.get_fn(num).map(AnyEntity::FuncRef),
|
||||
"jt" => self.get_jt(num).map(AnyEntity::JumpTable),
|
||||
@@ -124,6 +132,21 @@ impl SourceMap {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Rewrite a `GlobalVar` reference.
|
||||
pub fn rewrite_gv(&self, gv: &mut GlobalVar, loc: AnyEntity) -> Result<()> {
|
||||
match self.get_gv(gv.index() as u32) {
|
||||
Some(new) => {
|
||||
*gv = new;
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
err!(self.location(loc).unwrap_or_default(),
|
||||
"undefined reference: {}",
|
||||
gv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,6 +160,7 @@ pub trait MutableSourceMap {
|
||||
fn def_value(&mut self, src: Value, entity: Value, loc: &Location) -> Result<()>;
|
||||
fn def_ebb(&mut self, src: Ebb, entity: Ebb, loc: &Location) -> Result<()>;
|
||||
fn def_ss(&mut self, src_num: u32, entity: StackSlot, loc: &Location) -> Result<()>;
|
||||
fn def_gv(&mut self, src_num: u32, entity: GlobalVar, loc: &Location) -> Result<()>;
|
||||
fn def_sig(&mut self, src_num: u32, entity: SigRef, loc: &Location) -> Result<()>;
|
||||
fn def_fn(&mut self, src_num: u32, entity: FuncRef, loc: &Location) -> Result<()>;
|
||||
fn def_jt(&mut self, src_num: u32, entity: JumpTable, loc: &Location) -> Result<()>;
|
||||
@@ -152,6 +176,7 @@ impl MutableSourceMap for SourceMap {
|
||||
values: HashMap::new(),
|
||||
ebbs: HashMap::new(),
|
||||
stack_slots: HashMap::new(),
|
||||
global_vars: HashMap::new(),
|
||||
signatures: HashMap::new(),
|
||||
functions: HashMap::new(),
|
||||
jump_tables: HashMap::new(),
|
||||
@@ -183,6 +208,14 @@ impl MutableSourceMap for SourceMap {
|
||||
}
|
||||
}
|
||||
|
||||
fn def_gv(&mut self, src_num: u32, entity: GlobalVar, loc: &Location) -> Result<()> {
|
||||
if self.global_vars.insert(src_num, entity).is_some() {
|
||||
err!(loc, "duplicate global variable: gv{}", src_num)
|
||||
} else {
|
||||
self.def_entity(entity.into(), loc)
|
||||
}
|
||||
}
|
||||
|
||||
fn def_sig(&mut self, src_num: u32, entity: SigRef, loc: &Location) -> Result<()> {
|
||||
if self.signatures.insert(src_num, entity).is_some() {
|
||||
err!(loc, "duplicate signature: sig{}", src_num)
|
||||
|
||||
Reference in New Issue
Block a user