Parse signature and function declarations.

Also add support for parsing call and call_indirect instructions.
This commit is contained in:
Jakob Stoklund Olesen
2016-10-18 10:58:59 -07:00
parent cdb63a547e
commit df06f19979
2 changed files with 187 additions and 4 deletions

View File

@@ -22,3 +22,49 @@ ebb1:
; nextln: v1 = f32const 0.0 ; nextln: v1 = f32const 0.0
; nextln: return v0, v1 ; nextln: return v0, v1
; nextln: } ; nextln: }
function signatures() {
sig10 = signature()
sig11 = signature(i32, f64) -> i32, b1
fn5 = sig11 foo
fn8 = function bar(i32) -> b1
}
; sameln: function signatures() {
; nextln: $sig10 = signature()
; nextln: $sig11 = signature(i32, f64) -> i32, b1
; nextln: sig2 = signature(i32) -> b1
; nextln: $fn5 = $sig11 foo
; nextln: $fn8 = sig2 bar
; nextln: }
function direct() {
fn0 = function none()
fn1 = function one() -> i32
fn2 = function two() -> i32, f32
ebb0:
call fn0()
v1 = call fn1()
v2, v3 = call fn2()
return
}
; check: call $fn0()
; check: $v1 = call $fn1()
; check: $v2, $v3 = call $fn2()
; check: return
function indirect(i64) {
sig0 = signature(i64)
sig1 = signature() -> i32
sig2 = signature() -> i32, f32
ebb0(v0: i64):
v1 = call_indirect sig1, v0()
call_indirect sig0, v1(v0)
v3, v4 = call_indirect sig2, v1()
return
}
; check: $v1 = call_indirect $sig1, $v0()
; check: call_indirect $sig0, $v1($v0)
; check: $v3, $v4 = call_indirect $sig2, $v1()
; check: return

View File

