diff --git a/docs/cton_lexer.py b/docs/cton_lexer.py index 0139de337c..28a1be25b4 100644 --- a/docs/cton_lexer.py +++ b/docs/cton_lexer.py @@ -26,7 +26,7 @@ class CretonneLexer(RegexLexer): (r'[-+]?(\d+\.\d+([eE]\d+)?|[sq]NaN|Inf)', Number.Float), (r'[-+]?\d+', Number.Integer), # Reserved words. - (keywords('function', 'entry'), Keyword), + (keywords('function'), Keyword), # Known attributes. (keywords('align', 'aligntrap', 'uext', 'sext', 'inreg'), Name.Attribute), # Well known value types. diff --git a/docs/example.cton b/docs/example.cton index 190d3a25fd..cdfc61bf4b 100644 --- a/docs/example.cton +++ b/docs/example.cton @@ -1,7 +1,7 @@ function average(i32, i32) -> f32 { ss1 = stack_slot 8, align 4 ; Stack slot for ``sum``. -entry ebb1(v1: i32, v2: i32): +ebb1(v1: i32, v2: i32): v3 = f64const 0x0.0 stack_store v3, ss1 brz v2, ebb3 ; Handle count == 0. diff --git a/docs/langref.rst b/docs/langref.rst index c6e7b3ced6..848d140db8 100644 --- a/docs/langref.rst +++ b/docs/langref.rst @@ -41,9 +41,9 @@ that can be referenced inside the function. In the example above, the preamble declares a single local variable, ``ss1``. After the preamble follows the :term:`function body` which consists of -:term:`extended basic block`\s, one of which is marked as the :term:`entry -block`. Every EBB ends with a :term:`terminator instruction`, so execution can -never fall through to the next EBB without an explicit branch. +:term:`extended basic block`\s, the first of which is the :term:`entry block`. +Every EBB ends with a :term:`terminator instruction`, so execution can never +fall through to the next EBB without an explicit branch. A ``.cton`` file consists of a sequence of independent function definitions: @@ -395,7 +395,7 @@ This simple example illustrates direct function calls and signatures:: function gcd(i32 uext, i32 uext) -> i32 uext "C" { f1 = function divmod(i32 uext, i32 uext) -> i32 uext, i32 uext - entry ebb1(v1: i32, v2: i32): + ebb1(v1: i32, v2: i32): brz v2, ebb2 v3, v4 = call f1(v1, v2) br ebb1(v2, v4) @@ -625,7 +625,7 @@ A small example using heaps:: function vdup(i32, i32) { h1 = heap "main" - entry ebb1(v1: i32, v2: i32): + ebb1(v1: i32, v2: i32): v3 = heap_load.i32x4 h1, v1, 0 v4 = heap_addr h1, v2, 32 ; Shared range check for two stores. store v3, v4, 0 @@ -878,9 +878,9 @@ Glossary entry block The :term:`EBB` that is executed first in a function. Currently, a - Cretonne function must have exactly one entry block. The types of the - entry block arguments must match the types of arguments in the function - signature. + Cretonne function must have exactly one entry block which must be the + first block in the function. The types of the entry block arguments must + match the types of arguments in the function signature. stack slot A fixed size memory allocation in the current function's activation diff --git a/src/libcretonne/cfg.rs b/src/libcretonne/cfg.rs index 970af69afd..964a07a572 100644 --- a/src/libcretonne/cfg.rs +++ b/src/libcretonne/cfg.rs @@ -104,11 +104,8 @@ impl ControlFlowGraph { &self.data[ebb].successors } - pub fn postorder_ebbs(&self) -> Vec { - if self.len() < 1 { - return Vec::new(); - } - let mut stack_a = vec![Ebb::with_number(0).unwrap()]; + pub fn postorder_ebbs(&self, entry: Ebb) -> Vec { + let mut stack_a = vec![entry]; let mut stack_b = Vec::new(); while stack_a.len() > 0 { let cur = stack_a.pop().unwrap(); @@ -282,7 +279,7 @@ mod tests { func.layout.append_inst(jmp_ebb2_ebb5, ebb2); let cfg = ControlFlowGraph::new(&func); - assert_eq!(cfg.postorder_ebbs(), + assert_eq!(cfg.postorder_ebbs(func.layout.entry_block().unwrap()), vec![ebb0, ebb2, ebb5, ebb4, ebb1, ebb3]); } @@ -309,6 +306,7 @@ mod tests { func.layout.append_inst(jmp_ebb2_ebb3, ebb2); let cfg = ControlFlowGraph::new(&func); - assert_eq!(cfg.postorder_ebbs(), vec![ebb0, ebb1, ebb2, ebb3]); + assert_eq!(cfg.postorder_ebbs(func.layout.entry_block().unwrap()), + vec![ebb0, ebb1, ebb2, ebb3]); } } diff --git a/src/libcretonne/ir/layout.rs b/src/libcretonne/ir/layout.rs index a01d49ef53..af21ee5234 100644 --- a/src/libcretonne/ir/layout.rs +++ b/src/libcretonne/ir/layout.rs @@ -108,6 +108,12 @@ impl Layout { next: self.first_ebb, } } + + /// Get the function's entry block. + /// This is simply the first EBB in the layout order. + pub fn entry_block(&self) -> Option { + self.first_ebb + } } #[derive(Clone, Debug, Default)] @@ -414,8 +420,11 @@ mod tests { let e0 = Ebb::new(0); let e1 = Ebb::new(1); + assert_eq!(layout.entry_block(), None); layout.append_ebb(e0); + assert_eq!(layout.entry_block(), Some(e0)); layout.append_ebb(e1); + assert_eq!(layout.entry_block(), Some(e0)); let i0 = Inst::new(0); let i1 = Inst::new(1); diff --git a/src/libcretonne/ir/mod.rs b/src/libcretonne/ir/mod.rs index fb93e9ec99..0d7e9da3a4 100644 --- a/src/libcretonne/ir/mod.rs +++ b/src/libcretonne/ir/mod.rs @@ -10,7 +10,7 @@ pub mod layout; use ir::types::{FunctionName, Signature}; use entity_map::EntityRef; -use ir::entities::{Ebb, NO_EBB, StackSlot}; +use ir::entities::StackSlot; use ir::dfg::DataFlowGraph; use ir::layout::Layout; use std::fmt::{self, Debug, Display, Formatter}; @@ -24,9 +24,6 @@ pub struct Function { /// Signature of this function. signature: Signature, - /// The entry block. - pub entry_block: Ebb, - /// Stack slots allocated in this function. stack_slots: Vec, @@ -43,7 +40,6 @@ impl Function { Function { name: name, signature: sig, - entry_block: NO_EBB, stack_slots: Vec::new(), dfg: DataFlowGraph::new(), layout: Layout::new(), diff --git a/src/libreader/lexer.rs b/src/libreader/lexer.rs index 3803260c05..61dd7feb9b 100644 --- a/src/libreader/lexer.rs +++ b/src/libreader/lexer.rs @@ -32,7 +32,6 @@ pub enum Token<'a> { Equal, // '=' Arrow, // '->' Function, // 'function' - Entry, // 'entry' Float(&'a str), // Floating point immediate Integer(&'a str), // Integer immediate Type(types::Type), // i32, f32, b32x4, ... @@ -270,7 +269,6 @@ impl<'a> Lexer<'a> { fn keyword(text: &str) -> Option> { match text { "function" => Some(Token::Function), - "entry" => Some(Token::Entry), _ => None, } } @@ -444,7 +442,7 @@ mod tests { #[test] fn lex_identifiers() { - let mut lex = Lexer::new("v0 v00 vx01 ebb1234567890 ebb5234567890 entry v1x vx1 vxvx4 \ + let mut lex = Lexer::new("v0 v00 vx01 ebb1234567890 ebb5234567890 v1x vx1 vxvx4 \ function0 function b1 i32x4 f32x5"); assert_eq!(lex.next(), token(Token::Value(Value::direct_with_number(0).unwrap()), 1)); @@ -453,7 +451,6 @@ mod tests { assert_eq!(lex.next(), token(Token::Ebb(Ebb::with_number(1234567890).unwrap()), 1)); assert_eq!(lex.next(), token(Token::Identifier("ebb5234567890"), 1)); - assert_eq!(lex.next(), token(Token::Entry, 1)); assert_eq!(lex.next(), token(Token::Identifier("v1x"), 1)); assert_eq!(lex.next(), token(Token::Value(Value::table_with_number(1).unwrap()), 1)); diff --git a/src/libreader/parser.rs b/src/libreader/parser.rs index e333c0d3e9..a961ccdf60 100644 --- a/src/libreader/parser.rs +++ b/src/libreader/parser.rs @@ -15,7 +15,7 @@ use cretonne::ir::types::{Type, VOID, FunctionName, Signature, ArgumentType, Arg use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::ir::entities::*; use cretonne::ir::instructions::{Opcode, InstructionFormat, InstructionData, VariableArgs, - JumpData, BranchData, ReturnData}; + JumpData, BranchData, ReturnData}; use cretonne::ir::{Function, StackSlotData}; pub use lexer::Location; @@ -578,22 +578,14 @@ impl<'a> Parser<'a> { // Parse an extended basic block, add contents to `ctx`. // // extended-basic-block ::= * ebb-header { instruction } - // ebb-header ::= ["entry"] Ebb(ebb) [ebb-args] ":" + // ebb-header ::= Ebb(ebb) [ebb-args] ":" // fn parse_extended_basic_block(&mut self, ctx: &mut Context) -> Result<()> { - let is_entry = self.optional(Token::Entry); let ebb_num = try!(self.match_ebb("expected EBB header")); let ebb = try!(ctx.add_ebb(ebb_num, &self.loc)); - if is_entry { - if ctx.function.entry_block != NO_EBB { - return err!(self.loc, "multiple entry blocks in function"); - } - ctx.function.entry_block = ebb; - } - if !self.optional(Token::Colon) { - // ebb-header ::= ["entry"] Ebb(ebb) [ * ebb-args ] ":" + // ebb-header ::= Ebb(ebb) [ * ebb-args ] ":" try!(self.parse_ebb_args(ctx, ebb)); try!(self.match_token(Token::Colon, "expected ':' after EBB arguments")); }