From 43b4f7f4e74b4c952cee122107f0a0317dcacd8f Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 22 Jan 2016 13:08:18 -0800 Subject: [PATCH] Expand on control flow and direct function calls. Define the syntax for function signatures. --- docs/cton_lexer.py | 2 +- docs/langref.rst | 142 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 131 insertions(+), 13 deletions(-) diff --git a/docs/cton_lexer.py b/docs/cton_lexer.py index 0df2e6208a..4c309d779b 100644 --- a/docs/cton_lexer.py +++ b/docs/cton_lexer.py @@ -28,7 +28,7 @@ class CretonneLexer(RegexLexer): # Reserved words. (keywords('function', 'entry'), Keyword), # Known attributes. - (keywords('align'), Name.Attribute), + (keywords('align', 'uext', 'sext', 'inreg'), Name.Attribute), # Well known value types. (r'\b(bool|i\d+|f32|f64)(x\d+)?\b', Keyword.Type), # v = value diff --git a/docs/langref.rst b/docs/langref.rst index 6a9bcc60eb..b3f8b14ea1 100644 --- a/docs/langref.rst +++ b/docs/langref.rst @@ -178,9 +178,27 @@ called a *lane*. The number of lanes must be a power of two in the range 2-256. Like the :type:`bool` type, a boolean vector cannot be stored in memory. +Pseudo-types +------------ + +These are not concrete types, but convenient names uses to refer to real types +in this reference. + +.. type:: iPtr + + A Pointer-sized integer. + + This is either :type:`i32`, or :type:`i64`, depending on whether the target + platform has 32-bit or 64-bit pointers. + Control flow ============ +Branches transfer control to a new EBB and provide values for the target EBB's +arguments, if it has any. Conditional branches only take the branch if their +condition is satisfied, otherwise execution continues at the following +instruction in the EBB. + .. inst:: br EBB(args...) Branch. @@ -190,6 +208,7 @@ Control flow EBB. :arg EBB: Destination extended basic block. + :arg args...: Zero or more arguments passed to EBB. :result: None. This is a terminator instruction. .. inst:: brz x, EBB(args...) @@ -201,6 +220,7 @@ Control flow :arg iN/bool x: Value to test. :arg EBB: Destination extended basic block. + :arg args...: Arguments passed to EBB. :result: None. .. inst:: brnz x, EBB(args...) @@ -212,15 +232,16 @@ Control flow :arg iN/bool x: Value to test. :arg EBB: Destination extended basic block. + :arg args...: Zero or more arguments passed to EBB. :result: None. .. inst:: br_table x, JT Jump table branch. - Use ``x`` as an index into the jump table ``JT``. If a jump table entry is - found, branch to the corresponding EBB. If no entry was found fall through - to the next instruction. + Use ``x`` as an unsigned index into the jump table ``JT``. If a jump table + entry is found, branch to the corresponding EBB. If no entry was found fall + through to the next instruction. Note that this branch instruction can't pass arguments to the targeted blocks. Split critical edges as needed to work around this. @@ -229,20 +250,31 @@ Control flow :arg JT: Jump table which was declared in the preample. :result: None. -.. inst:: return args... +.. inst:: JT = jump_table EBB0, EBB1, ..., EBBn - Return from function. + Declare a jump table in the :term:`function preample`. - Unconditionally transfer control to the calling function, passing the - provided return values. + This declares a jump table for use by the :inst:`br_table` indirect branch + instruction. Entries in the table are either EBB names, or ``0`` which + indicates an absent entry. - :arg args: Return values. The list of retur values must match the list if - return value types in the function signature. - :result: None. This is a terminator instruction. + The EBBs listed must belong to the current function, and they can't have + any arguments. + + :arg EBB0: Target EBB when ``x = 0``. + :arg EBB1: Target EBB when ``x = 1``. + :arg EBBn: Target EBB when ``x = n``. + :result: A jump table identifier. (Not an SSA value). + +Traps stop the program because something went wrong. The exact behavior depends +on the target instruction set architecture and operating system. There are +explicit trap instructions defined below, but some instructions may also cause +traps for certain input value. For example, :inst:`udiv` traps when the divisor +is zero. .. inst:: trap - Terminate execution. + Terminate execution unconditionally. :result: None. This is a terminator instruction. @@ -264,12 +296,98 @@ Control flow :arg iN/bool x: Value to test. :result: None. + Function calls ============== A function call needs a target function and a :term:`function signature`. The target function may be determined dynamically at runtime, but the signature -must be known when the function call is compiled. +must be known when the function call is compiled. The function signature +describes how to call the function, including arguments, return values, and the +calling convention: + +.. productionlist:: + signature : "(" [arglist] ")" ["->" retlist] [call_conv] + arglist : arg + : arglist "," arg + retlist : arglist + arg : type + : arg flag + flag : "uext" | "sext" | "inreg" + callconv : `string` + +Arguments and return values have flags whose meaning is mostly target +dependent. They make it possible to call native functions on the target +platform. When calling other Cretonne functions, the flags are not necessary. + +Functions that are called directly must be declared in the :term:`function +preample`: + +.. inst:: F = function NAME signature + + Declare a function so it can be called directly. + + :arg NAME: Name of the function, passed to the linker for resolution. + :arg signature: Function signature. See below. + :result F: A function identifier that can be used with :inst:`call`. + +.. inst:: a, b, ... = call F(args...) + + Direct function call. + + :arg F: Function identifier to call, declared by :inst:`function`. + :arg args...: Function arguments matching the signature of F. + :result a,b,...: Return values matching the signature of F. + +.. inst:: return args... + + Return from function. + + Unconditionally transfer control to the calling function, passing the + provided return values. + + :arg args: Return values. The list of return values must match the list of + return value types in the function signature. + :result: None. This is a terminator instruction. + +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): + brz v2, ebb2 + v3, v4 = call f1(v1, v2) + br ebb1(v2, v4) + + ebb2: + return v1 + } + +Indirect function calls use a signature declared in the preample. + +.. inst:: SIG = signature signature + + Declare a function signature for use with indirect calls. + + :arg signature: Function signature. See :token:`signature`. + :result SIG: A signature identifier. + +.. inst:: a, b, ... = call_indirect SIG, x(args...) + + Indirect function call. + + :arg SIG: A function signature identifier declared with :inst:`signature`. + :arg iPtr x: The address of the function to call. + :arg args...: Function arguments matching SIG. + :result a,b,...: Return values matching SIG. + +.. todo:: Define safe indirect function calls. + + The :inst:`call_indirect` instruction is dangerous to use in a sandboxed + environment since it is not easy to verify the callee address. + We need a table-driven indirect call instruction, similar to + :inst:`br_table`.