@@ -9,12 +9,14 @@ use std::str::FromStr;
use std::u32; use std::u32;
use std::mem; use std::mem;
use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, StackSlotData, JumpTable, use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, StackSlotData, JumpTable,
JumpTableData, Signature, ArgumentType, ArgumentExtension}; JumpTableData, Signature, ArgumentType, ArgumentExtension, ExtFuncData, SigRef,
FuncRef};
use cretonne::ir::types::VOID; use cretonne::ir::types::VOID;
use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64};
use cretonne::ir::entities::{AnyEntity, NO_EBB, NO_INST, NO_VALUE}; use cretonne::ir::entities::{AnyEntity, NO_EBB, NO_INST, NO_VALUE};
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs, use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs,
TernaryOverflowData, JumpData, BranchData, ReturnData}; TernaryOverflowData, JumpData, BranchData, CallData,
IndirectCallData, ReturnData};
use cretonne::isa; use cretonne::isa;
use cretonne::settings; use cretonne::settings;
use testfile::{TestFile, Details, Comment}; use testfile::{TestFile, Details, Comment};
@@ -84,6 +86,32 @@ impl Context {
self.map.def_ss(number, self.function.stack_slots.push(data), loc) self.map.def_ss(number, self.function.stack_slots.push(data), loc)
} }
// Allocate a new signature and add a mapping number -> SigRef.
fn add_sig(&mut self, number: u32, data: Signature, loc: &Location) -> Result<()> {
self.map.def_sig(number, self.function.dfg.signatures.push(data), loc)
}
// Resolve a reference to a signature.
fn get_sig(&self, number: u32, loc: &Location) -> Result<SigRef> {
match self.map.get_sig(number) {
Some(sig) => Ok(sig),
None => err!(loc, "undefined signature sig{}", number),
}
}
// Allocate a new external function and add a mapping number -> FuncRef.
fn add_fn(&mut self, number: u32, data: ExtFuncData, loc: &Location) -> Result<()> {
self.map.def_fn(number, self.function.dfg.ext_funcs.push(data), loc)
}
// Resolve a reference to a function.
fn get_fn(&self, number: u32, loc: &Location) -> Result<FuncRef> {
match self.map.get_fn(number) {
Some(fnref) => Ok(fnref),
None => err!(loc, "undefined function fn{}", number),
}
}
// Allocate a new jump table and add a mapping number -> JumpTable. // Allocate a new jump table and add a mapping number -> JumpTable.
fn add_jt(&mut self, number: u32, data: JumpTableData, loc: &Location) -> Result<()> { fn add_jt(&mut self, number: u32, data: JumpTableData, loc: &Location) -> Result<()> {
self.map.def_jt(number, self.function.jump_tables.push(data), loc) self.map.def_jt(number, self.function.jump_tables.push(data), loc)
@@ -305,6 +333,26 @@ impl<'a> Parser<'a> {
} }
} }
// Match and consume a function reference.
fn match_fn(&mut self, err_msg: &str) -> Result<u32> {
if let Some(Token::FuncRef(fnref)) = self.token() {
self.consume();
Ok(fnref)
} else {
err!(self.loc, err_msg)
}
}
// Match and consume a signature reference.
fn match_sig(&mut self, err_msg: &str) -> Result<u32> {
if let Some(Token::SigRef(sigref)) = self.token() {
self.consume();
Ok(sigref)
} else {
err!(self.loc, err_msg)
}
}
// Match and consume a jump table reference. // Match and consume a jump table reference.
fn match_jt(&mut self) -> Result<u32> { fn match_jt(&mut self) -> Result<u32> {
if let Some(Token::JumpTable(jt)) = self.token() { if let Some(Token::JumpTable(jt)) = self.token() {
@@ -628,6 +676,16 @@ impl<'a> Parser<'a> {
self.parse_stack_slot_decl() self.parse_stack_slot_decl()
.and_then(|(num, dat)| ctx.add_ss(num, dat, &self.loc)) .and_then(|(num, dat)| ctx.add_ss(num, dat, &self.loc))
} }
Some(Token::SigRef(..)) => {
self.gather_comments(ctx.function.dfg.signatures.next_key());
self.parse_signature_decl()
.and_then(|(num, dat)| ctx.add_sig(num, dat, &self.loc))
}
Some(Token::FuncRef(..)) => {
self.gather_comments(ctx.function.dfg.ext_funcs.next_key());
self.parse_function_decl(ctx)
.and_then(|(num, dat)| ctx.add_fn(num, dat, &self.loc))
}
Some(Token::JumpTable(..)) => { Some(Token::JumpTable(..)) => {
self.gather_comments(ctx.function.jump_tables.next_key()); self.gather_comments(ctx.function.jump_tables.next_key());
self.parse_jump_table_decl() self.parse_jump_table_decl()
@@ -661,6 +719,56 @@ impl<'a> Parser<'a> {
Ok((number, data)) Ok((number, data))
} }
// Parse a signature decl.
//
// signature-decl ::= SigRef(sigref) "=" "signature" signature
//
fn parse_signature_decl(&mut self) -> Result<(u32, Signature)> {
let number = try!(self.match_sig("expected signature number: sig«n»"));
try!(self.match_token(Token::Equal, "expected '=' in signature decl"));
try!(self.match_identifier("signature", "expected 'signature'"));
let data = try!(self.parse_signature());
Ok((number, data))
}
// Parse a function decl.
//
// Two variants:
//
// function-decl ::= FuncRef(fnref) "=" function-spec
// FuncRef(fnref) "=" SigRef(sig) name
//
// The first variant allocates a new signature reference. The second references an existing
// signature which must be declared first.
//
fn parse_function_decl(&mut self, ctx: &mut Context) -> Result<(u32, ExtFuncData)> {
let number = try!(self.match_fn("expected function number: fn«n»"));
try!(self.match_token(Token::Equal, "expected '=' in function decl"));
let data = match self.token() {
Some(Token::Identifier("function")) => {
let (loc, name, sig) = try!(self.parse_function_spec());
let sigref = ctx.function.dfg.signatures.push(sig);
ctx.map.def_entity(sigref.into(), &loc).expect("duplicate SigRef entities created");
ExtFuncData {
name: name,
signature: sigref,
}
}
Some(Token::SigRef(sig_src)) => {
let sig = try!(ctx.get_sig(sig_src, &self.loc));
self.consume();
let name = try!(self.parse_function_name());
ExtFuncData {
name: name,
signature: sig,
}
}
_ => return err!(self.loc, "expected 'function' or sig«n» in function decl"),
};
Ok((number, data))
}
// Parse a jump table decl. // Parse a jump table decl.
// //
// jump-table-decl ::= * JumpTable(jt) "=" "jump_table" jt-entry {"," jt-entry} // jump-table-decl ::= * JumpTable(jt) "=" "jump_table" jt-entry {"," jt-entry}
@@ -1177,10 +1285,39 @@ impl<'a> Parser<'a> {
} }
} }
InstructionFormat::Call => { InstructionFormat::Call => {
unimplemented!(); let func_ref = try!(self.match_fn("expected function reference")
.and_then(|num| ctx.get_fn(num, &self.loc)));
try!(self.match_token(Token::LPar, "expected '(' before arguments"));
let args = try!(self.parse_value_list());
try!(self.match_token(Token::RPar, "expected ')' after arguments"));
InstructionData::Call {
opcode: opcode,
ty: VOID,
second_result: NO_VALUE,
data: Box::new(CallData {
func_ref: func_ref,
varargs: args,
}),
}
} }
InstructionFormat::IndirectCall => { InstructionFormat::IndirectCall => {
unimplemented!(); let sig_ref = try!(self.match_sig("expected signature reference")
.and_then(|num| ctx.get_sig(num, &self.loc)));
try!(self.match_token(Token::Comma, "expected ',' between operands"));
let callee = try!(self.match_value("expected SSA value callee operand"));
try!(self.match_token(Token::LPar, "expected '(' before arguments"));
let args = try!(self.parse_value_list());
try!(self.match_token(Token::RPar, "expected ')' after arguments"));
InstructionData::IndirectCall {
opcode: opcode,
ty: VOID,
second_result: NO_VALUE,
data: Box::new(IndirectCallData {
sig_ref: sig_ref,
arg: callee,
varargs: args,
}),
}
} }
InstructionFormat::Return => { InstructionFormat::Return => {
let args = try!(self.parse_value_list()); let args = try!(self.parse_value_list());