Skip to content

Latest commit

 

History

History
254 lines (185 loc) · 7.77 KB

TrilLanguageReference.md

File metadata and controls

254 lines (185 loc) · 7.77 KB

Tril Language Reference

In many ways, the Tril language mirrors the Testarossa Intermediate Language, Trees.

This language reference intends to document the places where special behaviour has been created in Tril to make writing test cases easier.

Basics

Tril is built out of two main components:

  1. A very permissive S-expression parser.
  2. An IlGenerator that walks the AST produced by said parser, and generates Trees.

Syntax

Tril represents Trees using S-expressions, with key-value properties to augment a particular node with more information.

  • (x (y) (z)) represents some x with y and z as children.

  • (x foo=bar baz=braz (y) (z) is the same tree as above, but where the node for x is augmented with two properties with values.

    Anything may be provided as a property for a node, however, unknown properties will be silently ignored.

Literals

  • Signed integer literals can be input directly, and will always be treated internally as a 64-bit integer.
  • Hexadecimal integer literals are supported as well, and are treated as 64-bit integers. Use a leading 0x.
  • Floating point numbers can be input by including a decimal point.

Comments

; starts a comment in Tril, and the comment proceeds to the end of a line.

Special Forms:

The key to Tril is the unlocking of extra behaviour using 'special forms', or atoms that represent certain behaviours in Testarossa.

Types

The Testarossa IL, and therefore Tril, deals with the following data types.

  • Int8
  • Int16
  • Int32
  • Int64
  • Address
  • Float
  • Double
  • NoType

Signedness is a property of operations, not the data itself.

In addition, there are vector types that are generated on demand. For example Vector128Int8 or Vector128Float can be generated during method compilation.

Methods

A whole method in Tril is wrapped in a method expression.

Properties

  • return Mandatory is the return type of the method.

  • args Optional is a square-bracketed list of arguments representing the types of the parameters, and the order in which they appear.

    eg. args=[Int32,Double,Float]

Block

In the Testarossa IL, all trees exist within the context of a basic block. In Tril, blocks must be children of a method, or they will not be recognized.

Properties

  • name Optional Blocks can be named in order to target them with branches.

Stores and loads

Currently the creation of new symbol references in Tril is not supported. However, store and load opcodes provide two options for where the store / load can come from, which can be specified with one of the following two properties:

  • parm can specify the parameter from which a load can come. Parameters are counted from zero. eg. (iload parm=2) loads the third parameter from the signature.
  • temp Stores to temps create new temporary variables that can later be referenced. eg. (istore temp="x" ...)

Branches

Branches evaluate a condition then either jump to a target, or falls through to the next block. The fallthrough block can be eiher implied, in which case it will be the next block textually, or it can be specified manually with the fallthrough property.

Properties

  • target Mandatory The name of the block a successful computation of the condition will continue executing in.
  • fallthrough Optional In some circumstances it is necessary to explicitly list the name of the fallthrough block of a branch to ensure the desired CFG is constructed. In addition to a block name, there are two special values that may be used here:
    • @none indicates no fallthrough edge need be generated: this can be the case for certain opcodes, ie

         (goto target="unconditionalTarget" fallthrough=@none)
      
    • @exit falls through to the exit block of the CFG. This can be useful for constructing invalid control flow in the case of test-cases.

Example

(method ...
   (block fallthrough="sub" name="start"
      (ificmpge target="add"
        ...) )
   (block name="sub"
      (ireturn
         ...) )
   (block name="add"
      (ireturn
        ... ) )

Commoning

Nodes can be given identifiers to allow creating commoned subtrees. To common a reference, on first computation annotate the node with the id="<some name>" property. Then, where commoning is desired, replace the node with (@id "<some name>")

(imul id="multiplyResult"
    ...)
(iadd
  (@id "multiplyResult")
  (@id "multiplyResult")

Vectors

Vector support in Tril is very preliminary, but present. Vector opcodes are formed by concatinating vector operation (such as vloadi) with any vector type, for example Vector128Double:

(vloadiVector128Double (aload parm=0))

####Properties

  • type Mandatory The data type being loaded or stored.

Calls

Call opcodes are supported with in Tril by providing extra annotation of the argument types and the function pointer to be invoked.

(icall address=0x1234 args=[Int32] ...)

####Properties

  • address Mandatory The address of the function to be invoked by the call opcode
  • args Optional The list of argument types passed to the call.

Examples

Incordec

Checked in as fvtest/tril/examples/incordec/incordec.tril

; This simple method takes as argument a pointer to a 32-bit integer. If the
; integer pointed to by the argument has a negative value, then the value
; decremented by 1 is returned. Otherwise (value is positive), the value
; incremented by 1 is returned.
;
; An equivalent C implementation:
;
; int incordec(int* parm0) {
;    if (*parm0 < 0) {
;     return *parm0 - (int)1.0;
;    } else {
;      int x = 1;
;      return *parm0 + x;
;    }
; }

(method name="incordec" return="Int32" args=["Address"]
   (block fallthrough="sub" name="start"     ; start:
      (ificmpge target="add"                 ; if (*parm0 >= 0) goto add;
         (iloadi offset=0 (aload parm=0) )
         (iconst 0) ) )
   (block name="sub"                         ; sub:
      (ireturn                               ; return *parm0 - 1;
         (isub
            (iloadi offset=0 (aload parm=0) )
            (d2i (dconst 1.0) ) ) ) )
   (block name="add"                         ; add:
      (istore temp="x" (iconst 1))           ; int x = 1;
      (ireturn                               ; return *parm0 + x;
         (iadd
            (iloadi offset=0 (aload parm=0) )
            (iload temp="x") ) ) ) )

Vector Support:

Vector addition of two input double vectors into a third output double vector. Hooked up as a test case in fvtest/compilertriltest/VectorTest.cpp.

(method return= NoType args=[Address,Address,Address]
  (block
     (vstoreiVector128Double offset=0
         (aload parm=0)
            (vaddVector128Double
                 (vloadiVector128Double (aload parm=1))
                 (vloadiVector128Double (aload parm=2))))
     (return)))