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.
(r'\b(b\d+|i\d+|f32|f64)(x\d+)?\b', Keyword.Type),
# v<nn> = value
# vx<nn> = value
# ss<nn> = stack slot
# jt<nn> = jump table
(r'(vx?|ss|jt)\d+', Name.Variable),
(r'(v|ss|jt)\d+', Name.Variable),
# ebb<nn> = extended basic block
(r'(ebb)\d+', Name.Label),
# Match instruction names in context.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -76,97 +76,20 @@ impl Ebb {
/// An opaque reference to an SSA value.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Value(u32);
entity_impl!(Value);
/// 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),
}
entity_impl!(Value, "v");
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 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 {
let encoding = n * 2;
assert!(encoding < u32::MAX);
Some(Value(encoding))
Some(Value(n))
} else {
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.
@@ -276,32 +199,14 @@ impl From<SigRef> for AnyEntity {
mod tests {
use super::*;
use std::u32;
use entity_map::EntityRef;
#[test]
fn value_with_number() {
assert_eq!(Value::direct_with_number(0).unwrap().to_string(), "v0");
assert_eq!(Value::direct_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::with_number(0).unwrap().to_string(), "v0");
assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");
assert_eq!(Value::direct_with_number(u32::MAX / 2), None);
assert_eq!(match Value::direct_with_number(u32::MAX / 2 - 1)
.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);
assert_eq!(Value::with_number(u32::MAX / 2), None);
assert!(Value::with_number(u32::MAX / 2 - 1).is_some());
}
#[test]

View File

@@ -115,7 +115,7 @@ mod tests {
let arg64 = dfg.append_ebb_arg(ebb, types::I64);
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 {
opcode: Opcode::IaddImm,
arg: arg64,
@@ -126,7 +126,7 @@ mod tests {
assert_eq!(encstr(&*isa, isa.encode(&dfg, &inst64, types::I64).unwrap()),
"I#04");
// Try to encode iadd_imm.i64 vx1, -10000.
// Try to encode iadd_imm.i64 v1, -10000.
let inst64_large = InstructionData::BinaryImm {
opcode: Opcode::IaddImm,
arg: arg64,
@@ -162,7 +162,7 @@ mod tests {
let arg64 = dfg.append_ebb_arg(ebb, types::I64);
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 {
opcode: Opcode::IaddImm,
arg: arg64,
@@ -173,7 +173,7 @@ mod tests {
assert_eq!(isa.encode(&dfg, &inst64, types::I64),
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 {
opcode: Opcode::IaddImm,
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:
//
// ebb1:
// ebb1(vx1: i32):
// ebb10(vx4: f64, vx5: b1):
// ebb1(v1: i32):
// ebb10(v4: f64, v5: b1):
//
// If we're writing encoding annotations, shift by 20.
@@ -372,10 +372,10 @@ mod tests {
f.dfg.append_ebb_arg(ebb, types::I8);
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());
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
Integer(&'a str), // Integer immediate
Type(types::Type), // i32, f32, b32x4, ...
Value(Value), // v12, vx7
Value(Value), // v12, v7
Ebb(Ebb), // ebb3
StackSlot(u32), // ss3
JumpTable(u32), // jt2
@@ -306,8 +306,7 @@ impl<'a> Lexer<'a> {
// decoded token.
fn numbered_entity(prefix: &str, number: u32) -> Option<Token<'a>> {
match prefix {
"v" => Value::direct_with_number(number).map(|v| Token::Value(v)),
"vx" => Value::table_with_number(number).map(|v| Token::Value(v)),
"v" => Value::with_number(number).map(|v| Token::Value(v)),
"ebb" => Ebb::with_number(number).map(|ebb| Token::Ebb(ebb)),
"ss" => Some(Token::StackSlot(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 \
function0 function b1 i32x4 f32x5");
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("vx01"), 1));
assert_eq!(lex.next(),
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("v1x"), 1));
assert_eq!(lex.next(),
token(Token::Value(Value::table_with_number(1).unwrap()), 1));
assert_eq!(lex.next(), token(Token::Identifier("vx1"), 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("function"), 1));

View File

@@ -1011,7 +1011,7 @@ impl<'a> Parser<'a> {
// We need to parse instruction results here because they are shared
// 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()?;
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
// 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 } ")"
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`.
//
// ebb-arg ::= * Value(vx) ":" Type(t)
// ebb-arg ::= * Value(v) ":" Type(t)
//
fn parse_ebb_arg(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> {
// ebb-arg ::= * Value(vx) ":" Type(t)
let vx = self.match_value("EBB argument must be a value")?;
let vx_location = self.loc;
// ebb-arg ::= Value(vx) * ":" Type(t)
// ebb-arg ::= * Value(v) ":" Type(t)
let v = self.match_value("EBB argument must be a value")?;
let v_location = self.loc;
// ebb-arg ::= Value(v) * ":" Type(t)
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")?;
// Allocate the EBB argument and add the mapping.
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> {
@@ -1147,21 +1147,21 @@ impl<'a> Parser<'a> {
// 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>> {
// Result value numbers.
let mut results = Vec::new();
// 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() {
self.consume();
results.push(v);
// inst-results ::= Value(v) * { "," Value(vx) }
// inst-results ::= Value(v) * { "," Value(v) }
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")?);
}
}
@@ -1171,7 +1171,7 @@ impl<'a> Parser<'a> {
// 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<()> {
if results.len() != 1 {
@@ -1711,19 +1711,23 @@ mod tests {
let (func, details) = Parser::new("function qux() {
ebb0:
v4 = iconst.i8 6
vx3 -> v4
v1 = iadd_imm vx3, 17
v3 -> v4
v1 = iadd_imm v3, 17
}")
.parse_function(None)
.unwrap();
assert_eq!(func.name.to_string(), "qux");
let v4 = details.map.lookup_str("v4").unwrap();
assert_eq!(v4.to_string(), "vx0");
let vx3 = details.map.lookup_str("vx3").unwrap();
assert_eq!(vx3.to_string(), "vx2");
let aliased_to = func.dfg
.resolve_aliases(Value::table_with_number(0).unwrap());
assert_eq!(aliased_to.to_string(), "vx0");
assert_eq!(v4.to_string(), "v0");
let v3 = details.map.lookup_str("v3").unwrap();
assert_eq!(v3.to_string(), "v2");
match v3 {
AnyEntity::Value(v3) => {
let aliased_to = func.dfg.resolve_aliases(v3);
assert_eq!(aliased_to.to_string(), "v0");
}
_ => panic!("expected value: {}", v3),
}
}
#[test]
@@ -1789,7 +1793,7 @@ mod tests {
fn ebb_header() {
let (func, _) = Parser::new("function ebbs() {
ebb0:
ebb4(vx3: i32):
ebb4(v3: i32):
}")
.parse_function(None)
.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.
#[derive(Debug)]
pub struct SourceMap {
values: HashMap<Value, Value>, // vNN, vxNN
values: HashMap<Value, Value>, // vNN
ebbs: HashMap<Ebb, Ebb>, // ebbNN
stack_slots: HashMap<u32, StackSlot>, // ssNN
signatures: HashMap<u32, SigRef>, // sigNN
@@ -64,12 +64,7 @@ impl SourceMap {
pub fn lookup_str(&self, name: &str) -> Option<AnyEntity> {
split_entity_name(name).and_then(|(ent, num)| match ent {
"v" => {
Value::direct_with_number(num)
.and_then(|v| self.get_value(v))
.map(AnyEntity::Value)
}
"vx" => {
Value::table_with_number(num)
Value::with_number(num)
.and_then(|v| self.get_value(v))
.map(AnyEntity::Value)
}
@@ -230,8 +225,8 @@ mod tests {
let tf = parse_test("function detail() {
ss10 = stack_slot 13
jt10 = jump_table ebb0
ebb0(v4: i32, vx7: i32):
v10 = iadd v4, vx7
ebb0(v4: i32, v7: i32):
v10 = iadd v4, v7
}")
.unwrap();
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("jt10").unwrap().to_string(), "jt0");
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("vx7").unwrap().to_string(), "vx1");
assert_eq!(map.lookup_str("v10").unwrap().to_string(), "vx2");
assert_eq!(map.lookup_str("v4").unwrap().to_string(), "v0");
assert_eq!(map.lookup_str("v7").unwrap().to_string(), "v1");
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 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 ctonName /%\w\+\>/