Parse signature and function declarations.
Also add support for parsing call and call_indirect instructions.
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
Reference in New Issue
Block a user