Table of Contents

About

BL-MIR (Biscuit Language Middle Intermediate Representation) is a simplified representation of the Biscuit Language created from AST. It is located between AST and LLVM-IR.

MIR Interpreter

BL Compiler has integrated interpreter for MIR.

  • Default execution stack size is 2MB.
  • Stack allocations are 8 byte aligned.

Assert function example

assert :: fn (cond: bool) {
  if !cond {
    unreachable;
  }
};
@assert  : fn(bool) void : {
%entry_1866:
    %1867              bool arg $0
    %1868              void decl cond : bool = %1867
    %1872             *bool declref cond
    %1998              bool load %1872
    %1873              bool unop !%1998
    %1874              void br %1873 ? %if_then_1869 : %if_else_1870

%if_then_1869:
    %1875              void unreachable 
    %1876              void br %if_cont_1871

%if_else_1870:
    %1877              void br %if_cont_1871

%if_cont_1871:
    %1999              void ret 
} // comptime 
define void @assert(i1) local_unnamed_addr #0 {
entry:
  br i1 %0, label %if_cont, label %if_then

if_then:                                          ; preds = %entry
  tail call void @llvm.debugtrap()
  br label %if_cont

if_cont:                                          ; preds = %entry, %if_then
  ret void
}

Stack manipulation

  • Interpreter is used for evaluation of compile-time known expressions during analyze process.
  • Compile-time known values are not pushed on the stack.

Example function:

assert :: fn (cond: bool) {
  if (!cond) {
    unreachable;
  }
};

main :: fn () s32 {
  v :: 10;
  assert(v == 10);
  return 0;
};

Stack operation produced during execution of the main function:

executing 'main' in compile time...
     -             Terminal  PUSH RA
    15            InstrCall  PUSH RA
    27             InstrArg  PUSH    (1B, 0x7fbd02347078) bool
    28         InstrDeclVar  POP     (1B, 0x7fbd0234707f) bool
    28         InstrDeclVar  PUSH    (1B, 0x7fbd02347078) bool
    39            InstrLoad  PUSH    (1B, 0x7fbd02347080) bool
    33            InstrUnop  POP     (1B, 0x7fbd02347087) bool
    33            InstrUnop  PUSH    (1B, 0x7fbd02347080) bool
    34          InstrCondBr  POP     (1B, 0x7fbd02347087) bool
    40             InstrRet  POP RA
    17             InstrRet  POP RA
execution finished with state: 0

Function

@<name> <T> [flags] { 
  [entry block]
}

Block

Basic block representation.

<name>: 
  ...
  <terminal instruction>

Instructions

const

Constant values are known in compile time.

<T> const <value> // yields constant value of the type T

decl

Variable declaration:

void decl <name> : <T> = <init value> // yields void 

Stack operations:

stack op data description
PUSH - storage for the variable

Constant declaration:

void decl <name> : <T> : <init value> // yields void 

declmember

Declare member of the structured type.

void declmember <name> : <T> // yields void 

declvariant

Declare enum variant.

void declvariant <name> : <T> : <value> // yields void 

declref

Reference to some declaration. This instruction is 'noop'. Symbol lookup is done here during analyze pass, when symbol is not found error is generated.

<*T> declref <name> // yields pointer to found declaration

load

Push pointed value on the stack.

<T> load <ptr> // yields T loaded from ptr

Stack operations:

stack op data description
POP ptr pointer to source
PUSH value value loaded from source

store

Store value from source to destination address.

void store <src> -> <dest ptr> // yields void

Stack operations:

stack op data description
POP dest ptr pointer to destination
POP src ptr value

arg

Load argument of the current function on the stack.

<T> arg $<arg number> // yields T

Stack operations:

stack op data description
PUSH arg fn argument

call

Call some function. This instruction will create new stack frame and switch control to the callee.

Compile-time known arguments are passed by const value otherwise call instruction expects that all arguments are already pushed on the stack in reverse order.

Stack operations:

stack op data description
PUSH RA pc, call ptr create new frame stack (push program counter and call instruction pointer)

ret

Return value from the function and return control to the caller. This instruction terminates current basic block.

This instruction also clean up all argumets pushed on the stack and push return value if there is one and if it is used.

void ret [value] // yields void

Stack operations:

stack op data description
POP RA - rollback the stack to return address
POP arg 1 clenup fn argument
POP arg 2 clenup fn argument
POP arg 3 clenup fn argument
PUSH value push call result value if there is one

br

Breaks to the basic block. This instruction terminates current basic block.

