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:
@@ -16,6 +16,9 @@ ebb = EntityRefKind(
|
||||
#: A reference to a stack slot declared in the function preamble.
|
||||
stack_slot = EntityRefKind('stack_slot', 'A stack slot.')
|
||||
|
||||
#: A reference to a global variable.
|
||||
global_var = EntityRefKind('global_var', 'A global variable.')
|
||||
|
||||
#: A reference to a function sugnature declared in the function preamble.
|
||||
#: Tbis is used to provide the call signature in an indirect call instruction.
|
||||
sig_ref = EntityRefKind('sig_ref', 'A function signature.')
|
||||
|
||||
@@ -10,7 +10,8 @@ from cdsl.formats import InstructionFormat
|
||||
from cdsl.operands import VALUE, VARIABLE_ARGS
|
||||
from .immediates import imm64, uimm8, ieee32, ieee64, offset32, uoffset32
|
||||
from .immediates import boolean, intcc, floatcc, memflags, regunit
|
||||
from .entities import ebb, sig_ref, func_ref, jump_table, stack_slot
|
||||
from . import entities
|
||||
from .entities import ebb, sig_ref, func_ref, stack_slot
|
||||
|
||||
Nullary = InstructionFormat()
|
||||
|
||||
@@ -19,6 +20,7 @@ UnaryImm = InstructionFormat(imm64)
|
||||
UnaryIeee32 = InstructionFormat(ieee32)
|
||||
UnaryIeee64 = InstructionFormat(ieee64)
|
||||
UnaryBool = InstructionFormat(boolean)
|
||||
UnaryGlobalVar = InstructionFormat(entities.global_var)
|
||||
|
||||
Binary = InstructionFormat(VALUE, VALUE)
|
||||
BinaryImm = InstructionFormat(VALUE, imm64)
|
||||
@@ -42,7 +44,7 @@ FloatCompare = InstructionFormat(floatcc, VALUE, VALUE)
|
||||
Jump = InstructionFormat(ebb, VARIABLE_ARGS)
|
||||
Branch = InstructionFormat(VALUE, ebb, VARIABLE_ARGS)
|
||||
BranchIcmp = InstructionFormat(intcc, VALUE, VALUE, ebb, VARIABLE_ARGS)
|
||||
BranchTable = InstructionFormat(VALUE, jump_table)
|
||||
BranchTable = InstructionFormat(VALUE, entities.jump_table)
|
||||
|
||||
Call = InstructionFormat(func_ref, VARIABLE_ARGS)
|
||||
IndirectCall = InstructionFormat(sig_ref, VALUE, VARIABLE_ARGS)
|
||||
|
||||
@@ -345,6 +345,18 @@ stack_addr = Instruction(
|
||||
""",
|
||||
ins=(SS, Offset), outs=addr)
|
||||
|
||||
#
|
||||
# Global variables.
|
||||
#
|
||||
|
||||
GV = Operand('GV', entities.global_var)
|
||||
|
||||
global_addr = Instruction(
|
||||
'global_addr', r"""
|
||||
Compute the address of global variable GV.
|
||||
""",
|
||||
ins=GV, outs=addr)
|
||||
|
||||
#
|
||||
# WebAssembly bounds-checked heap accesses.
|
||||
#
|
||||
|
||||
@@ -59,7 +59,7 @@ VARIABLE_ARGS = OperandKind(
|
||||
'variable_args', """
|
||||
A variable size list of `value` operands.
|
||||
|
||||
Use this to represent arguemtns passed to a function call, arguments
|
||||
Use this to represent arguments passed to a function call, arguments
|
||||
passed to an extended basic block, or a variable number of results
|
||||
returned from an instruction.
|
||||
""",
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
use ir::types;
|
||||
use ir::{InstructionData, DataFlowGraph};
|
||||
use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, SigRef, FuncRef, StackSlot, ValueList,
|
||||
MemFlags};
|
||||
use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, SigRef, FuncRef, StackSlot, GlobalVar,
|
||||
ValueList, MemFlags};
|
||||
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, Offset32, Uoffset32};
|
||||
use ir::condcodes::{IntCC, FloatCC};
|
||||
use isa::RegUnit;
|
||||
|
||||
@@ -65,6 +65,24 @@ entity_impl!(Inst, "inst");
|
||||
pub struct StackSlot(u32);
|
||||
entity_impl!(StackSlot, "ss");
|
||||
|
||||
/// An opaque reference to a global variable.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct GlobalVar(u32);
|
||||
entity_impl!(GlobalVar, "gv");
|
||||
|
||||
impl GlobalVar {
|
||||
/// Create a new global variable reference from its number.
|
||||
///
|
||||
/// This method is for use by the parser.
|
||||
pub fn with_number(n: u32) -> Option<GlobalVar> {
|
||||
if n < u32::MAX {
|
||||
Some(GlobalVar(n))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An opaque reference to a jump table.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct JumpTable(u32);
|
||||
@@ -93,6 +111,8 @@ pub enum AnyEntity {
|
||||
Value(Value),
|
||||
/// A stack slot.
|
||||
StackSlot(StackSlot),
|
||||
/// A Global variable.
|
||||
GlobalVar(GlobalVar),
|
||||
/// A jump table.
|
||||
JumpTable(JumpTable),
|
||||
/// An external function.
|
||||
@@ -109,6 +129,7 @@ impl fmt::Display for AnyEntity {
|
||||
AnyEntity::Inst(r) => r.fmt(f),
|
||||
AnyEntity::Value(r) => r.fmt(f),
|
||||
AnyEntity::StackSlot(r) => r.fmt(f),
|
||||
AnyEntity::GlobalVar(r) => r.fmt(f),
|
||||
AnyEntity::JumpTable(r) => r.fmt(f),
|
||||
AnyEntity::FuncRef(r) => r.fmt(f),
|
||||
AnyEntity::SigRef(r) => r.fmt(f),
|
||||
@@ -140,6 +161,12 @@ impl From<StackSlot> for AnyEntity {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GlobalVar> for AnyEntity {
|
||||
fn from(r: GlobalVar) -> AnyEntity {
|
||||
AnyEntity::GlobalVar(r)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JumpTable> for AnyEntity {
|
||||
fn from(r: JumpTable) -> AnyEntity {
|
||||
AnyEntity::JumpTable(r)
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
//! instructions.
|
||||
|
||||
use entity_map::{EntityMap, PrimaryEntityData};
|
||||
use ir::{FunctionName, CallConv, Signature, JumpTableData, DataFlowGraph, Layout};
|
||||
use ir::{JumpTables, InstEncodings, ValueLocations, StackSlots, EbbOffsets};
|
||||
use ir::{FunctionName, CallConv, Signature, JumpTableData, GlobalVarData, DataFlowGraph, Layout};
|
||||
use ir::{JumpTables, InstEncodings, ValueLocations, StackSlots, GlobalVars, EbbOffsets};
|
||||
use isa::TargetIsa;
|
||||
use std::fmt;
|
||||
use write::write_function;
|
||||
@@ -25,6 +25,9 @@ pub struct Function {
|
||||
/// Stack slots allocated in this function.
|
||||
pub stack_slots: StackSlots,
|
||||
|
||||
/// Global variables referenced.
|
||||
pub global_vars: GlobalVars,
|
||||
|
||||
/// Jump tables used in this function.
|
||||
pub jump_tables: JumpTables,
|
||||
|
||||
@@ -50,6 +53,7 @@ pub struct Function {
|
||||
}
|
||||
|
||||
impl PrimaryEntityData for JumpTableData {}
|
||||
impl PrimaryEntityData for GlobalVarData {}
|
||||
|
||||
impl Function {
|
||||
/// Create a function with the given name and signature.
|
||||
@@ -58,6 +62,7 @@ impl Function {
|
||||
name,
|
||||
signature: sig,
|
||||
stack_slots: StackSlots::new(),
|
||||
global_vars: GlobalVars::new(),
|
||||
jump_tables: EntityMap::new(),
|
||||
dfg: DataFlowGraph::new(),
|
||||
layout: Layout::new(),
|
||||
|
||||
37
lib/cretonne/src/ir/globalvar.rs
Normal file
37
lib/cretonne/src/ir/globalvar.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
//! Global variables.
|
||||
|
||||
use ir::GlobalVar;
|
||||
use ir::immediates::Offset32;
|
||||
use std::fmt;
|
||||
|
||||
/// Information about a global variable declaration.
|
||||
#[derive(Clone)]
|
||||
pub enum GlobalVarData {
|
||||
/// Variable is part of the VM context struct, it's address is a constant offset from the VM
|
||||
/// context pointer.
|
||||
VmCtx {
|
||||
/// Offset from the `vmctx` pointer to this global.
|
||||
offset: Offset32,
|
||||
},
|
||||
|
||||
/// Variable is part of a struct pointed to by another global variable.
|
||||
///
|
||||
/// The `base` global variable is assumed to contain a pointer to a struct. This global
|
||||
/// variable lives at an offset into the struct.
|
||||
Deref {
|
||||
/// The base pointer global variable.
|
||||
base: GlobalVar,
|
||||
|
||||
/// Byte offset to be added to the pointer loaded from `base`.
|
||||
offset: Offset32,
|
||||
},
|
||||
}
|
||||
|
||||
impl fmt::Display for GlobalVarData {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&GlobalVarData::VmCtx { offset } => write!(f, "vmctx{}", offset),
|
||||
&GlobalVarData::Deref { base, offset } => write!(f, "deref({}){}", base, offset),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,6 +109,10 @@ pub enum InstructionData {
|
||||
UnaryIeee32 { opcode: Opcode, imm: Ieee32 },
|
||||
UnaryIeee64 { opcode: Opcode, imm: Ieee64 },
|
||||
UnaryBool { opcode: Opcode, imm: bool },
|
||||
UnaryGlobalVar {
|
||||
opcode: Opcode,
|
||||
global_var: ir::GlobalVar,
|
||||
},
|
||||
Binary { opcode: Opcode, args: [Value; 2] },
|
||||
BinaryImm {
|
||||
opcode: Opcode,
|
||||
|
||||
@@ -13,17 +13,19 @@ pub mod function;
|
||||
mod builder;
|
||||
mod extfunc;
|
||||
mod funcname;
|
||||
mod globalvar;
|
||||
mod memflags;
|
||||
mod progpoint;
|
||||
mod valueloc;
|
||||
|
||||
pub use ir::builder::{InstBuilder, InstBuilderBase, InstInserterBase, InsertBuilder};
|
||||
pub use ir::dfg::{DataFlowGraph, ValueDef};
|
||||
pub use ir::entities::{Ebb, Inst, Value, StackSlot, JumpTable, FuncRef, SigRef};
|
||||
pub use ir::entities::{Ebb, Inst, Value, StackSlot, GlobalVar, JumpTable, FuncRef, SigRef};
|
||||
pub use ir::extfunc::{Signature, CallConv, ArgumentType, ArgumentExtension, ArgumentPurpose,
|
||||
ExtFuncData};
|
||||
pub use ir::funcname::FunctionName;
|
||||
pub use ir::function::Function;
|
||||
pub use ir::globalvar::GlobalVarData;
|
||||
pub use ir::instructions::{Opcode, InstructionData, VariableArgs, ValueList, ValueListPool};
|
||||
pub use ir::jumptable::JumpTableData;
|
||||
pub use ir::layout::{Layout, CursorBase, Cursor};
|
||||
@@ -48,3 +50,6 @@ pub type InstEncodings = EntityMap<Inst, isa::Encoding>;
|
||||
|
||||
/// Code offsets for EBBs.
|
||||
pub type EbbOffsets = EntityMap<Ebb, binemit::CodeOffset>;
|
||||
|
||||
/// Map of global variables.
|
||||
pub type GlobalVars = EntityMap<GlobalVar, GlobalVarData>;
|
||||
|
||||
@@ -57,7 +57,7 @@ use flowgraph::ControlFlowGraph;
|
||||
use ir::entities::AnyEntity;
|
||||
use ir::instructions::{InstructionFormat, BranchInfo, ResolvedConstraint, CallInfo};
|
||||
use ir::{types, Function, ValueDef, Ebb, Inst, SigRef, FuncRef, ValueList, JumpTable, StackSlot,
|
||||
StackSlotKind, Value, Type, Opcode, ValueLoc, ArgumentLoc};
|
||||
StackSlotKind, GlobalVar, Value, Type, Opcode, ValueLoc, ArgumentLoc};
|
||||
use isa::TargetIsa;
|
||||
use std::error as std_error;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
@@ -270,6 +270,9 @@ impl<'a> Verifier<'a> {
|
||||
StackStore { stack_slot, .. } => {
|
||||
self.verify_stack_slot(inst, stack_slot)?;
|
||||
}
|
||||
UnaryGlobalVar { global_var, .. } => {
|
||||
self.verify_global_var(inst, global_var)?;
|
||||
}
|
||||
|
||||
// Exhaustive list so we can't forget to add new formats
|
||||
Nullary { .. } |
|
||||
@@ -328,6 +331,14 @@ impl<'a> Verifier<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_global_var(&self, inst: Inst, gv: GlobalVar) -> Result {
|
||||
if !self.func.global_vars.is_valid(gv) {
|
||||
err!(inst, "invalid global variable {}", gv)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_value_list(&self, inst: Inst, l: &ValueList) -> Result {
|
||||
if !l.is_valid(&self.func.dfg.value_lists) {
|
||||
err!(inst, "invalid value list reference {:?}", l)
|
||||
|
||||
@@ -49,6 +49,11 @@ fn write_preamble(w: &mut Write,
|
||||
writeln!(w, " {} = {}", ss, func.stack_slots[ss])?;
|
||||
}
|
||||
|
||||
for gv in func.global_vars.keys() {
|
||||
any = true;
|
||||
writeln!(w, " {} = {}", gv, func.global_vars[gv])?;
|
||||
}
|
||||
|
||||
// Write out all signatures before functions since function declarations can refer to
|
||||
// signatures.
|
||||
for sig in func.dfg.signatures.keys() {
|
||||
@@ -244,6 +249,7 @@ pub fn write_operands(w: &mut Write,
|
||||
UnaryIeee32 { imm, .. } => write!(w, " {}", imm),
|
||||
UnaryIeee64 { imm, .. } => write!(w, " {}", imm),
|
||||
UnaryBool { imm, .. } => write!(w, " {}", imm),
|
||||
UnaryGlobalVar { global_var, .. } => write!(w, " {}", global_var),
|
||||
Binary { args, .. } => write!(w, " {}, {}", args[0], args[1]),
|
||||
BinaryImm { arg, imm, .. } => write!(w, " {}, {}", arg, imm),
|
||||
Ternary { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
|
||||
@@ -338,7 +344,6 @@ pub fn write_operands(w: &mut Write,
|
||||
write!(w, " {}, %{} -> %{}", arg, src, dst)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user