From 5900f32fff9970b4221ce7fb7e94133e387ff9de Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 31 Aug 2017 12:47:39 -0700 Subject: Continue work on IR-based codegen This gets us far enough that we can convert a single test case to use the IR, under the new `-use-ir` flag. Getting this merged into mainline will at least ensure that we keep the IR path working in a minimal fashion, even when we have to add functionality the existing AST-based path There is definitely some clutter here from keeping both IR-based and AST-based translation around, but I don't want to have a long-lived branch for the IR that gets further and further away from the `master` branch that is actually getting used and tested. Summary of changes: - Add pointer types and basic `load` operation to be able to handle variable declarations - Add basic `call` instruction type - Add simple address math for field reference in l-value - Always add IR for referenced decls to global scope - Add notion of "intrinsic" type modifier, which maps a type declaration directly to an IR opcode (plus optional literal operands to handle things like texture/sampler flavor) - Improve printing of IR instructions, types, operands - Add constant-buffer type to IR - Allow any instruction to be detected as "should be folded into use sites" and use this to tag things of constant-buffer type - Also add logic for implicit base on member expressions, to handle references to `cbuffer` members - Add connection back to original decl to IR variables (including global shader parameters...) - Use reflection name instead of true name when emitting HLSL from IR (so that we can match HLSL output) - Make IR include decorations for type layout - Re-use existing emit logic for HLSL semantics to output `register` semantics for IR-based code - Make IR-based codegen be an option we can enable from the command line - It still isn't on by default (it can barely manage a trivial shader), but it seems better to enable it always instead of putting it under an `#ifdef` - Fix up how we check for intrinsic operations suring AST-based cross compilation so that adding new intrinsic ops for the IR won't break codegen. --- source/slang/ir.h | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) (limited to 'source/slang/ir.h') diff --git a/source/slang/ir.h b/source/slang/ir.h index fcebf5d15..aa7b6a045 100644 --- a/source/slang/ir.h +++ b/source/slang/ir.h @@ -7,6 +7,8 @@ // similar in spirit to LLVM (but much simpler). // +#include "type-layout.h" + // We need the definition of `BaseType` which currently belongs to the AST #include "syntax.h" @@ -72,6 +74,7 @@ struct IRUse enum IRDecorationOp : uint16_t { kIRDecorationOp_HighLevelDecl, + kIRDecorationOp_Layout, }; // A "decoration" that gets applied to an instruction. @@ -161,6 +164,15 @@ struct IRHighLevelDeclDecoration : IRDecoration Decl* decl; }; +// Associates an IR-level decoration with a source layout +struct IRLayoutDecoration : IRDecoration +{ + enum { kDecorationOp = kIRDecorationOp_Layout }; + + Layout* layout; +}; + + typedef long long IRIntegerValue; typedef double IRFloatingPointValue; @@ -211,6 +223,41 @@ struct IRFuncType : IRType } }; +struct IRPtrType : IRType +{ + IRUse valueType; + + IRType* getValueType() { return (IRType*) valueType.usedValue; } +}; + +struct IRTextureType : IRType +{ + IRUse flavor; + IRUse elementType; + + IRIntegerValue getFlavor() { return ((IRConstant*) flavor.usedValue)->u.intVal; } + IRType* getElementType() { return (IRType*) elementType.usedValue; } +}; + +struct IRUniformBufferType : IRType +{ + IRUse elementType; + IRType* getElementType() { return (IRType*) elementType.usedValue; } +}; + +struct IRConstantBufferType : IRUniformBufferType {}; +struct IRTextureBufferType : IRUniformBufferType {}; + +struct IRCall : IRInst +{ + IRUse func; +}; + +struct IRLoad : IRInst +{ + IRUse ptr; +}; + struct IRStructField; struct IRFieldExtract : IRInst { @@ -221,6 +268,16 @@ struct IRFieldExtract : IRInst IRStructField* getField() { return (IRStructField*) field.usedValue; } }; +struct IRFieldAddress : IRInst +{ + IRUse base; + IRUse field; + + IRInst* getBase() { return base.usedValue; } + IRStructField* getField() { return (IRStructField*) field.usedValue; } +}; + + // A instruction that ends a basic block (usually because of control flow) struct IRTerminatorInst : IRInst {}; @@ -285,6 +342,9 @@ struct IRParam : IRInst IRParam* getNextParam(); }; +struct IRVar : IRInst +{}; + // 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 @@ -360,6 +420,11 @@ struct IRBuilder IRType* getVoidType(); IRType* getBlockType(); + IRType* getIntrinsicType( + IROp op, + UInt argCount, + IRValue* const* args); + IRStructDecl* createStructType(); IRStructField* createStructField(IRType* fieldType); @@ -368,10 +433,19 @@ struct IRBuilder IRType* const* paramTypes, IRType* resultType); + IRType* getPtrType( + IRType* valueType); + IRValue* getBoolValue(bool value); IRValue* getIntValue(IRType* type, IRIntegerValue value); IRValue* getFloatValue(IRType* type, IRFloatingPointValue value); + IRInst* emitCallInst( + IRType* type, + IRValue* func, + UInt argCount, + IRValue* const* args); + IRInst* emitIntrinsicInst( IRType* type, IntrinsicOp intrinsicOp, @@ -393,11 +467,22 @@ struct IRBuilder IRParam* emitParam( IRType* type); + IRVar* emitVar( + IRType* type); + + IRInst* emitLoad( + IRValue* ptr); + IRInst* emitFieldExtract( IRType* type, IRValue* base, IRStructField* field); + IRInst* emitFieldAddress( + IRType* type, + IRValue* basePtr, + IRStructField* field); + IRInst* emitReturn( IRValue* val); @@ -414,7 +499,14 @@ struct IRBuilder return (T*) addDecorationImpl(inst, sizeof(T), op); } + template + T* addDecoration(IRInst* inst) + { + return (T*) addDecorationImpl(inst, sizeof(T), IRDecorationOp(T::kDecorationOp)); + } + IRHighLevelDeclDecoration* addHighLevelDeclDecoration(IRInst* inst, Decl* decl); + IRLayoutDecoration* addLayoutDecoration(IRInst* inst, Layout* layout); }; void dumpIR(IRModule* module); -- cgit v1.2.3