diff options
| author | Tim Foley <tim.foley.is@gmail.com> | 2017-08-16 16:25:32 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-08-16 16:25:32 -0700 |
| commit | 3dd88c2eb5cd2e405cd5aa184a2cd45db6fb027a (patch) | |
| tree | 040d49332f125fb7a5450128c98cb9abf21ec035 /source/slang/ir.h | |
| parent | 74e04b8746f7254d5e95520ff31fb09d4bc327b1 (diff) | |
| parent | e30ba2f6b7ad346fa5f2d435a9edc9ba1c56efab (diff) | |
Merge pull request #167 from tfoleyNV/ir
More work on IR
Diffstat (limited to 'source/slang/ir.h')
| -rw-r--r-- | source/slang/ir.h | 253 |
1 files changed, 188 insertions, 65 deletions
diff --git a/source/slang/ir.h b/source/slang/ir.h index db46235b3..95dec6007 100644 --- a/source/slang/ir.h +++ b/source/slang/ir.h @@ -7,125 +7,248 @@ // similar in spirit to LLVM (but much simpler). // +// We need the definition of `BaseType` which currently belongs to the AST +#include "syntax.h" + namespace Slang { -struct IRBlock; struct IRFunc; +struct IRInst; struct IRModule; +struct IRParentInst; struct IRType; -// A value that can be referenced in the program. -struct IRValue +typedef unsigned int IROpFlags; +enum : IROpFlags +{ + kIROpFlags_None = 0, + + // This op is a parent op + kIROpFlag_Parent = 1 << 0, +}; + +// A logical operation/opcode in the IR +struct IROpInfo +{ + // What is the name/mnemonic for this operation + char const* name; + + // How many required arguments are there + // (not including the mandatory type argument) + unsigned int fixedArgCount; + + // Flags to control how we emit additional info + IROpFlags flags; +}; + +// A use of another value/inst within an IR operation +struct IRUse +{ + // The value that is doing the using. + IRInst* user; + + // The value that is being used + IRInst* usedValue; + + // The next use of the same value + IRUse* nextUse; + + // A "link" back to where this use is referenced, + // so that we can simplify updates. + IRUse** prevLink; + + void init(IRInst* user, IRInst* usedValue); +}; + +// In the IR, almost *everything* is an instruction, +// in order to make the representation as uniform as possible. +struct IRInst +{ + // The operation that this value represents + IROpInfo const* op; + + // A unique ID to represent the op when printing + // (or zero to indicate that the value of this + // op isn't special). + UInt id; + + // The parent of this instruction. + // This will often be a basic block, but we + // allow instructions to nest in more general ways. + IRParentInst* parent; + + // The next and previous instructions in the same parent block + IRInst* nextInst; + IRInst* prevInst; + + // The first use of this value (start of a linked list) + IRUse* firstUse; + + // The type of this value + IRUse type; + + IRUse* getArgs(); +}; + +typedef IRInst IRValue; + +typedef long long IRIntegerValue; +typedef double IRFloatingPointValue; + +struct IRIntLit : IRInst +{ + IRIntegerValue value; +}; + +struct IRFloatLit : IRInst { - // Type type of this value - IRType* type; + IRFloatingPointValue value; }; // Representation of a type at the IR level. // Such a type may not correspond to the high-level-language notion // of a type as used by the front end. // -// Note that types are values in the IR, so that operations +// Note that types are instructions in the IR, so that operations // may take type operands as easily as values. -struct IRType : IRValue +struct IRType : IRInst { }; -// An instruction in the program. -struct IRInst : IRValue +struct IRVectorType : IRType { - // The basic block that contains this instruction, - // or NULL if the instruction currently has no parent. - IRBlock* parentBlock; + IRUse elementType; + IRUse elementCount; +}; - // The next and previous instructions in the same parent block - IRInst* nextInst; - IRInst* prevInst; +struct IRStructType : IRType +{}; + +struct IRFieldExtract : IRInst +{ + IRUse base; + UInt fieldIndex; }; // A instruction that ends a basic block (usually because of control flow) struct IRTerminatorInst : IRInst {}; -// A basic block, consisting of a sequence of instructions that can only -// be entered at the top, and can only be exited at the last instruction. -// -// Note that a block is itself a value, so that it can be a direct operand -// of an instruction (e.g., an instruction that branches to the block) -struct IRBlock : IRValue +struct IRReturn : IRTerminatorInst +{}; + +struct IRReturnVal : IRReturn { - // The function that contains this block - IRFunc* parentFunc; + IRUse val; +}; - // The first and last instruction in the block (or NULL in - // the case that the block is empty). +struct IRReturnVoid : IRReturn +{}; + +// A parent instruction contains a sequence of other instructions +// +struct IRParentInst : IRInst +{ + // The first and last instruction in the container (or NULL in + // the case that the container is empty). // + IRInst* firstChild; + IRInst* lastChild; +}; + +// A basic block is a parent instruction that adds the constraint +// that all the children need to be "ordinary" instructions (so +// no function declarations, or nested blocks). We also expect +// that the previous/next instruction are always a basic block. +// +struct IRBlock : IRParentInst +{ // Note that in a valid program, every block must end with // a "terminator" instruction, so these should be non-NULL, // and `last` should actually be an `IRTerminatorInst`. - IRInst* first; - IRInst* last; - - // Next and previous block in the same function - IRBlock* nextBlock; - IRBlock* prevBlock; + IRInst* firstChild; + IRInst* lastChild; }; -// A function parameter. -struct IRParam : IRValue +// A function parameter is represented by an instruction +// in the entry block of a function. +struct IRParam : IRInst { - // The function that declared this parameter - IRFunc* parentFunc; - - // The next and previous parameter of the function - IRParam* nextParam; - IRParam* prevParam; - }; -// A function, which consists of zero or more blocks of instructions. +// A function is a parent to zero or more blocks of instructions. // // A function is itself a value, so that it can be a direct operand of // an instruction (e.g., a call). -struct IRFunc : IRValue +struct IRFunc : IRParentInst { - // The IR module that defines this function - IRModule* parentModule; - - // The unique entry block for the function is always the - // first block in the list of blocks. - IRBlock* firstBlock; - - // The last block in the function. - IRBlock* lastBlock; - - // The parameters of the function - IRParam* firstParam; - IRParam* lastParam; - - // The next/previous function in the same IR module - IRFunc* nextFunc; - IRFunc* prevFunc; }; -// A module defining global values -struct IRModule +// A module is a parent to functions, global variables, types, etc. +struct IRModule : IRParentInst { -}; - -typedef long long IRIntegerValue; -typedef double IRFloatingPointValue; + // The designated entry-point function, if any + IRFunc* entryPoint; + // A special counter used to assign logical ids to instructions in this module. + UInt idCounter; +}; struct IRBuilder { + // The module that will own all of the IR + IRModule* module; + + // The parent instruction to add children to. + IRParentInst* parentInst; + + IRType* getBaseType(BaseType flavor); IRType* getBoolType(); + IRType* getVectorType(IRType* elementType, IRValue* elementCount); + IRType* getTypeType(); + IRType* getVoidType(); + IRType* getBlockType(); + IRType* getStructType( + UInt fieldCount, + IRType* const* fieldTypes); IRValue* getBoolValue(bool value); IRValue* getIntValue(IRType* type, IRIntegerValue value); IRValue* getFloatValue(IRType* type, IRFloatingPointValue value); + + IRInst* emitIntrinsicInst( + IRType* type, + IntrinsicOp intrinsicOp, + UInt argCount, + IRValue* const* args); + + IRInst* emitConstructorInst( + IRType* type, + UInt argCount, + IRValue* const* args); + + IRModule* createModule(); + + IRFunc* createFunc(); + + IRBlock* createBlock(); + + IRParam* createParam( + IRType* type); + + IRInst* createFieldExtract( + IRType* type, + IRValue* base, + UInt fieldIndex); + + IRInst* createReturn( + IRValue* val); + + IRInst* createReturn(); }; +void dumpIR(IRModule* module); + } #endif |