void br <block> // yields void

br (conditional)

Breaks into then block if the condition is true. This instruction terminates current basic block.

void br <cont> ? <then_block> : <else_block> // yields void

Stack operations:

stack op data description
POP condition checked condition

unreachable

Abort execution when this instruction is reached.

binop

Binary operation.

<T> binop <lhs> <+|-|*|/|%> <rhs> // yields result value of type T

Stack operations:

stack op data description
POP lhs left-hand side of operation
POP rhs right-hand side of operation
PUSH result result value of the operation

unop

Unary operation.

<T> unop <+|-|*|&> <value> // yields result value of type T

Stack operations:

stack op data description
POP value  
PUSH result result value of the operation

elemptr

Evaluates address of the array element and push it on the stack. Input array pointer can also be a pointer to slice.

<*T> elemptr <[arr ptr|slice ptr]>[<index>] // yields result address *T (elem type)

Stack operations:

stack op data description
POP index  
PUSH elem ptr Address of the array element

memberptr

Evaluates address of member of the structured type via '.' operator.

<*T> memberptr <target ptr>.<member name|order> // yields result address *T (member type)

Stack operations:

stack op data description
POP target ptr  
PUSH member ptr Address of the member

addrof

Evaluates address of the variable.

<*T> addrof <target> // yields result address *T

Getting address of variable:

stack op data description
PUSH var ptr pointer to allocated variable

Skipped when address has been pushed by previous instruction (ex.: 'elemptr').

bitcast

Produce bit casting from one type to other. Bit cast just change type of pushed value. No stack operations are produced.

<T> bitcast <target> // yields value with casted type

sext

Signed-extend cast.

<T> sext <target> // yields value with casted type

Stack operations:

stack op data description
POP target  
PUSH result result with new type

zext

Zero-extend cast.

<T> zext <target> // yields value with casted type

Stack operations:

stack op data description
POP target  
PUSH resutlt result with new type

trunc

Truncates target to destination type 'T'.

<T> trunc <target> // yields value with casted type

Stack operations:

stack op data description
POP target  
PUSH result result with new type

fptosi

Floating point to signed integer cast.

<T> fptosi <target> // yields value with casted type

fptoui

Floating point to unsigned integer cast.

<T> fptoui <target> // yields value with casted type

ptrtoint

Pointer to integer cast. This cast is noop cast when T has same size as type of the target.

<T> ptrtoint <target> // yields value with casted type

inttoptr

Integer to pointer cast. This cast is noop cast when T has same size as type of the target.

<T> inttoptr <target> // yields value with casted type

fpext

Floating point extend cast.

<T> fpext <target> // yields value with casted type

Stack operations:

stack op data description
POP target  
PUSH resutlt result with new type

fptrunc

Truncates floating point target to destination type 'T'.

<T> fptrunc <target> // yields value with casted type

Stack operations:

stack op data description
POP target  
PUSH result result with new type

sizeof

Determinates size of expresion or type in compile time.

usize sizeof <expr|type> // yields size of input in bytes

alignof

Determinates alignment of expresion or type in compile time.

usize alignof <expr|type> // yields alignment of input

typeinfo

Determinates TypeInfo related to expresion or type in compile time.

TypeInfo *typeinfo <expr|type> // yields pointer to TypeInfo element 

typekind

Determinates TypeKind related to expresion or type in compile time.

TypeKind typekind <expr|type> // yields TypeKind constant 

compound

Compound initializer is group of data, it can act like a contant value. Naked, non-contant compound initializer can produce temporary allocation.

<T> compound <T> {[val, ...]} // yields T

vargs

Builds vargs slice from input values. This instruction produce additional tmp variable allocation on the stack.

<*vargs> vargs <T> {[val, ...]} // yields pointer to vargs tmp

Stack operations:

stack op data description
POP val 1  
POP val 2  
POP val 3  
PUSH * vargs slice VArgs array slice pointer

phi

Yields value based on previous executed block. This instruction yields value associated to block which executed before owner block of this instruction.

<T> phi [<value>, <block name>] ... // yields value of type T 

Stack operations:

stack op data description
POP value Pop selected value
PUSH value Push selected value

toany

Convert any input value to Any value. This instruction produce temporary allocation on the stack.

<*Any> toany val // yields pointer to Any tmp

Stack operations:

stack op data description
POP val  
PUSH any ptr pointer to Any tmp

Author: Martin Dorazil

Created: 2019-10-15 Tue 09:46

Validate