Inline jump tables in parsed br_table instructions (#5755)

As jump tables are used by at most one br_table instruction, inline their definition in those instructions instead of requiring them to be declared as function-level metadata.
This commit is contained in:
Trevor Elliott
2023-02-09 14:24:04 -08:00
committed by GitHub
parent 202d3af16a
commit 15fe9c7c93
23 changed files with 54 additions and 200 deletions

View File

@@ -41,7 +41,6 @@ pub enum Token<'a> {
DynamicStackSlot(u32), // dss4
GlobalValue(u32), // gv3
Table(u32), // table2
JumpTable(u32), // jt2
Constant(u32), // const2
FuncRef(u32), // fn2
SigRef(u32), // sig2
@@ -346,7 +345,6 @@ impl<'a> Lexer<'a> {
"dt" => Some(Token::DynamicType(number)),
"gv" => Some(Token::GlobalValue(number)),
"table" => Some(Token::Table(number)),
"jt" => Some(Token::JumpTable(number)),
"const" => Some(Token::Constant(number)),
"fn" => Some(Token::FuncRef(number)),
"sig" => Some(Token::SigRef(number)),

View File

@@ -18,8 +18,8 @@ use cranelift_codegen::ir::{self, UserExternalNameRef};
use cranelift_codegen::ir::{
AbiParam, ArgumentExtension, ArgumentPurpose, Block, Constant, ConstantData, DynamicStackSlot,
DynamicStackSlotData, DynamicTypeData, ExtFuncData, ExternalName, FuncRef, Function,
GlobalValue, GlobalValueData, JumpTable, JumpTableData, MemFlags, Opcode, SigRef, Signature,
StackSlot, StackSlotData, StackSlotKind, Table, TableData, Type, UserFuncName, Value,
GlobalValue, GlobalValueData, JumpTableData, MemFlags, Opcode, SigRef, Signature, StackSlot,
StackSlotData, StackSlotKind, Table, TableData, Type, UserFuncName, Value,
};
use cranelift_codegen::isa::{self, CallConv};
use cranelift_codegen::packed_option::ReservedValue;
@@ -390,25 +390,6 @@ impl Context {
}
}
// Allocate a new jump table.
fn add_jt(&mut self, jt: JumpTable, data: JumpTableData, loc: Location) -> ParseResult<()> {
self.map.def_jt(jt, loc)?;
while self.function.stencil.dfg.jump_tables.next_key().index() <= jt.index() {
self.function.create_jump_table(JumpTableData::new());
}
self.function.stencil.dfg.jump_tables[jt] = data;
Ok(())
}
// Resolve a reference to a jump table.
fn check_jt(&self, jt: JumpTable, loc: Location) -> ParseResult<()> {
if !self.map.contains_jt(jt) {
err!(loc, "undefined jump table {}", jt)
} else {
Ok(())
}
}
// Allocate a new constant.
fn add_constant(
&mut self,
@@ -670,17 +651,6 @@ impl<'a> Parser<'a> {
err!(self.loc, err_msg)
}
// Match and consume a jump table reference.
fn match_jt(&mut self) -> ParseResult<JumpTable> {
if let Some(Token::JumpTable(jt)) = self.token() {
self.consume();
if let Some(jt) = JumpTable::with_number(jt) {
return Ok(jt);
}
}
err!(self.loc, "expected jump table number: jt«n»")
}
// Match and consume a constant reference.
fn match_constant(&mut self) -> ParseResult<Constant> {
if let Some(Token::Constant(c)) = self.token() {
@@ -1484,11 +1454,6 @@ impl<'a> Parser<'a> {
self.parse_function_decl(ctx)
.and_then(|(fn_, dat)| ctx.add_fn(fn_, dat, self.loc))
}
Some(Token::JumpTable(..)) => {
self.start_gathering_comments();
self.parse_jump_table_decl()
.and_then(|(jt, dat)| ctx.add_jt(jt, dat, self.loc))
}
Some(Token::Constant(..)) => {
self.start_gathering_comments();
self.parse_constant_decl()
@@ -1798,18 +1763,15 @@ impl<'a> Parser<'a> {
Ok((fn_, data))
}
// Parse a jump table decl.
// Parse a jump table literal.
//
// jump-table-decl ::= * JumpTable(jt) "=" "jump_table" "[" jt-entry {"," jt-entry} "]"
fn parse_jump_table_decl(&mut self) -> ParseResult<(JumpTable, JumpTableData)> {
let jt = self.match_jt()?;
self.match_token(Token::Equal, "expected '=' in jump_table decl")?;
self.match_identifier("jump_table", "expected 'jump_table'")?;
// jump-table-lit ::= "[" block {"," block } "]"
// | "[]"
fn parse_jump_table(&mut self) -> ParseResult<JumpTableData> {
self.match_token(Token::LBracket, "expected '[' before jump table contents")?;
let mut data = JumpTableData::new();
// jump-table-decl ::= JumpTable(jt) "=" "jump_table" "[" * Block(dest) {"," Block(dest)} "]"
match self.token() {
Some(Token::Block(dest)) => {
self.consume();
@@ -1837,11 +1799,7 @@ impl<'a> Parser<'a> {
self.consume();
// Collect any trailing comments.
self.token();
self.claim_gathered_comments(jt);
Ok((jt, data))
Ok(data)
}
// Parse a constant decl.
@@ -2613,8 +2571,8 @@ impl<'a> Parser<'a> {
self.match_token(Token::Comma, "expected ',' between operands")?;
let block_num = self.match_block("expected branch destination block")?;
self.match_token(Token::Comma, "expected ',' between operands")?;
let table = self.match_jt()?;
ctx.check_jt(table, self.loc)?;
let table_data = self.parse_jump_table()?;
let table = ctx.function.dfg.jump_tables.push(table_data);
InstructionData::BranchTable {
opcode,
arg,
@@ -3079,25 +3037,6 @@ mod tests {
assert!(!is_warning);
}
#[test]
fn duplicate_jt() {
let ParseError {
location,
message,
is_warning,
} = Parser::new(
"function %blocks() system_v {
jt0 = jump_table []
jt0 = jump_table []",
)
.parse_function()
.unwrap_err();
assert_eq!(location.line_number, 3);
assert_eq!(message, "duplicate entity: jt0");
assert!(!is_warning);
}
#[test]
fn duplicate_ss() {
let ParseError {
@@ -3182,8 +3121,6 @@ mod tests {
function %comment() system_v { ; decl
ss10 = explicit_slot 13 ; stackslot.
; Still stackslot.
jt10 = jump_table [block0]
; Jumptable
block0: ; Basic block
trap user42; Instruction
} ; Trailing.
@@ -3192,7 +3129,7 @@ mod tests {
.parse_function()
.unwrap();
assert_eq!(func.name.to_string(), "%comment");
assert_eq!(comments.len(), 8); // no 'before' comment.
assert_eq!(comments.len(), 7); // no 'before' comment.
assert_eq!(
comments[0],
Comment {
@@ -3203,16 +3140,14 @@ mod tests {
assert_eq!(comments[1].entity.to_string(), "ss10");
assert_eq!(comments[2].entity.to_string(), "ss10");
assert_eq!(comments[2].text, "; Still stackslot.");
assert_eq!(comments[3].entity.to_string(), "jt10");
assert_eq!(comments[3].text, "; Jumptable");
assert_eq!(comments[4].entity.to_string(), "block0");
assert_eq!(comments[4].text, "; Basic block");
assert_eq!(comments[3].entity.to_string(), "block0");
assert_eq!(comments[3].text, "; Basic block");
assert_eq!(comments[5].entity.to_string(), "inst0");
assert_eq!(comments[5].text, "; Instruction");
assert_eq!(comments[4].entity.to_string(), "inst0");
assert_eq!(comments[4].text, "; Instruction");
assert_eq!(comments[5].entity, AnyEntity::Function);
assert_eq!(comments[6].entity, AnyEntity::Function);
assert_eq!(comments[7].entity, AnyEntity::Function);
}
#[test]

View File

@@ -227,7 +227,6 @@ mod tests {
let tf = parse_test(
"function %detail() {
ss10 = explicit_slot 13
jt10 = jump_table [block0]
block0(v4: i32, v7: i32):
v10 = iadd v4, v7
}",
@@ -239,7 +238,6 @@ mod tests {
assert_eq!(map.lookup_str("v0"), None);
assert_eq!(map.lookup_str("ss1"), None);
assert_eq!(map.lookup_str("ss10").unwrap().to_string(), "ss10");
assert_eq!(map.lookup_str("jt10").unwrap().to_string(), "jt10");
assert_eq!(map.lookup_str("block0").unwrap().to_string(), "block0");
assert_eq!(map.lookup_str("v4").unwrap().to_string(), "v4");
assert_eq!(map.lookup_str("v7").unwrap().to_string(), "v7");