Flatten the Value reference representation.

All values are now references into the value table, so drop the
distinction between direct and table values. Direct values don't exist
any more.

Also remove the parser support for the 'vxNN' syntax. Only 'vNN' values
can be parsed now.
This commit is contained in:
Jakob Stoklund Olesen
2017-04-12 14:26:23 -07:00
parent 7cac9dcb41
commit 23ae70cacf
15 changed files with 115 additions and 264 deletions

View File

@@ -47,10 +47,9 @@ class CretonneLexer(RegexLexer):
# Well known value types. # Well known value types.
(r'\b(b\d+|i\d+|f32|f64)(x\d+)?\b', Keyword.Type), (r'\b(b\d+|i\d+|f32|f64)(x\d+)?\b', Keyword.Type),
# v<nn> = value # v<nn> = value
# vx<nn> = value
# ss<nn> = stack slot # ss<nn> = stack slot
# jt<nn> = jump table # jt<nn> = jump table
(r'(vx?|ss|jt)\d+', Name.Variable), (r'(v|ss|jt)\d+', Name.Variable),
# ebb<nn> = extended basic block # ebb<nn> = extended basic block
(r'(ebb)\d+', Name.Label), (r'(ebb)\d+', Name.Label),
# Match instruction names in context. # Match instruction names in context.

View File

