Skip to content

RustamSubkhankulov/iris

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

96 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

iris

Intermediate Representation Internal Structure - SSA-like IR developed as an educational project

logo

Overview

IRIS is an example of IR that includes simple operations, separated into different dialects - arith, builtin and ctrlflow.

Dialect arith:

  • ADD, SUB, MUL, DIV - basic arithmetical operations;
  • CONST - operation generating a constant SSA value;
  • CAST - operation, casting values between different data types;
  • CMP - comparison operation, which takes predicate (EQ (equal), NEQ (not-equal), A (above), B (below), AE (above or equal), BE (below or equal)).

Dialect builtin:

  • PARAM - operation representing function's parameter;
  • COPY - operation that copies one SSA value into the new one.

Dialect ctrlflow:

  • CALL - routine call operation;
  • JUMP - unconditional jump;
  • JUMPC - conditional jump;
  • RETURN - return from the routine operation;
  • PHI - phi-function.

IRIS structure & examples

Here's an example of IRIS IR for a programm that calculates factorial of a number:

factorial:
  ^bb0 <start> <to bb1> :
      a0.ui32 builtin.param -> (v3,v5,v7)
      c1.ui32 arith.const (1) -> (v5,v8p)
      c2.ui32 arith.const (2) -> (v3)
  ^bb1 <from bb0> <to T:bb2 / F:bb3> :
      v3.b arith.cmp.b (a0 : ui32, c2 : ui32) -> (n4)
      n4 ctrlflow.jmpc (v3 : b)
  ^bb3 <from bb1> <to bb2> :
      v5.ui32 arith.sub (a0 : ui32, c1 : ui32) -> (v6)
      v6.ui32 ctrlflow.call @factorial (v5 : ui32) -> (v7)
      v7.ui32 arith.mul (a0 : ui32, v6 : ui32) -> (v8p)
  ^bb2 <from bb3 bb1> <final> :
      v8p.ui32 ctrlflow.phi (c1 : ui32, v7 : ui32) -> (n9)
      n9 ctrlflow.return (v8p : ui32)

Each operation is located in one of the basic blocks, and basic block is located in the region, which represent IR for a whole routine (function).

Function parameters are marked with literal a (a0, a1 etc.). Constant-generated SSA values are marked with literal c (c1, c2 etc.). Other SSA values are marked with literal v (v3, v4 etc.).

Operations that do not produce material result, for example, ctrlflow::jump, are marked with literal n for 'none', as its return value type is DataType::NONE.

Notice that different SSA values can have different literal preceeding its ID, but regardless of the literal every value in the region has unique ID.

Basic block properties:

  • Basic block's ID is unique among the others in the same region;
  • Each basic block has a list of predecessors (<from bb3 bb1>), or it is the starting basic block, in which case it is marked with <start>;
  • A basic block can have either zero (<final>), one (<to bb2>) or two successors (<to T:bb2 / F:bb3>);
  • Basic block cannot have a terminator operation inside of it (it must be the last operation in the basic block);
  • If operation have zero successors, its last operation must be ctrlflow::return (TODO - add check);
  • If operation have one successor, its last operation cannot be ctrlflow::jumpc;
  • If operation have two successors, its last operation must be ctrlflow::jumpc.

Operations common properties:

  • Opcode value, which is unique for every type of operation across all dialects;
  • SSA-value's ID, which is unique across whole region;
  • Return data type, which is DataType::NONE if operation does not produce any result;
  • Optional list of inputs. Some operations can have variadic number of inputs (ctrlflow::call), other have fixed number of inputs (arith::add);
  • List of users, who use this operation's result as their input/inputs;

iris::Region class provide API for working with basic block's dominators:

  • collectDomInfo() - collect dominators information from the graph;
  • getDFS() and getRPO() - obtain corresponding traversal orders;
  • getIdom() and getIdomByID() - get immediate dominator
  • getDominatedBlocks() and getDominatedBlocksByID() - get blocks, for which given one is immediate dominator;
  • getDominatorsChain() and getDominatorsChainByID() - get chain of immediate dominators from the given block to the starting block.

Building examples

Requirements:

  • CMake >= 3.21
  • C++ compiler supporting C++23 standard

To build project, use following commads from the project's roor directory:

cmake -B build
cmake --build build

If you want to build specific target, use following command:

cmake --build build --target <target_name>

List of available targets:

  • iris - IR-support static library
  • factorial - example of IR usage - building IR for a programm calculating factorial manually via iris::IRBuilder

Static library output files are located in build/lib/, and executables - in build/bin.

Testing

Project includes tests, impemented using GTest.

To build and run tests, run following commands from project's root directory:

cmake -B build
cmake --build build --target iris_tests
cd build
ctest

Tests include:

  • Separate test suites for each dialect and its operations' verifiers and construction pre-conditions (tests/dialects/);
  • Tests of verifiers (ex-fails) and API tests for:
    • Generic operation iris::Operation;
    • Basic block iris::BasicBlock;
    • Region iris::Region;
    • IR-builder iris::IRBuilder;
  • Immediate dominators calculation tests (tests/dom_info.cpp);

About

Intermediate Representation Internal Structure - SSA-like IR developed as an educational project

Topics

Resources

License

Stars

Watchers

Forks