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:
@@ -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)),
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user