@@ -3,7 +3,6 @@ test legalizer
isa riscv isa riscv
; regex: V=v\d+ ; regex: V=v\d+
; regex: VX=vx\d+
function f(i32) { function f(i32) {
sig0 = signature(i32) -> i32 sig0 = signature(i32) -> i32

View File

@@ -7,7 +7,7 @@ isa riscv supports_m=1
set is_64bit=1 set is_64bit=1
isa riscv supports_m=1 isa riscv supports_m=1
; regex: V=vx?\d+ ; regex: V=v\d+
function carry_out(i32, i32) -> i32, b1 { function carry_out(i32, i32) -> i32, b1 {
ebb0(v1: i32, v2: i32): ebb0(v1: i32, v2: i32):

View File

@@ -2,7 +2,7 @@
test legalizer test legalizer
isa riscv isa riscv
; regex: V=vx?\d+ ; regex: V=v\d+
function int_split_args(i64) -> i64 { function int_split_args(i64) -> i64 {
ebb0(v0: i64): ebb0(v0: i64):

View File

@@ -2,7 +2,7 @@
test legalizer test legalizer
isa riscv supports_m=1 isa riscv supports_m=1
; regex: V=vx?\d+ ; regex: V=v\d+
function bitwise_and(i64, i64) -> i64 { function bitwise_and(i64, i64) -> i64 {
ebb0(v1: i64, v2: i64): ebb0(v1: i64, v2: i64):

View File

@@ -2,7 +2,7 @@
test legalizer test legalizer
isa riscv isa riscv
; regex: V=vx?\d+ ; regex: V=v\d+
function simple(i64, i64) -> i64 { function simple(i64, i64) -> i64 {
ebb0(v1: i64, v2: i64): ebb0(v1: i64, v2: i64):

View File

@@ -12,13 +12,13 @@ test cat
function defs() { function defs() {
ebb100(v20: i32): ebb100(v20: i32):
v1000 = iconst.i32x8 5 v1000 = iconst.i32x8 5
vx200 = f64const 0x4.0p0 v9200 = f64const 0x4.0p0
trap trap
} }
; sameln: function defs() { ; sameln: function defs() {
; nextln: $ebb100($v20: i32): ; nextln: $ebb100($v20: i32):
; nextln: $v1000 = iconst.i32x8 5 ; nextln: $v1000 = iconst.i32x8 5
; nextln: $vx200 = f64const 0x1.0000000000000p2 ; nextln: $v9200 = f64const 0x1.0000000000000p2
; nextln: trap ; nextln: trap
; nextln: } ; nextln: }

View File

@@ -2,7 +2,6 @@
use entity_map::{EntityMap, PrimaryEntityData}; use entity_map::{EntityMap, PrimaryEntityData};
use ir::builder::{InsertBuilder, ReplaceBuilder}; use ir::builder::{InsertBuilder, ReplaceBuilder};
use ir::entities::ExpandedValue;
use ir::extfunc::ExtFuncData; use ir::extfunc::ExtFuncData;
use ir::instructions::{Opcode, InstructionData, CallInfo}; use ir::instructions::{Opcode, InstructionData, CallInfo};
use ir::layout::Cursor; use ir::layout::Cursor;
@@ -48,12 +47,8 @@ pub struct DataFlowGraph {
/// - EBB arguments in `ebbs`. /// - EBB arguments in `ebbs`.
pub value_lists: ValueListPool, pub value_lists: ValueListPool,
/// Extended value table. Most `Value` references refer directly to their defining instruction. /// Primary value table with entries for all values.
/// Others index into this table. values: EntityMap<Value, ValueData>,
///
/// This is implemented directly with a `Vec` rather than an `EntityMap<Value, ...>` because
/// the Value entity references can refer to two things -- an instruction or an extended value.
extended_values: Vec<ValueData>,
/// Function signature table. These signatures are referenced by indirect call instructions as /// Function signature table. These signatures are referenced by indirect call instructions as
/// well as the external function references. /// well as the external function references.
@@ -65,6 +60,7 @@ pub struct DataFlowGraph {
impl PrimaryEntityData for InstructionData {} impl PrimaryEntityData for InstructionData {}
impl PrimaryEntityData for EbbData {} impl PrimaryEntityData for EbbData {}
impl PrimaryEntityData for ValueData {}
impl PrimaryEntityData for Signature {} impl PrimaryEntityData for Signature {}
impl PrimaryEntityData for ExtFuncData {} impl PrimaryEntityData for ExtFuncData {}
@@ -76,7 +72,7 @@ impl DataFlowGraph {
results: EntityMap::new(), results: EntityMap::new(),
ebbs: EntityMap::new(), ebbs: EntityMap::new(),
value_lists: ValueListPool::new(), value_lists: ValueListPool::new(),
extended_values: Vec::new(), values: EntityMap::new(),
signatures: EntityMap::new(), signatures: EntityMap::new(),
ext_funcs: EntityMap::new(), ext_funcs: EntityMap::new(),
} }
@@ -115,44 +111,29 @@ impl DataFlowGraph {
impl DataFlowGraph { impl DataFlowGraph {
// Allocate an extended value entry. // Allocate an extended value entry.
fn make_value(&mut self, data: ValueData) -> Value { fn make_value(&mut self, data: ValueData) -> Value {
let vref = Value::new_table(self.extended_values.len()); self.values.push(data)
self.extended_values.push(data);
vref
} }
/// Check if a value reference is valid. /// Check if a value reference is valid.
pub fn value_is_valid(&self, v: Value) -> bool { pub fn value_is_valid(&self, v: Value) -> bool {
match v.expand() { self.values.is_valid(v)
ExpandedValue::Direct(inst) => self.insts.is_valid(inst),
ExpandedValue::Table(index) => index < self.extended_values.len(),
}
} }
/// Get the type of a value. /// Get the type of a value.
pub fn value_type(&self, v: Value) -> Type { pub fn value_type(&self, v: Value) -> Type {
use ir::entities::ExpandedValue::*; match self.values[v] {
match v.expand() { ValueData::Inst { ty, .. } |
Direct(_) => panic!("Unexpected direct value"), ValueData::Arg { ty, .. } |
Table(i) => {
match self.extended_values[i] {
ValueData::Inst { ty, .. } => ty,
ValueData::Arg { ty, .. } => ty,
ValueData::Alias { ty, .. } => ty, ValueData::Alias { ty, .. } => ty,
} }
} }
}
}
/// Get the definition of a value. /// Get the definition of a value.
/// ///
/// This is either the instruction that defined it or the Ebb that has the value as an /// This is either the instruction that defined it or the Ebb that has the value as an
/// argument. /// argument.
pub fn value_def(&self, v: Value) -> ValueDef { pub fn value_def(&self, v: Value) -> ValueDef {
use ir::entities::ExpandedValue::*; match self.values[v] {
match v.expand() {
Direct(inst) => ValueDef::Res(inst, 0),
Table(idx) => {
match self.extended_values[idx] {
ValueData::Inst { inst, num, .. } => { ValueData::Inst { inst, num, .. } => {
assert_eq!(Some(v), assert_eq!(Some(v),
self.results[inst].get(num as usize, &self.value_lists), self.results[inst].get(num as usize, &self.value_lists),
@@ -174,30 +155,20 @@ impl DataFlowGraph {
} }
} }
} }
}
}
/// Resolve value aliases. /// Resolve value aliases.
/// ///
/// Find the original SSA value that `value` aliases. /// Find the original SSA value that `value` aliases.
pub fn resolve_aliases(&self, value: Value) -> Value { pub fn resolve_aliases(&self, value: Value) -> Value {
use ir::entities::ExpandedValue::Table;
let mut v = value; let mut v = value;
// Note that extended_values may be empty here. // Note that extended_values may be empty here.
for _ in 0..1 + self.extended_values.len() { for _ in 0..1 + self.values.len() {
v = match v.expand() { if let ValueData::Alias { original, .. } = self.values[v] {
Table(idx) => { v = original;
match self.extended_values[idx] { } else {
ValueData::Alias { original, .. } => { return v;
// Follow alias values.
original
} }
_ => return v,
}
}
_ => return v,
};
} }
panic!("Value alias loop detected for {}", value); panic!("Value alias loop detected for {}", value);
} }
@@ -233,13 +204,7 @@ impl DataFlowGraph {
/// ///
/// Change the `dest` value to behave as an alias of `src`. This means that all uses of `dest` /// Change the `dest` value to behave as an alias of `src`. This means that all uses of `dest`
/// will behave as if they used that value `src`. /// will behave as if they used that value `src`.
///
/// The `dest` value cannot be a direct value defined as the first result of an instruction. To
/// replace a direct value with `src`, its defining instruction should be replaced with a
/// `copy src` instruction. See `replace()`.
pub fn change_to_alias(&mut self, dest: Value, src: Value) { pub fn change_to_alias(&mut self, dest: Value, src: Value) {
use ir::entities::ExpandedValue::Table;
// Try to create short alias chains by finding the original source value. // Try to create short alias chains by finding the original source value.
// This also avoids the creation of loops. // This also avoids the creation of loops.
let original = self.resolve_aliases(src); let original = self.resolve_aliases(src);
@@ -256,14 +221,10 @@ impl DataFlowGraph {
self.value_type(dest), self.value_type(dest),
ty); ty);
if let Table(idx) = dest.expand() { self.values[dest] = ValueData::Alias {
self.extended_values[idx] = ValueData::Alias {
ty: ty, ty: ty,
original: original, original: original,
}; };
} else {
panic!("Cannot change direct value {} into an alias", dest);
}
} }
/// Create a new value alias. /// Create a new value alias.
@@ -458,15 +419,11 @@ impl DataFlowGraph {
let num = self.results[inst].push(res, &mut self.value_lists); let num = self.results[inst].push(res, &mut self.value_lists);
assert!(num <= u16::MAX as usize, "Too many result values"); assert!(num <= u16::MAX as usize, "Too many result values");
let ty = self.value_type(res); let ty = self.value_type(res);
if let ExpandedValue::Table(idx) = res.expand() { self.values[res] = ValueData::Inst {
self.extended_values[idx] = ValueData::Inst {
ty: ty, ty: ty,
num: num as u16, num: num as u16,
inst: inst, inst: inst,
}; };
} else {
panic!("Unexpected direct value");
}
} }
/// Append a new instruction result value to `inst`. /// Append a new instruction result value to `inst`.
@@ -609,11 +566,7 @@ impl DataFlowGraph {
/// ///
/// Returns the new value. /// Returns the new value.
pub fn replace_ebb_arg(&mut self, old_arg: Value, new_type: Type) -> Value { pub fn replace_ebb_arg(&mut self, old_arg: Value, new_type: Type) -> Value {
let old_data = if let ExpandedValue::Table(index) = old_arg.expand() { let old_data = self.values[old_arg].clone();
self.extended_values[index].clone()
} else {
panic!("old_arg: {} must be an EBB argument", old_arg);
};
// Create new value identical to the old one except for the type. // Create new value identical to the old one except for the type.
let (ebb, num) = if let ValueData::Arg { num, ebb, .. } = old_data { let (ebb, num) = if let ValueData::Arg { num, ebb, .. } = old_data {
@@ -655,13 +608,11 @@ impl DataFlowGraph {
// Now update `arg` itself. // Now update `arg` itself.
let arg_ebb = ebb; let arg_ebb = ebb;
if let ExpandedValue::Table(idx) = arg.expand() { if let ValueData::Arg { ref mut num, ebb, .. } = self.values[arg] {
if let ValueData::Arg { ref mut num, ebb, .. } = self.extended_values[idx] {
*num = arg_num as u16; *num = arg_num as u16;
assert_eq!(arg_ebb, ebb, "{} should already belong to EBB", arg); assert_eq!(arg_ebb, ebb, "{} should already belong to EBB", arg);
return; return;
} }
}
panic!("{} must be an EBB argument value", arg); panic!("{} must be an EBB argument value", arg);
} }
} }
@@ -724,7 +675,7 @@ mod tests {
let inst = dfg.make_inst(idata); let inst = dfg.make_inst(idata);
dfg.make_inst_results(inst, types::I32); dfg.make_inst_results(inst, types::I32);
assert_eq!(inst.to_string(), "inst0"); assert_eq!(inst.to_string(), "inst0");
assert_eq!(dfg.display_inst(inst).to_string(), "vx0 = iconst.i32"); assert_eq!(dfg.display_inst(inst).to_string(), "v0 = iconst.i32");
// Immutable reference resolution. // Immutable reference resolution.
{ {
@@ -766,12 +717,12 @@ mod tests {
assert_eq!(dfg.ebb_args(ebb), &[]); assert_eq!(dfg.ebb_args(ebb), &[]);
let arg1 = dfg.append_ebb_arg(ebb, types::F32); let arg1 = dfg.append_ebb_arg(ebb, types::F32);
assert_eq!(arg1.to_string(), "vx0"); assert_eq!(arg1.to_string(), "v0");
assert_eq!(dfg.num_ebb_args(ebb), 1); assert_eq!(dfg.num_ebb_args(ebb), 1);
assert_eq!(dfg.ebb_args(ebb), &[arg1]); assert_eq!(dfg.ebb_args(ebb), &[arg1]);
let arg2 = dfg.append_ebb_arg(ebb, types::I16); let arg2 = dfg.append_ebb_arg(ebb, types::I16);
assert_eq!(arg2.to_string(), "vx1"); assert_eq!(arg2.to_string(), "v1");
assert_eq!(dfg.num_ebb_args(ebb), 2); assert_eq!(dfg.num_ebb_args(ebb), 2);
assert_eq!(dfg.ebb_args(ebb), &[arg1, arg2]); assert_eq!(dfg.ebb_args(ebb), &[arg1, arg2]);
@@ -835,7 +786,7 @@ mod tests {
// Build a little test program. // Build a little test program.
let v1 = dfg.ins(pos).iconst(types::I32, 42); let v1 = dfg.ins(pos).iconst(types::I32, 42);
// Make sure we can resolve value aliases even when extended_values is empty. // Make sure we can resolve value aliases even when values is empty.
assert_eq!(dfg.resolve_aliases(v1), v1); assert_eq!(dfg.resolve_aliases(v1), v1);
let arg0 = dfg.append_ebb_arg(ebb0, types::I32); let arg0 = dfg.append_ebb_arg(ebb0, types::I32);

View File

@@ -76,97 +76,20 @@ impl Ebb {
/// An opaque reference to an SSA value. /// An opaque reference to an SSA value.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Value(u32); pub struct Value(u32);
entity_impl!(Value); entity_impl!(Value, "v");
/// Value references can either reference an instruction directly, or they can refer to the
/// extended value table.
pub enum ExpandedValue {
/// This is the first value produced by the referenced instruction.
Direct(Inst),
/// This value is described in the extended value table.
Table(usize),
}
impl Value { impl Value {
/// Create a `Direct` value from its number representation. /// Create a value from its number representation.
/// This is the number in the `vNN` notation. /// This is the number in the `vNN` notation.
/// ///
/// This method is for use by the parser. /// This method is for use by the parser.
pub fn direct_with_number(n: u32) -> Option<Value> { pub fn with_number(n: u32) -> Option<Value> {
if n < u32::MAX / 2 { if n < u32::MAX / 2 {
let encoding = n * 2; Some(Value(n))
assert!(encoding < u32::MAX);
Some(Value(encoding))
} else { } else {
None None
} }
} }
/// Create a `Table` value from its number representation.
/// This is the number in the `vxNN` notation.
///
/// This method is for use by the parser.
pub fn table_with_number(n: u32) -> Option<Value> {
if n < u32::MAX / 2 {
let encoding = n * 2 + 1;
assert!(encoding < u32::MAX);
Some(Value(encoding))
} else {
None
}
}
/// Create a `Direct` value corresponding to the first value produced by `i`.
pub fn new_direct(i: Inst) -> Value {
let encoding = i.index() * 2;
assert!(encoding < u32::MAX as usize);
Value(encoding as u32)
}
/// Create a `Table` value referring to entry `i` in the `DataFlowGraph.extended_values` table.
/// This constructor should not be used directly. Use the public `DataFlowGraph` methods to
/// manipulate values.
pub fn new_table(index: usize) -> Value {
let encoding = index * 2 + 1;
assert!(encoding < u32::MAX as usize);
Value(encoding as u32)
}
/// Expand the internal representation into something useful.
pub fn expand(&self) -> ExpandedValue {
use self::ExpandedValue::*;
let index = (self.0 / 2) as usize;
if self.0 % 2 == 0 {
Direct(Inst::new(index))
} else {
Table(index)
}
}
/// Assuming that this is a direct value, get the referenced instruction.
///
/// # Panics
///
/// If this is not a value created with `new_direct()`.
pub fn unwrap_direct(&self) -> Inst {
if let ExpandedValue::Direct(inst) = self.expand() {
inst
} else {
panic!("{} is not a direct value", self)
}
}
}
/// Display a `Value` reference as "v7" or "v2x".
impl Display for Value {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
use self::ExpandedValue::*;
match self.expand() {
Direct(i) => write!(fmt, "v{}", i.0),
Table(i) => write!(fmt, "vx{}", i),
}
}
} }
/// An opaque reference to an instruction in a function. /// An opaque reference to an instruction in a function.
@@ -276,32 +199,14 @@ impl From<SigRef> for AnyEntity {
mod tests { mod tests {
use super::*; use super::*;
use std::u32; use std::u32;
use entity_map::EntityRef;
#[test] #[test]
fn value_with_number() { fn value_with_number() {
assert_eq!(Value::direct_with_number(0).unwrap().to_string(), "v0"); assert_eq!(Value::with_number(0).unwrap().to_string(), "v0");
assert_eq!(Value::direct_with_number(1).unwrap().to_string(), "v1"); assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");
assert_eq!(Value::table_with_number(0).unwrap().to_string(), "vx0");
assert_eq!(Value::table_with_number(1).unwrap().to_string(), "vx1");
assert_eq!(Value::direct_with_number(u32::MAX / 2), None); assert_eq!(Value::with_number(u32::MAX / 2), None);
assert_eq!(match Value::direct_with_number(u32::MAX / 2 - 1) assert!(Value::with_number(u32::MAX / 2 - 1).is_some());
.unwrap()
.expand() {
ExpandedValue::Direct(i) => i.index() as u32,
_ => u32::MAX,
},
u32::MAX / 2 - 1);
assert_eq!(Value::table_with_number(u32::MAX / 2), None);
assert_eq!(match Value::table_with_number(u32::MAX / 2 - 1)
.unwrap()
.expand() {
ExpandedValue::Table(i) => i as u32,
_ => u32::MAX,
},
u32::MAX / 2 - 1);
} }
#[test] #[test]

View File

@@ -115,7 +115,7 @@ mod tests {
let arg64 = dfg.append_ebb_arg(ebb, types::I64); let arg64 = dfg.append_ebb_arg(ebb, types::I64);
let arg32 = dfg.append_ebb_arg(ebb, types::I32); let arg32 = dfg.append_ebb_arg(ebb, types::I32);
// Try to encode iadd_imm.i64 vx1, -10. // Try to encode iadd_imm.i64 v1, -10.
let inst64 = InstructionData::BinaryImm { let inst64 = InstructionData::BinaryImm {
opcode: Opcode::IaddImm, opcode: Opcode::IaddImm,
arg: arg64, arg: arg64,
@@ -126,7 +126,7 @@ mod tests {
assert_eq!(encstr(&*isa, isa.encode(&dfg, &inst64, types::I64).unwrap()), assert_eq!(encstr(&*isa, isa.encode(&dfg, &inst64, types::I64).unwrap()),
"I#04"); "I#04");
// Try to encode iadd_imm.i64 vx1, -10000. // Try to encode iadd_imm.i64 v1, -10000.
let inst64_large = InstructionData::BinaryImm { let inst64_large = InstructionData::BinaryImm {
opcode: Opcode::IaddImm, opcode: Opcode::IaddImm,
arg: arg64, arg: arg64,
@@ -162,7 +162,7 @@ mod tests {
let arg64 = dfg.append_ebb_arg(ebb, types::I64); let arg64 = dfg.append_ebb_arg(ebb, types::I64);
let arg32 = dfg.append_ebb_arg(ebb, types::I32); let arg32 = dfg.append_ebb_arg(ebb, types::I32);
// Try to encode iadd_imm.i64 vx1, -10. // Try to encode iadd_imm.i64 v1, -10.
let inst64 = InstructionData::BinaryImm { let inst64 = InstructionData::BinaryImm {
opcode: Opcode::IaddImm, opcode: Opcode::IaddImm,
arg: arg64, arg: arg64,
@@ -173,7 +173,7 @@ mod tests {
assert_eq!(isa.encode(&dfg, &inst64, types::I64), assert_eq!(isa.encode(&dfg, &inst64, types::I64),
Err(isa::Legalize::Narrow)); Err(isa::Legalize::Narrow));
// Try to encode iadd_imm.i64 vx1, -10000. // Try to encode iadd_imm.i64 v1, -10000.
let inst64_large = InstructionData::BinaryImm { let inst64_large = InstructionData::BinaryImm {
opcode: Opcode::IaddImm, opcode: Opcode::IaddImm,
arg: arg64, arg: arg64,

View File

@@ -86,8 +86,8 @@ pub fn write_ebb_header(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
// Write out the basic block header, outdented: // Write out the basic block header, outdented:
// //
// ebb1: // ebb1:
// ebb1(vx1: i32): // ebb1(v1: i32):
// ebb10(vx4: f64, vx5: b1): // ebb10(v4: f64, v5: b1):
// //
// If we're writing encoding annotations, shift by 20. // If we're writing encoding annotations, shift by 20.
@@ -372,10 +372,10 @@ mod tests {
f.dfg.append_ebb_arg(ebb, types::I8); f.dfg.append_ebb_arg(ebb, types::I8);
assert_eq!(f.to_string(), assert_eq!(f.to_string(),
"function foo() {\n ss0 = stack_slot 4\n\nebb0(vx0: i8):\n}\n"); "function foo() {\n ss0 = stack_slot 4\n\nebb0(v0: i8):\n}\n");
f.dfg.append_ebb_arg(ebb, types::F32.by(4).unwrap()); f.dfg.append_ebb_arg(ebb, types::F32.by(4).unwrap());
assert_eq!(f.to_string(), assert_eq!(f.to_string(),
"function foo() {\n ss0 = stack_slot 4\n\nebb0(vx0: i8, vx1: f32x4):\n}\n"); "function foo() {\n ss0 = stack_slot 4\n\nebb0(v0: i8, v1: f32x4):\n}\n");
} }
} }

View File

@@ -34,7 +34,7 @@ pub enum Token<'a> {
Float(&'a str), // Floating point immediate Float(&'a str), // Floating point immediate
Integer(&'a str), // Integer immediate Integer(&'a str), // Integer immediate
Type(types::Type), // i32, f32, b32x4, ... Type(types::Type), // i32, f32, b32x4, ...
Value(Value), // v12, vx7 Value(Value), // v12, v7
Ebb(Ebb), // ebb3 Ebb(Ebb), // ebb3
StackSlot(u32), // ss3 StackSlot(u32), // ss3
JumpTable(u32), // jt2 JumpTable(u32), // jt2
@@ -306,8 +306,7 @@ impl<'a> Lexer<'a> {
// decoded token. // decoded token.
fn numbered_entity(prefix: &str, number: u32) -> Option<Token<'a>> { fn numbered_entity(prefix: &str, number: u32) -> Option<Token<'a>> {
match prefix { match prefix {
"v" => Value::direct_with_number(number).map(|v| Token::Value(v)), "v" => Value::with_number(number).map(|v| Token::Value(v)),
"vx" => Value::table_with_number(number).map(|v| Token::Value(v)),
"ebb" => Ebb::with_number(number).map(|ebb| Token::Ebb(ebb)), "ebb" => Ebb::with_number(number).map(|ebb| Token::Ebb(ebb)),
"ss" => Some(Token::StackSlot(number)), "ss" => Some(Token::StackSlot(number)),
"jt" => Some(Token::JumpTable(number)), "jt" => Some(Token::JumpTable(number)),
@@ -531,15 +530,14 @@ mod tests {
let mut lex = Lexer::new("v0 v00 vx01 ebb1234567890 ebb5234567890 v1x vx1 vxvx4 \ let mut lex = Lexer::new("v0 v00 vx01 ebb1234567890 ebb5234567890 v1x vx1 vxvx4 \
function0 function b1 i32x4 f32x5"); function0 function b1 i32x4 f32x5");
assert_eq!(lex.next(), assert_eq!(lex.next(),
token(Token::Value(Value::direct_with_number(0).unwrap()), 1)); token(Token::Value(Value::with_number(0).unwrap()), 1));
assert_eq!(lex.next(), token(Token::Identifier("v00"), 1)); assert_eq!(lex.next(), token(Token::Identifier("v00"), 1));
assert_eq!(lex.next(), token(Token::Identifier("vx01"), 1)); assert_eq!(lex.next(), token(Token::Identifier("vx01"), 1));
assert_eq!(lex.next(), assert_eq!(lex.next(),
token(Token::Ebb(Ebb::with_number(1234567890).unwrap()), 1)); token(Token::Ebb(Ebb::with_number(1234567890).unwrap()), 1));
assert_eq!(lex.next(), token(Token::Identifier("ebb5234567890"), 1)); assert_eq!(lex.next(), token(Token::Identifier("ebb5234567890"), 1));
assert_eq!(lex.next(), token(Token::Identifier("v1x"), 1)); assert_eq!(lex.next(), token(Token::Identifier("v1x"), 1));
assert_eq!(lex.next(), assert_eq!(lex.next(), token(Token::Identifier("vx1"), 1));
token(Token::Value(Value::table_with_number(1).unwrap()), 1));
assert_eq!(lex.next(), token(Token::Identifier("vxvx4"), 1)); assert_eq!(lex.next(), token(Token::Identifier("vxvx4"), 1));
assert_eq!(lex.next(), token(Token::Identifier("function0"), 1)); assert_eq!(lex.next(), token(Token::Identifier("function0"), 1));
assert_eq!(lex.next(), token(Token::Identifier("function"), 1)); assert_eq!(lex.next(), token(Token::Identifier("function"), 1));

View File

@@ -1011,7 +1011,7 @@ impl<'a> Parser<'a> {
// We need to parse instruction results here because they are shared // We need to parse instruction results here because they are shared
// between the parsing of value aliases and the parsing of instructions. // between the parsing of value aliases and the parsing of instructions.
// //
// inst-results ::= Value(v) { "," Value(vx) } // inst-results ::= Value(v) { "," Value(v) }
let results = self.parse_inst_results()?; let results = self.parse_inst_results()?;
match self.token() { match self.token() {
@@ -1032,7 +1032,7 @@ impl<'a> Parser<'a> {
} }
// Parse parenthesized list of EBB arguments. Returns a vector of (u32, Type) pairs with the // Parse parenthesized list of EBB arguments. Returns a vector of (u32, Type) pairs with the
// source vx numbers of the defined values and the defined types. // source value numbers of the defined values and the defined types.
// //
// ebb-args ::= * "(" ebb-arg { "," ebb-arg } ")" // ebb-args ::= * "(" ebb-arg { "," ebb-arg } ")"
fn parse_ebb_args(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> { fn parse_ebb_args(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> {
@@ -1056,19 +1056,19 @@ impl<'a> Parser<'a> {
// Parse a single EBB argument declaration, and append it to `ebb`. // Parse a single EBB argument declaration, and append it to `ebb`.
// //
// ebb-arg ::= * Value(vx) ":" Type(t) // ebb-arg ::= * Value(v) ":" Type(t)
// //
fn parse_ebb_arg(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> { fn parse_ebb_arg(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> {
// ebb-arg ::= * Value(vx) ":" Type(t) // ebb-arg ::= * Value(v) ":" Type(t)
let vx = self.match_value("EBB argument must be a value")?; let v = self.match_value("EBB argument must be a value")?;
let vx_location = self.loc; let v_location = self.loc;
// ebb-arg ::= Value(vx) * ":" Type(t) // ebb-arg ::= Value(v) * ":" Type(t)
self.match_token(Token::Colon, "expected ':' after EBB argument")?; self.match_token(Token::Colon, "expected ':' after EBB argument")?;
// ebb-arg ::= Value(vx) ":" * Type(t) // ebb-arg ::= Value(v) ":" * Type(t)
let t = self.match_type("expected EBB argument type")?; let t = self.match_type("expected EBB argument type")?;
// Allocate the EBB argument and add the mapping. // Allocate the EBB argument and add the mapping.
let value = ctx.function.dfg.append_ebb_arg(ebb, t); let value = ctx.function.dfg.append_ebb_arg(ebb, t);
ctx.map.def_value(vx, value, &vx_location) ctx.map.def_value(v, value, &v_location)
} }
fn parse_value_location(&mut self, ctx: &Context) -> Result<ValueLoc> { fn parse_value_location(&mut self, ctx: &Context) -> Result<ValueLoc> {
@@ -1147,21 +1147,21 @@ impl<'a> Parser<'a> {
// Parse instruction results and return them. // Parse instruction results and return them.
// //
// inst-results ::= Value(v) { "," Value(vx) } // inst-results ::= Value(v) { "," Value(v) }
// //
fn parse_inst_results(&mut self) -> Result<Vec<Value>> { fn parse_inst_results(&mut self) -> Result<Vec<Value>> {
// Result value numbers. // Result value numbers.
let mut results = Vec::new(); let mut results = Vec::new();
// instruction ::= * [inst-results "="] Opcode(opc) ["." Type] ... // instruction ::= * [inst-results "="] Opcode(opc) ["." Type] ...
// inst-results ::= * Value(v) { "," Value(vx) } // inst-results ::= * Value(v) { "," Value(v) }
if let Some(Token::Value(v)) = self.token() { if let Some(Token::Value(v)) = self.token() {
self.consume(); self.consume();
results.push(v); results.push(v);
// inst-results ::= Value(v) * { "," Value(vx) } // inst-results ::= Value(v) * { "," Value(v) }
while self.optional(Token::Comma) { while self.optional(Token::Comma) {
// inst-results ::= Value(v) { "," * Value(vx) } // inst-results ::= Value(v) { "," * Value(v) }
results.push(self.match_value("expected result value")?); results.push(self.match_value("expected result value")?);
} }
} }
@@ -1171,7 +1171,7 @@ impl<'a> Parser<'a> {
// Parse a value alias, and append it to `ebb`. // Parse a value alias, and append it to `ebb`.
// //
// value_alias ::= [inst-results] "->" Value(vx) // value_alias ::= [inst-results] "->" Value(v)
// //
fn parse_value_alias(&mut self, results: Vec<Value>, ctx: &mut Context) -> Result<()> { fn parse_value_alias(&mut self, results: Vec<Value>, ctx: &mut Context) -> Result<()> {
if results.len() != 1 { if results.len() != 1 {
@@ -1711,19 +1711,23 @@ mod tests {
let (func, details) = Parser::new("function qux() { let (func, details) = Parser::new("function qux() {
ebb0: ebb0:
v4 = iconst.i8 6 v4 = iconst.i8 6
vx3 -> v4 v3 -> v4
v1 = iadd_imm vx3, 17 v1 = iadd_imm v3, 17
}") }")
.parse_function(None) .parse_function(None)
.unwrap(); .unwrap();
assert_eq!(func.name.to_string(), "qux"); assert_eq!(func.name.to_string(), "qux");
let v4 = details.map.lookup_str("v4").unwrap(); let v4 = details.map.lookup_str("v4").unwrap();
assert_eq!(v4.to_string(), "vx0"); assert_eq!(v4.to_string(), "v0");
let vx3 = details.map.lookup_str("vx3").unwrap(); let v3 = details.map.lookup_str("v3").unwrap();
assert_eq!(vx3.to_string(), "vx2"); assert_eq!(v3.to_string(), "v2");
let aliased_to = func.dfg match v3 {
.resolve_aliases(Value::table_with_number(0).unwrap()); AnyEntity::Value(v3) => {
assert_eq!(aliased_to.to_string(), "vx0"); let aliased_to = func.dfg.resolve_aliases(v3);
assert_eq!(aliased_to.to_string(), "v0");
}
_ => panic!("expected value: {}", v3),
}
} }
#[test] #[test]
@@ -1789,7 +1793,7 @@ mod tests {
fn ebb_header() { fn ebb_header() {
let (func, _) = Parser::new("function ebbs() { let (func, _) = Parser::new("function ebbs() {
ebb0: ebb0:
ebb4(vx3: i32): ebb4(v3: i32):
}") }")
.parse_function(None) .parse_function(None)
.unwrap(); .unwrap();

View File

@@ -16,7 +16,7 @@ use lexer::split_entity_name;
/// Mapping from source entity names to entity references that are valid in the parsed function. /// Mapping from source entity names to entity references that are valid in the parsed function.
#[derive(Debug)] #[derive(Debug)]
pub struct SourceMap { pub struct SourceMap {
values: HashMap<Value, Value>, // vNN, vxNN values: HashMap<Value, Value>, // vNN
ebbs: HashMap<Ebb, Ebb>, // ebbNN ebbs: HashMap<Ebb, Ebb>, // ebbNN
stack_slots: HashMap<u32, StackSlot>, // ssNN stack_slots: HashMap<u32, StackSlot>, // ssNN
signatures: HashMap<u32, SigRef>, // sigNN signatures: HashMap<u32, SigRef>, // sigNN
@@ -64,12 +64,7 @@ impl SourceMap {
pub fn lookup_str(&self, name: &str) -> Option<AnyEntity> { pub fn lookup_str(&self, name: &str) -> Option<AnyEntity> {
split_entity_name(name).and_then(|(ent, num)| match ent { split_entity_name(name).and_then(|(ent, num)| match ent {
"v" => { "v" => {
Value::direct_with_number(num) Value::with_number(num)
.and_then(|v| self.get_value(v))
.map(AnyEntity::Value)
}
"vx" => {
Value::table_with_number(num)
.and_then(|v| self.get_value(v)) .and_then(|v| self.get_value(v))
.map(AnyEntity::Value) .map(AnyEntity::Value)
} }
@@ -230,8 +225,8 @@ mod tests {
let tf = parse_test("function detail() { let tf = parse_test("function detail() {
ss10 = stack_slot 13 ss10 = stack_slot 13
jt10 = jump_table ebb0 jt10 = jump_table ebb0
ebb0(v4: i32, vx7: i32): ebb0(v4: i32, v7: i32):
v10 = iadd v4, vx7 v10 = iadd v4, v7
}") }")
.unwrap(); .unwrap();
let map = &tf.functions[0].1.map; let map = &tf.functions[0].1.map;
@@ -241,8 +236,8 @@ mod tests {
assert_eq!(map.lookup_str("ss10").unwrap().to_string(), "ss0"); assert_eq!(map.lookup_str("ss10").unwrap().to_string(), "ss0");
assert_eq!(map.lookup_str("jt10").unwrap().to_string(), "jt0"); assert_eq!(map.lookup_str("jt10").unwrap().to_string(), "jt0");
assert_eq!(map.lookup_str("ebb0").unwrap().to_string(), "ebb0"); assert_eq!(map.lookup_str("ebb0").unwrap().to_string(), "ebb0");
assert_eq!(map.lookup_str("v4").unwrap().to_string(), "vx0"); assert_eq!(map.lookup_str("v4").unwrap().to_string(), "v0");
assert_eq!(map.lookup_str("vx7").unwrap().to_string(), "vx1"); assert_eq!(map.lookup_str("v7").unwrap().to_string(), "v1");
assert_eq!(map.lookup_str("v10").unwrap().to_string(), "vx2"); assert_eq!(map.lookup_str("v10").unwrap().to_string(), "v2");
} }
} }

View File

@@ -18,7 +18,7 @@ syn keyword ctonDecl function stack_slot jump_table
syn keyword ctonFilecheck check sameln nextln unordered not regex contained syn keyword ctonFilecheck check sameln nextln unordered not regex contained
syn match ctonType /\<[bif]\d\+\(x\d\+\)\?\>/ syn match ctonType /\<[bif]\d\+\(x\d\+\)\?\>/
syn match ctonEntity /\<\(v\|vx\|ss\|jt\|fn\|sig\)\d\+\>/ syn match ctonEntity /\<\(v\|ss\|jt\|fn\|sig\)\d\+\>/
syn match ctonLabel /\<ebb\d+\>/ syn match ctonLabel /\<ebb\d+\>/
syn match ctonName /%\w\+\>/ syn match ctonName /%\w\+\>/