Move entry_block() into Layout.

The single entry block in a function is simply the first block in the layout.

Remove the 'entry' keyword from the textual IL, the lexer and parser.
This commit is contained in:
Jakob Stoklund Olesen
2016-07-22 10:06:51 -07:00
parent 27cb00ef42
commit 8296e92ddc
8 changed files with 29 additions and 37 deletions

View File

@@ -26,7 +26,7 @@ class CretonneLexer(RegexLexer):
(r'[-+]?(\d+\.\d+([eE]\d+)?|[sq]NaN|Inf)', Number.Float), (r'[-+]?(\d+\.\d+([eE]\d+)?|[sq]NaN|Inf)', Number.Float),
(r'[-+]?\d+', Number.Integer), (r'[-+]?\d+', Number.Integer),
# Reserved words. # Reserved words.
(keywords('function', 'entry'), Keyword), (keywords('function'), Keyword),
# Known attributes. # Known attributes.
(keywords('align', 'aligntrap', 'uext', 'sext', 'inreg'), Name.Attribute), (keywords('align', 'aligntrap', 'uext', 'sext', 'inreg'), Name.Attribute),
# Well known value types. # Well known value types.

View File

@@ -1,7 +1,7 @@
function average(i32, i32) -> f32 { function average(i32, i32) -> f32 {
ss1 = stack_slot 8, align 4 ; Stack slot for ``sum``. 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 v3 = f64const 0x0.0
stack_store v3, ss1 stack_store v3, ss1
brz v2, ebb3 ; Handle count == 0. brz v2, ebb3 ; Handle count == 0.

View File

@@ -41,9 +41,9 @@ that can be referenced inside the function. In the example above, the preamble
declares a single local variable, ``ss1``. declares a single local variable, ``ss1``.
After the preamble follows the :term:`function body` which consists of 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 :term:`extended basic block`\s, the first of which is the :term:`entry block`.
block`. Every EBB ends with a :term:`terminator instruction`, so execution can Every EBB ends with a :term:`terminator instruction`, so execution can never
never fall through to the next EBB without an explicit branch. fall through to the next EBB without an explicit branch.
A ``.cton`` file consists of a sequence of independent function definitions: 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" { function gcd(i32 uext, i32 uext) -> i32 uext "C" {
f1 = function divmod(i32 uext, i32 uext) -> i32 uext, i32 uext 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 brz v2, ebb2
v3, v4 = call f1(v1, v2) v3, v4 = call f1(v1, v2)
br ebb1(v2, v4) br ebb1(v2, v4)
@@ -625,7 +625,7 @@ A small example using heaps::
function vdup(i32, i32) { function vdup(i32, i32) {
h1 = heap "main" h1 = heap "main"
entry ebb1(v1: i32, v2: i32): ebb1(v1: i32, v2: i32):
v3 = heap_load.i32x4 h1, v1, 0 v3 = heap_load.i32x4 h1, v1, 0
v4 = heap_addr h1, v2, 32 ; Shared range check for two stores. v4 = heap_addr h1, v2, 32 ; Shared range check for two stores.
store v3, v4, 0 store v3, v4, 0
@@ -878,9 +878,9 @@ Glossary
entry block entry block
The :term:`EBB` that is executed first in a function. Currently, a The :term:`EBB` that is executed first in a function. Currently, a
Cretonne function must have exactly one entry block. The types of the Cretonne function must have exactly one entry block which must be the
entry block arguments must match the types of arguments in the function first block in the function. The types of the entry block arguments must
signature. match the types of arguments in the function signature.
stack slot stack slot
A fixed size memory allocation in the current function's activation A fixed size memory allocation in the current function's activation

View File

@@ -104,11 +104,8 @@ impl ControlFlowGraph {
&self.data[ebb].successors &self.data[ebb].successors
} }
pub fn postorder_ebbs(&self) -> Vec<Ebb> { pub fn postorder_ebbs(&self, entry: Ebb) -> Vec<Ebb> {
if self.len() < 1 { let mut stack_a = vec![entry];
return Vec::new();
}
let mut stack_a = vec![Ebb::with_number(0).unwrap()];
let mut stack_b = Vec::new(); let mut stack_b = Vec::new();
while stack_a.len() > 0 { while stack_a.len() > 0 {
let cur = stack_a.pop().unwrap(); let cur = stack_a.pop().unwrap();
@@ -282,7 +279,7 @@ mod tests {
func.layout.append_inst(jmp_ebb2_ebb5, ebb2); func.layout.append_inst(jmp_ebb2_ebb5, ebb2);
let cfg = ControlFlowGraph::new(&func); 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]); vec![ebb0, ebb2, ebb5, ebb4, ebb1, ebb3]);
} }
@@ -309,6 +306,7 @@ mod tests {
func.layout.append_inst(jmp_ebb2_ebb3, ebb2); func.layout.append_inst(jmp_ebb2_ebb3, ebb2);
let cfg = ControlFlowGraph::new(&func); 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]);
} }
} }

View File

@@ -108,6 +108,12 @@ impl Layout {
next: self.first_ebb, 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<Ebb> {
self.first_ebb
}
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@@ -414,8 +420,11 @@ mod tests {
let e0 = Ebb::new(0); let e0 = Ebb::new(0);
let e1 = Ebb::new(1); let e1 = Ebb::new(1);
assert_eq!(layout.entry_block(), None);
layout.append_ebb(e0); layout.append_ebb(e0);
assert_eq!(layout.entry_block(), Some(e0));
layout.append_ebb(e1); layout.append_ebb(e1);
assert_eq!(layout.entry_block(), Some(e0));
let i0 = Inst::new(0); let i0 = Inst::new(0);
let i1 = Inst::new(1); let i1 = Inst::new(1);

View File

@@ -10,7 +10,7 @@ pub mod layout;
use ir::types::{FunctionName, Signature}; use ir::types::{FunctionName, Signature};
use entity_map::EntityRef; use entity_map::EntityRef;
use ir::entities::{Ebb, NO_EBB, StackSlot}; use ir::entities::StackSlot;
use ir::dfg::DataFlowGraph; use ir::dfg::DataFlowGraph;
use ir::layout::Layout; use ir::layout::Layout;
use std::fmt::{self, Debug, Display, Formatter}; use std::fmt::{self, Debug, Display, Formatter};
@@ -24,9 +24,6 @@ pub struct Function {
/// Signature of this function. /// Signature of this function.
signature: Signature, signature: Signature,
/// The entry block.
pub entry_block: Ebb,
/// Stack slots allocated in this function. /// Stack slots allocated in this function.
stack_slots: Vec<StackSlotData>, stack_slots: Vec<StackSlotData>,
@@ -43,7 +40,6 @@ impl Function {
Function { Function {
name: name, name: name,
signature: sig, signature: sig,
entry_block: NO_EBB,
stack_slots: Vec::new(), stack_slots: Vec::new(),
dfg: DataFlowGraph::new(), dfg: DataFlowGraph::new(),
layout: Layout::new(), layout: Layout::new(),

View File

@@ -32,7 +32,6 @@ pub enum Token<'a> {
Equal, // '=' Equal, // '='
Arrow, // '->' Arrow, // '->'
Function, // 'function' Function, // 'function'
Entry, // 'entry'
Float(&'a str), // Floating point immediate Float(&'a str), // Floating point immediate
Integer(&'a str), // Integer immediate Integer(&'a str), // Integer immediate
Type(types::Type), // i32, f32, b32x4, ... Type(types::Type), // i32, f32, b32x4, ...
@@ -270,7 +269,6 @@ impl<'a> Lexer<'a> {
fn keyword(text: &str) -> Option<Token<'a>> { fn keyword(text: &str) -> Option<Token<'a>> {
match text { match text {
"function" => Some(Token::Function), "function" => Some(Token::Function),
"entry" => Some(Token::Entry),
_ => None, _ => None,
} }
} }
@@ -444,7 +442,7 @@ mod tests {
#[test] #[test]
fn lex_identifiers() { 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"); function0 function b1 i32x4 f32x5");
assert_eq!(lex.next(), assert_eq!(lex.next(),
token(Token::Value(Value::direct_with_number(0).unwrap()), 1)); token(Token::Value(Value::direct_with_number(0).unwrap()), 1));
@@ -453,7 +451,6 @@ mod tests {
assert_eq!(lex.next(), assert_eq!(lex.next(),
token(Token::Ebb(Ebb::with_number(1234567890).unwrap()), 1)); token(Token::Ebb(Ebb::with_number(1234567890).unwrap()), 1));
assert_eq!(lex.next(), token(Token::Identifier("ebb5234567890"), 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::Identifier("v1x"), 1));
assert_eq!(lex.next(), assert_eq!(lex.next(),
token(Token::Value(Value::table_with_number(1).unwrap()), 1)); token(Token::Value(Value::table_with_number(1).unwrap()), 1));

View File

@@ -578,22 +578,14 @@ impl<'a> Parser<'a> {
// Parse an extended basic block, add contents to `ctx`. // Parse an extended basic block, add contents to `ctx`.
// //
// extended-basic-block ::= * ebb-header { instruction } // 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<()> { 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_num = try!(self.match_ebb("expected EBB header"));
let ebb = try!(ctx.add_ebb(ebb_num, &self.loc)); 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) { 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.parse_ebb_args(ctx, ebb));
try!(self.match_token(Token::Colon, "expected ':' after EBB arguments")); try!(self.match_token(Token::Colon, "expected ':' after EBB arguments"));
} }