From 81f26cfbba2c184201ccd3eb74419a25cc0f42d8 Mon Sep 17 00:00:00 2001 From: Angus Holder Date: Thu, 9 Mar 2017 20:19:15 +0000 Subject: [PATCH] Added parsing of argument locations for functions and signatures. --- filetests/isa/riscv/abi.cton | 33 +++++++++++ lib/reader/src/parser.rs | 108 +++++++++++++++++++++++++++-------- 2 files changed, 117 insertions(+), 24 deletions(-) diff --git a/filetests/isa/riscv/abi.cton b/filetests/isa/riscv/abi.cton index 0282e94874..0b47fe6727 100644 --- a/filetests/isa/riscv/abi.cton +++ b/filetests/isa/riscv/abi.cton @@ -61,3 +61,36 @@ ebb0(v0: i64x4): v1 = iadd v0, v0 return v0 } + +function parse_encoding(i32 [%x5]) -> i32 [%x10] { +; check: function parse_encoding(i32 [%x5]) -> i32 [%x10] { + + sig0 = signature(i32 [%x10]) -> i32 [%x10] +; check: sig0 = signature(i32 [%x10]) -> i32 [%x10] + + sig1 = signature(i32 [%x10], i32 [%x11]) -> b1 [%x10] +; check: sig1 = signature(i32 [%x10], i32 [%x11]) -> b1 [%x10] + + sig2 = signature(f32 [%f10], i32 [%x12], i32 [%x13]) -> f64 [%f10] +; check: sig2 = signature(f32 [%f10], i32 [%x12], i32 [%x13]) -> f64 [%f10] + +; Arguments on stack where not necessary + sig3 = signature(f64 [%f10], i32 [0], i32 [4]) -> f64 [%f10] +; check: sig3 = signature(f64 [%f10], i32 [0], i32 [4]) -> f64 [%f10] + +; Stack argument before register argument + sig4 = signature(f32 [72], i32 [%x10]) +; check: sig4 = signature(f32 [72], i32 [%x10]) + +; Return value on stack + sig5 = signature() -> f32 [0] +; check: sig5 = signature() -> f32 [0] + +; function + signature + fn15 = function bar(i32 [%x10]) -> b1 [%x10] +; check: sig6 = signature(i32 [%x10]) -> b1 [%x10] +; nextln: fn0 = sig6 bar + +ebb0(v0: i32): + return_reg v0 +} \ No newline at end of file diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index b83f8c0b38..6041039513 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -10,7 +10,7 @@ use std::{u16, u32}; use std::mem; use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, StackSlotData, JumpTable, JumpTableData, Signature, ArgumentType, ArgumentExtension, ExtFuncData, SigRef, - FuncRef, ValueLoc}; + FuncRef, ValueLoc, ArgumentLoc}; use cretonne::ir::types::VOID; use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::ir::entities::AnyEntity; @@ -445,6 +445,19 @@ impl<'a> Parser<'a> { } } + // Match and consume a u32 immediate. + // This is used for stack argument byte offsets. + fn match_uimm32(&mut self, err_msg: &str) -> Result { + if let Some(Token::Integer(text)) = self.token() { + self.consume(); + // Lexer just gives us raw text that looks like an integer. + // Parse it as a u32 to check for overflow and other issues. + text.parse().map_err(|_| self.error("expected u32 decimal immediate")) + } else { + err!(self.loc, err_msg) + } + } + // Match and consume an Ieee32 immediate. fn match_ieee32(&mut self, err_msg: &str) -> Result { if let Some(Token::Float(text)) = self.token() { @@ -596,7 +609,7 @@ impl<'a> Parser<'a> { self.comments.clear(); self.gather_comments(AnyEntity::Function); - let (location, name, sig) = self.parse_function_spec()?; + let (location, name, sig) = self.parse_function_spec(unique_isa)?; let mut ctx = Context::new(Function::with_name_signature(name, sig), unique_isa); // function ::= function-spec * "{" preamble function-body "}" @@ -630,7 +643,9 @@ impl<'a> Parser<'a> { // // function-spec ::= * "function" name signature // - fn parse_function_spec(&mut self) -> Result<(Location, FunctionName, Signature)> { + fn parse_function_spec(&mut self, + unique_isa: Option<&TargetIsa>) + -> Result<(Location, FunctionName, Signature)> { self.match_identifier("function", "expected 'function'")?; let location = self.loc; @@ -638,7 +653,7 @@ impl<'a> Parser<'a> { let name = self.parse_function_name()?; // function-spec ::= "function" name * signature - let sig = self.parse_signature()?; + let sig = self.parse_signature(unique_isa)?; Ok((location, name, sig)) } @@ -661,17 +676,21 @@ impl<'a> Parser<'a> { // // signature ::= * "(" [arglist] ")" ["->" retlist] [call_conv] // - fn parse_signature(&mut self) -> Result { + fn parse_signature(&mut self, unique_isa: Option<&TargetIsa>) -> Result { let mut sig = Signature::new(); self.match_token(Token::LPar, "expected function signature: ( args... )")?; // signature ::= "(" * [arglist] ")" ["->" retlist] [call_conv] if self.token() != Some(Token::RPar) { - sig.argument_types = self.parse_argument_list()?; + sig.argument_types = self.parse_argument_list(unique_isa)?; } self.match_token(Token::RPar, "expected ')' after function arguments")?; if self.optional(Token::Arrow) { - sig.return_types = self.parse_argument_list()?; + sig.return_types = self.parse_argument_list(unique_isa)?; + } + + if sig.argument_types.iter().all(|a| a.location.is_assigned()) { + sig.compute_argument_bytes(); } // TBD: calling convention. @@ -683,27 +702,27 @@ impl<'a> Parser<'a> { // // arglist ::= * arg { "," arg } // - fn parse_argument_list(&mut self) -> Result> { + fn parse_argument_list(&mut self, unique_isa: Option<&TargetIsa>) -> Result> { let mut list = Vec::new(); // arglist ::= * arg { "," arg } - list.push(self.parse_argument_type()?); + list.push(self.parse_argument_type(unique_isa)?); // arglist ::= arg * { "," arg } while self.optional(Token::Comma) { // arglist ::= arg { "," * arg } - list.push(self.parse_argument_type()?); + list.push(self.parse_argument_type(unique_isa)?); } Ok(list) } // Parse a single argument type with flags. - fn parse_argument_type(&mut self) -> Result { - // arg ::= * type { flag } + fn parse_argument_type(&mut self, unique_isa: Option<&TargetIsa>) -> Result { + // arg ::= * type { flag } [ argumentloc ] let mut arg = ArgumentType::new(self.match_type("expected argument type")?); - // arg ::= type * { flag } + // arg ::= type * { flag } [ argumentloc ] while let Some(Token::Identifier(s)) = self.token() { match s { "uext" => arg.extension = ArgumentExtension::Uext, @@ -714,9 +733,50 @@ impl<'a> Parser<'a> { self.consume(); } + // arg ::= type { flag } * [ argumentloc ] + arg.location = self.parse_argument_location(unique_isa)?; + Ok(arg) } + // Parse an argument location specifier; either a register or a byte offset into the stack. + fn parse_argument_location(&mut self, unique_isa: Option<&TargetIsa>) -> Result { + // argumentloc ::= '[' regname | uimm32 ']' + if self.optional(Token::LBracket) { + let result = match self.token() { + Some(Token::Name(name)) => { + self.consume(); + if let Some(isa) = unique_isa { + isa.register_info() + .parse_regunit(name) + .map(ArgumentLoc::Reg) + .ok_or(self.error("invalid register name")) + } else { + // We are unable to parse the register without a TargetISA, so we quietly + // ignore it. + Ok(ArgumentLoc::Unassigned) + } + } + Some(Token::Integer(_)) => { + let offset = self.match_uimm32("expected stack argument byte offset")?; + Ok(ArgumentLoc::Stack(offset)) + } + Some(Token::Minus) => { + self.consume(); + Ok(ArgumentLoc::Unassigned) + } + _ => err!(self.loc, "expected argument location"), + }; + + self.match_token(Token::RBracket, + "expected ']' to end argument location annotation")?; + + result + } else { + Ok(ArgumentLoc::Unassigned) + } + } + // Parse the function preamble. // // preamble ::= * { preamble-decl } @@ -736,7 +796,7 @@ impl<'a> Parser<'a> { } Some(Token::SigRef(..)) => { self.gather_comments(ctx.function.dfg.signatures.next_key()); - self.parse_signature_decl() + self.parse_signature_decl(ctx.unique_isa) .and_then(|(num, dat)| ctx.add_sig(num, dat, &self.loc)) } Some(Token::FuncRef(..)) => { @@ -781,11 +841,11 @@ impl<'a> Parser<'a> { // // signature-decl ::= SigRef(sigref) "=" "signature" signature // - fn parse_signature_decl(&mut self) -> Result<(u32, Signature)> { + fn parse_signature_decl(&mut self, unique_isa: Option<&TargetIsa>) -> Result<(u32, Signature)> { let number = self.match_sig("expected signature number: sig«n»")?; self.match_token(Token::Equal, "expected '=' in signature decl")?; self.match_identifier("signature", "expected 'signature'")?; - let data = self.parse_signature()?; + let data = self.parse_signature(unique_isa)?; Ok((number, data)) } @@ -805,7 +865,7 @@ impl<'a> Parser<'a> { let data = match self.token() { Some(Token::Identifier("function")) => { - let (loc, name, sig) = self.parse_function_spec()?; + let (loc, name, sig) = self.parse_function_spec(ctx.unique_isa)?; let sigref = ctx.function.dfg.signatures.push(sig); ctx.map.def_entity(sigref.into(), &loc).expect("duplicate SigRef entities created"); ExtFuncData { @@ -1523,33 +1583,33 @@ mod tests { #[test] fn argument_type() { let mut p = Parser::new("i32 sext"); - let arg = p.parse_argument_type().unwrap(); + let arg = p.parse_argument_type(None).unwrap(); assert_eq!(arg.value_type, types::I32); assert_eq!(arg.extension, ArgumentExtension::Sext); assert_eq!(arg.inreg, false); - let Error { location, message } = p.parse_argument_type().unwrap_err(); + let Error { location, message } = p.parse_argument_type(None).unwrap_err(); assert_eq!(location.line_number, 1); assert_eq!(message, "expected argument type"); } #[test] fn signature() { - let sig = Parser::new("()").parse_signature().unwrap(); + let sig = Parser::new("()").parse_signature(None).unwrap(); assert_eq!(sig.argument_types.len(), 0); assert_eq!(sig.return_types.len(), 0); let sig2 = Parser::new("(i8 inreg uext, f32, f64) -> i32 sext, f64") - .parse_signature() + .parse_signature(None) .unwrap(); assert_eq!(sig2.to_string(), "(i8 uext inreg, f32, f64) -> i32 sext, f64"); // `void` is not recognized as a type by the lexer. It should not appear in files. - assert_eq!(Parser::new("() -> void").parse_signature().unwrap_err().to_string(), + assert_eq!(Parser::new("() -> void").parse_signature(None).unwrap_err().to_string(), "1: expected argument type"); - assert_eq!(Parser::new("i8 -> i8").parse_signature().unwrap_err().to_string(), + assert_eq!(Parser::new("i8 -> i8").parse_signature(None).unwrap_err().to_string(), "1: expected function signature: ( args... )"); - assert_eq!(Parser::new("(i8 -> i8").parse_signature().unwrap_err().to_string(), + assert_eq!(Parser::new("(i8 -> i8").parse_signature(None).unwrap_err().to_string(), "1: expected ')' after function arguments"); }