From ad19484792dcc5a1fb90720614830c66c4b9712d Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 17 Aug 2017 13:40:50 -0700 Subject: Add some dummy logic to print IR to HLSL - Change IR instructions to just hold an integer opcode instead of a pointer to the "info" structure - Externalize definition of IR instructions to a header file, and use the "X macro" approach to allow generating different definitions - Add notion of function types to the IR, so that we can easily query the result type of a function - Add some convenience accesors to allow walking the IR in a strongly-typed manner (e.g., iterate over the parameters of a function) - TODO: these should really be changed to assert the type of things, as least in debug builds - Add very basic logic to `emit.cpp` so that it can walk the generated IR and start printing it back as HLSL - This isn't meant to be usable as-is, but it is a step toward where we need to go --- source/slang/ir.cpp | 224 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 135 insertions(+), 89 deletions(-) (limited to 'source/slang/ir.cpp') diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index c40b0f048..d2c3f5ba5 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -6,51 +6,19 @@ namespace Slang { -#define OP(ID, MNEMONIC, ARG_COUNT, FLAGS) \ - static const IROpInfo kIROpInfo_##ID { \ - #MNEMONIC, ARG_COUNT, FLAGS, } - -#define PARENT kIROpFlag_Parent - - OP(TypeType, type.type, 0, 0); - OP(VoidType, type.void, 0, 0); - OP(BlockType, type.block, 0, 0); - OP(VectorType, type.vector, 2, 0); - OP(BoolType, type.bool, 0, 0); - OP(Float32Type, type.f32, 0, 0); - OP(Int32Type, type.i32, 0, 0); - OP(UInt32Type, type.u32, 0, 0); - OP(StructType, type.struct, 0, 0); - - OP(IntLit, integer_constant, 0, 0); - OP(FloatLit, float_constant, 0, 0); - - OP(Construct, construct, 0, 0); - - OP(Module, module, 0, PARENT); - OP(Func, func, 0, PARENT); - OP(Block, block, 0, PARENT); - - OP(Param, param, 0, 0); - - OP(FieldExtract, get_field, 1, 0); - OP(ReturnVal, return_val, 1, 0); - OP(ReturnVoid, return_void, 1, 0); - -#define INTRINSIC(NAME) \ - static const IROpInfo kIROpInfo_Intrinsic_##NAME { \ - "intrinsic." #NAME, 0, 0, }; -#include "intrinsic-defs.h" - -#undef PARENT -#undef OP + static const IROpInfo kIROpInfos[] = + { +#define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) \ + { #MNEMONIC, ARG_COUNT, FLAGS, }, +#include "ir-inst-defs.h" + }; - static IROpInfo const* const kIRIntrinsicOpInfos[] = + static const IROp kIRIntrinsicOps[] = { - nullptr, + (IROp) 0, -#define INTRINSIC(NAME) &kIROpInfo_Intrinsic_##NAME, +#define INTRINSIC(NAME) kIROp_Intrinsic_##NAME, #include "intrinsic-defs.h" }; @@ -80,6 +48,33 @@ namespace Slang // + IRParam* IRFunc::getFirstParam() + { + auto entryBlock = getFirstBlock(); + if(!entryBlock) return nullptr; + + auto firstInst = entryBlock->firstChild; + if(!firstInst) return nullptr; + + if(firstInst->op != kIROp_Param) + return nullptr; + + return (IRParam*) firstInst; + } + + IRParam* IRParam::getNextParam() + { + auto next = nextInst; + if(!next) return nullptr; + + if(next->op != kIROp_Param) + return nullptr; + + return (IRParam*) next; + } + + // + // Add an instruction to a specific parent void IRBuilder::addInst(IRParentInst* parent, IRInst* inst) { @@ -124,10 +119,12 @@ namespace Slang static IRValue* createInstImpl( IRBuilder* builder, UInt size, - IROpInfo const* op, + IROp op, IRType* type, - UInt argCount, - IRValue* const* args) + UInt fixedArgCount, + IRValue* const* fixedArgs, + UInt varArgCount = 0, + IRValue* const* varArgs = nullptr) { IRValue* inst = (IRInst*) malloc(size); memset(inst, 0, size); @@ -135,7 +132,7 @@ namespace Slang IRUse* instArgs = inst->getArgs(); auto module = builder->getModule(); - if (!module || (type && type->op == &kIROpInfo_VoidType)) + if (!module || (type && type->op == kIROp_VoidType)) { // Can't or shouldn't assign an ID to this op } @@ -143,15 +140,25 @@ namespace Slang { inst->id = ++module->idCounter; } - inst->argCount = argCount + 1; + inst->argCount = fixedArgCount + varArgCount + 1; inst->op = op; - inst->type.init(inst, type); + auto operand = inst->getArgs(); - for( UInt aa = 0; aa < argCount; ++aa ) + operand->init(inst, type); + operand++; + + for( UInt aa = 0; aa < fixedArgCount; ++aa ) { - instArgs[aa+1].init(inst, args[aa]); + operand->init(inst, fixedArgs[aa]); + operand++; + } + + for( UInt aa = 0; aa < varArgCount; ++aa ) + { + operand->init(inst, varArgs[aa]); + operand++; } return inst; @@ -165,7 +172,7 @@ namespace Slang static IRValue* createInstImpl( IRBuilder* builder, UInt size, - IROpInfo const* op, + IROp op, UInt argCount, IRValue* const* args) { @@ -181,7 +188,7 @@ namespace Slang template static T* createInst( IRBuilder* builder, - IROpInfo const* op, + IROp op, IRType* type, UInt argCount, IRValue* const* args) @@ -198,7 +205,7 @@ namespace Slang template static T* createInst( IRBuilder* builder, - IROpInfo const* op, + IROp op, IRType* type) { return (T*)createInstImpl( @@ -213,7 +220,7 @@ namespace Slang template static T* createInst( IRBuilder* builder, - IROpInfo const* op, + IROp op, IRType* type, IRValue* arg) { @@ -229,7 +236,7 @@ namespace Slang template static T* createInst( IRBuilder* builder, - IROpInfo const* op, + IROp op, IRType* type, IRValue* arg1, IRValue* arg2) @@ -247,7 +254,7 @@ namespace Slang template static T* createInstWithTrailingArgs( IRBuilder* builder, - IROpInfo const* op, + IROp op, IRType* type, UInt argCount, IRValue* const* args) @@ -261,6 +268,27 @@ namespace Slang args); } + template + static T* createInstWithTrailingArgs( + IRBuilder* builder, + IROp op, + IRType* type, + UInt fixedArgCount, + IRValue* const* fixedArgs, + UInt varArgCount, + IRValue* const* varArgs) + { + return (T*)createInstImpl( + builder, + sizeof(T) + varArgCount * sizeof(IRUse), + op, + type, + fixedArgCount, + fixedArgs, + varArgCount, + varArgs); + } + // bool operator==(IRInstKey const& left, IRInstKey const& right) @@ -327,7 +355,7 @@ namespace Slang static IRInst* findOrEmitInstImpl( IRBuilder* builder, UInt size, - IROpInfo const* op, + IROp op, IRType* type, UInt argCount, IRValue* const* args) @@ -354,7 +382,7 @@ namespace Slang parent = builder->parentInst; } - if( parent->op == &kIROpInfo_Func ) + if( parent->op == kIROp_Func ) { // We are trying to insert into a function, and we should really // be inserting into its entry block. @@ -398,7 +426,7 @@ namespace Slang template static T* findOrEmitInst( IRBuilder* builder, - IROpInfo const* op, + IROp op, IRType* type, UInt argCount, IRValue* const* args) @@ -415,7 +443,7 @@ namespace Slang template static T* findOrEmitInst( IRBuilder* builder, - IROpInfo const* op, + IROp op, IRType* type) { return (T*) findOrEmitInstImpl( @@ -430,7 +458,7 @@ namespace Slang template static T* findOrEmitInst( IRBuilder* builder, - IROpInfo const* op, + IROp op, IRType* type, IRInst* arg) { @@ -446,7 +474,7 @@ namespace Slang template static T* findOrEmitInst( IRBuilder* builder, - IROpInfo const* op, + IROp op, IRType* type, IRInst* arg1, IRInst* arg2) @@ -482,11 +510,11 @@ namespace Slang } static IRConstant* findOrEmitConstant( - IRBuilder* builder, - IROpInfo const* op, - IRType* type, - UInt valueSize, - void const* value) + IRBuilder* builder, + IROp op, + IRType* type, + UInt valueSize, + void const* value) { // First, we need to pick a good insertion point // for the instruction, which we do by looking @@ -531,7 +559,7 @@ namespace Slang // - static IRType* getBaseTypeImpl(IRBuilder* builder, IROpInfo const* op) + static IRType* getBaseTypeImpl(IRBuilder* builder, IROp op) { auto inst = findOrEmitInst( builder, @@ -544,10 +572,10 @@ namespace Slang { switch( flavor ) { - case BaseType::Bool: return getBaseTypeImpl(this, &kIROpInfo_BoolType); - case BaseType::Float: return getBaseTypeImpl(this, &kIROpInfo_Float32Type); - case BaseType::Int: return getBaseTypeImpl(this, &kIROpInfo_Int32Type); - case BaseType::UInt: return getBaseTypeImpl(this, &kIROpInfo_UInt32Type); + case BaseType::Bool: return getBaseTypeImpl(this, kIROp_BoolType); + case BaseType::Float: return getBaseTypeImpl(this, kIROp_Float32Type); + case BaseType::Int: return getBaseTypeImpl(this, kIROp_Int32Type); + case BaseType::UInt: return getBaseTypeImpl(this, kIROp_UInt32Type); default: SLANG_UNEXPECTED("unhandled base type"); @@ -564,7 +592,7 @@ namespace Slang { return findOrEmitInst( this, - &kIROpInfo_VectorType, + kIROp_VectorType, getTypeType(), elementType, elementCount); @@ -574,7 +602,7 @@ namespace Slang { return findOrEmitInst( this, - &kIROpInfo_TypeType, + kIROp_TypeType, nullptr); } @@ -582,7 +610,7 @@ namespace Slang { return findOrEmitInst( this, - &kIROpInfo_VoidType, + kIROp_VoidType, getTypeType()); } @@ -590,7 +618,7 @@ namespace Slang { return findOrEmitInst( this, - &kIROpInfo_BlockType, + kIROp_BlockType, getTypeType()); } @@ -600,7 +628,7 @@ namespace Slang { auto inst = createInstWithTrailingArgs( this, - &kIROpInfo_StructType, + kIROp_StructType, getTypeType(), fieldCount, (IRValue* const*)fieldTypes); @@ -608,6 +636,23 @@ namespace Slang return inst; } + IRType* IRBuilder::getFuncType( + UInt paramCount, + IRType* const* paramTypes, + IRType* resultType) + { + auto inst = createInstWithTrailingArgs( + this, + kIROp_FuncType, + getTypeType(), + 1, + (IRValue* const*) &resultType, + paramCount, + (IRValue* const*) paramTypes); + addInst(inst); + return inst; + } + IRValue* IRBuilder::getBoolValue(bool value) { SLANG_UNIMPLEMENTED_X("IR"); @@ -617,7 +662,7 @@ namespace Slang { return findOrEmitConstant( this, - &kIROpInfo_IntLit, + kIROp_IntLit, type, sizeof(value), &value); @@ -627,7 +672,7 @@ namespace Slang { return findOrEmitConstant( this, - &kIROpInfo_FloatLit, + kIROp_FloatLit, type, sizeof(value), &value); @@ -641,7 +686,7 @@ namespace Slang { auto inst = createInstWithTrailingArgs( this, - kIRIntrinsicOpInfos[(int)intrinsicOp], + kIRIntrinsicOps[(int)intrinsicOp], type, argCount, args); @@ -656,7 +701,7 @@ namespace Slang { auto inst = createInstWithTrailingArgs( this, - &kIROpInfo_Construct, + kIROp_Construct, type, argCount, args); @@ -668,7 +713,7 @@ namespace Slang { return createInst( this, - &kIROpInfo_Module, + kIROp_Module, nullptr); } @@ -677,7 +722,7 @@ namespace Slang { return createInst( this, - &kIROpInfo_Func, + kIROp_Func, nullptr); } @@ -685,7 +730,7 @@ namespace Slang { return createInst( this, - &kIROpInfo_Block, + kIROp_Block, getBlockType()); } @@ -701,7 +746,7 @@ namespace Slang { auto inst = createInst( this, - &kIROpInfo_Param, + kIROp_Param, type); addInst(inst); return inst; @@ -714,7 +759,7 @@ namespace Slang { auto inst = createInst( this, - &kIROpInfo_FieldExtract, + kIROp_FieldExtract, type, base); @@ -729,7 +774,7 @@ namespace Slang { auto inst = createInst( this, - &kIROpInfo_ReturnVal, + kIROp_ReturnVal, getVoidType(), val); addInst(inst); @@ -740,7 +785,7 @@ namespace Slang { auto inst = createInst( this, - &kIROpInfo_ReturnVoid, + kIROp_ReturnVoid, getVoidType()); addInst(inst); return inst; @@ -803,6 +848,7 @@ namespace Slang // TODO: need to display a name for the result... auto op = inst->op; + auto opInfo = &kIROpInfos[op]; if (inst->id) { @@ -810,7 +856,7 @@ namespace Slang dump(context, " = "); } - dump(context, op->name); + dump(context, opInfo->name); // TODO: dump operands uint32_t argCount = inst->argCount; @@ -832,7 +878,7 @@ namespace Slang dump(context, "\n"); - if (op->flags & kIROpFlag_Parent) + if (opInfo->flags & kIROpFlag_Parent) { dumpIndent(context); dump(context, "{\n"); -- cgit v1.2.3 From 95348fdb623509eb22c04d4c7c19af8228c5a533 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 17 Aug 2017 14:17:29 -0700 Subject: [ir] Represent fields more direclty Previously, a `StructType` was an ordinary instruction that took a variable number of types are operands, representing the types of fields. This ends up being inconvenient for a few reasons: - To add decorations to the fields, you'd end up having to decorate the struct type instead (SPIR-V has this problem) - You need to compute field indices during lowering, when you might prefer to defer that until later - The get/set field operations now need an index, which needs to be an explicit operand, which means a magic numeric literal floating around to represent the index The new approach fixes for the first two of these, and at least makes the last one a bit nicer. A `StructDecl` is now a parent instruction, and its sub-instructions represent the fields of the type - each field is an explicit instruction of type `StructField`. The operation to extract a field takes a direct reference the struct field, so everything is quite explicit. --- source/slang/emit.cpp | 22 +++++++++------------ source/slang/ir-inst-defs.h | 7 ++++--- source/slang/ir.cpp | 32 +++++++++++++++--------------- source/slang/ir.h | 37 +++++++++++++++++++++-------------- source/slang/lower-to-ir.cpp | 46 +++++++++++++++++--------------------------- 5 files changed, 71 insertions(+), 73 deletions(-) (limited to 'source/slang/ir.cpp') diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 35020249b..1f0436d8a 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -4016,8 +4016,8 @@ emitDeclImpl(decl, nullptr); emitIRInstResultDecl(context, inst); emitIROperand(context, fieldExtract->getBase()); - emit(".field"); - emit(fieldExtract->fieldIndex); + emit("."); + emit(getName(fieldExtract->getField())); emit(";\n"); } break; @@ -4087,20 +4087,16 @@ emitDeclImpl(decl, nullptr); void emitIRStruct( EmitContext* context, - IRStructType* structType) + IRStructDecl* structType) { emit("struct "); emit(getName(structType)); emit("\n{\n"); - auto fieldCount = structType->getFieldCount(); - for( UInt ff = 0; ff < fieldCount; ++ff ) - { - auto fieldType = structType->getFieldType(ff); - - String fieldName = "field"; - fieldName.append(ff); - emitIRType(context, fieldType, fieldName); + for(auto ff = structType->getFirstField(); ff; ff = ff->getNextField()) + { + auto fieldType = ff->getFieldType(); + emitIRType(context, fieldType, getName(ff)); emit(";\n"); } emit("};\n"); @@ -4119,7 +4115,7 @@ emitDeclImpl(decl, nullptr); break; case kIROp_StructType: - emitIRStruct(context, (IRStructType*) inst); + emitIRStruct(context, (IRStructDecl*) inst); break; default: @@ -4254,7 +4250,7 @@ String emitEntryPoint( // // We'll try to detect the cases here: // -#if 0 +#if 1 if(!(translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING )) { // This seems to be case (3), because the user is asking for full diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h index 8445e5a1e..d594d2755 100644 --- a/source/slang/ir-inst-defs.h +++ b/source/slang/ir-inst-defs.h @@ -14,7 +14,7 @@ INST(BoolType, type.bool, 0, 0) INST(Float32Type, type.f32, 0, 0) INST(Int32Type, type.i32, 0, 0) INST(UInt32Type, type.u32, 0, 0) -INST(StructType, type.struct, 0, 0) +INST(StructType, type.struct, 0, PARENT) INST(FuncType, func_type, 0, 0) INST(IntLit, integer_constant, 0, 0) @@ -26,9 +26,10 @@ INST(Module, module, 0, PARENT) INST(Func, func, 0, PARENT) INST(Block, block, 0, PARENT) -INST(Param, param, 0, 0) +INST(Param, param, 0, 0) +INST(StructField, field, 0, 0) -INST(FieldExtract, get_field, 1, 0) +INST(FieldExtract, get_field, 2, 0) INST(ReturnVal, return_val, 1, 0) INST(ReturnVoid, return_void, 1, 0) diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index d2c3f5ba5..b6af6aabb 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -622,20 +622,23 @@ namespace Slang getTypeType()); } - IRType* IRBuilder::getStructType( - UInt fieldCount, - IRType* const* fieldTypes) + IRStructDecl* IRBuilder::createStructType() { - auto inst = createInstWithTrailingArgs( + return createInst( this, kIROp_StructType, - getTypeType(), - fieldCount, - (IRValue* const*)fieldTypes); - addInst(inst); - return inst; + getTypeType()); } + IRStructField* IRBuilder::createStructField(IRType* fieldType) + { + return createInst( + this, + kIROp_StructField, + fieldType); + } + + IRType* IRBuilder::getFuncType( UInt paramCount, IRType* const* paramTypes, @@ -753,17 +756,16 @@ namespace Slang } IRInst* IRBuilder::emitFieldExtract( - IRType* type, - IRValue* base, - UInt fieldIndex) + IRType* type, + IRValue* base, + IRStructField* field) { auto inst = createInst( this, kIROp_FieldExtract, type, - base); - - inst->fieldIndex = fieldIndex; + base, + field); addInst(inst); return inst; diff --git a/source/slang/ir.h b/source/slang/ir.h index e583997fd..319340024 100644 --- a/source/slang/ir.h +++ b/source/slang/ir.h @@ -153,13 +153,6 @@ struct IRVectorType : IRType IRInst* getElementCount() { return elementCount.usedValue; } }; -struct IRStructType : IRType -{ - - UInt getFieldCount() { return getArgCount() - 1; } - IRType* getFieldType(UInt index) { return (IRType*) getArg(index + 1); } -}; - struct IRFuncType : IRType { IRUse resultType; @@ -176,12 +169,14 @@ struct IRFuncType : IRType } }; +struct IRStructField; struct IRFieldExtract : IRInst { IRUse base; - UInt fieldIndex; + 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) @@ -212,6 +207,20 @@ struct IRParentInst : IRInst IRInst* lastChild; }; +struct IRStructField : IRInst +{ + IRType* getFieldType() { return (IRType*) type.usedValue; } + + IRStructField* getNextField() { return (IRStructField*) nextInst; } +}; + +struct IRStructDecl : IRParentInst +{ + IRStructField* getFirstField() { return (IRStructField*) firstChild; } + IRStructField* getLastField() { return (IRStructField*) 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 @@ -308,9 +317,9 @@ struct IRBuilder IRType* getTypeType(); IRType* getVoidType(); IRType* getBlockType(); - IRType* getStructType( - UInt fieldCount, - IRType* const* fieldTypes); + + IRStructDecl* createStructType(); + IRStructField* createStructField(IRType* fieldType); IRType* getFuncType( UInt paramCount, @@ -343,9 +352,9 @@ struct IRBuilder IRType* type); IRInst* emitFieldExtract( - IRType* type, - IRValue* base, - UInt fieldIndex); + IRType* type, + IRValue* base, + IRStructField* field); IRInst* emitReturn( IRValue* val); diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index ed8ed3318..5d0a40072 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -394,7 +394,7 @@ struct ExprLoweringVisitor : ExprVisitor LoweredValInfo extractField( LoweredTypeInfo fieldType, LoweredValInfo base, - UInt fieldIndex) + LoweredValInfo field) { switch (base.flavor) { @@ -405,7 +405,7 @@ struct ExprLoweringVisitor : ExprVisitor getBuilder()->emitFieldExtract( getSimpleType(fieldType), irBase, - fieldIndex)); + (IRStructField*) getSimpleVal(field))); } break; @@ -424,22 +424,8 @@ struct ExprLoweringVisitor : ExprVisitor { // Okay, easy enough: we have a reference to a field of a struct type... - // HACK: for now just scan the decl to find the right index. - // TODO: we need to deal with the fact that the struct might get - // tuple-ified. - // - UInt index = 0; - for (auto fieldDecl : getMembersOfType(fieldDeclRef.GetParent().As())) - { - if (fieldDecl == fieldDeclRef.getDecl()) - { - break; - } - - index++; - } - - return extractField(loweredType, loweredBase, index); + auto loweredField = ensureDecl(context, fieldDeclRef); + return extractField(loweredType, loweredBase, loweredField); } SLANG_UNIMPLEMENTED_X("codegen for subscript expression"); @@ -559,20 +545,27 @@ struct DeclLoweringVisitor : DeclVisitor // User-defined aggregate type: need to translate into // a corresponding IR aggregate type. - List fieldTypes; - List irFieldTypes; + auto builder = getBuilder(); + IRStructDecl* irStruct = builder->createStructType(); for (auto fieldDecl : decl->GetFields()) { + // TODO: need to track relationship to original fields... + // TODO: need to be prepared to deal with tuple-ness of fields here auto fieldType = lowerType(context, fieldDecl->getType()); - fieldTypes.Add(fieldType); - switch (fieldType.flavor) { case LoweredTypeInfo::Flavor::Simple: - irFieldTypes.Add(fieldType.type); + { + auto irField = builder->createStructField(getSimpleType(fieldType)); + builder->addInst(irStruct, irField); + + context->shared->declValues.Add( + DeclRef(fieldDecl, nullptr), + LoweredValInfo::simple(irField)); + } break; default: @@ -580,13 +573,10 @@ struct DeclLoweringVisitor : DeclVisitor } } - // TODO: need to track relationship to original fields... - IRType* irStructType = getBuilder()->getStructType( - irFieldTypes.Count(), - &irFieldTypes[0]); + builder->addInst(irStruct); - return LoweredValInfo::simple(irStructType); + return LoweredValInfo::simple(irStruct); } LoweredValInfo visitFunctionDeclBase(FunctionDeclBase* decl) -- cgit v1.2.3 From ec8175c1f0afe3f7758f70da240aba03a791c3a9 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 17 Aug 2017 14:51:09 -0700 Subject: [ir] Add support for "decorations" on instructions The terminology here is similar to SPIR-V. For right now the only decoration exposed is a fairly brute-force one that just points back to a high-level declaration so that we can look up info on it that might affect how we print output. --- source/slang/emit.cpp | 24 ++++++++++++++++++- source/slang/ir.cpp | 38 ++++++++++++++++++++++++++++-- source/slang/ir.h | 55 ++++++++++++++++++++++++++++++++++++++++++++ source/slang/lower-to-ir.cpp | 5 ++++ 4 files changed, 119 insertions(+), 3 deletions(-) (limited to 'source/slang/ir.cpp') diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 1f0436d8a..6440c63a3 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -3827,6 +3827,11 @@ emitDeclImpl(decl, nullptr); String getName(IRInst* inst) { + if(auto decoration = inst->findDecoration()) + { + return getText(decoration->decl->getName()); + } + StringBuilder sb; sb << "_S"; sb << inst->id; @@ -4038,6 +4043,17 @@ emitDeclImpl(decl, nullptr); } } + void emitIRSemantics( + EmitContext* context, + IRInst* inst) + { + auto decoration = inst->findDecoration(); + if( decoration ) + { + EmitSemantics(decoration->decl); + } + } + void emitIRFunc( EmitContext* context, IRFunc* func) @@ -4061,6 +4077,9 @@ emitDeclImpl(decl, nullptr); } emit(")"); + + emitIRSemantics(context, func); + // TODO: encode declaration vs. definition bool isDefinition = true; if(isDefinition) @@ -4097,6 +4116,9 @@ emitDeclImpl(decl, nullptr); { auto fieldType = ff->getFieldType(); emitIRType(context, fieldType, getName(ff)); + + emitIRSemantics(context, ff); + emit(";\n"); } emit("};\n"); @@ -4250,7 +4272,7 @@ String emitEntryPoint( // // We'll try to detect the cases here: // -#if 1 +#if 0 if(!(translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING )) { // This seems to be case (3), because the user is asking for full diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index b6af6aabb..8e4f789ef 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -46,6 +46,16 @@ namespace Slang return &type; } + IRDecoration* IRInst::findDecorationImpl(IRDecorationOp decorationOp) + { + for( auto dd = firstDecoration; dd; dd = dd->next ) + { + if(dd->op == decorationOp) + return dd; + } + return nullptr; + } + // IRParam* IRFunc::getFirstParam() @@ -129,8 +139,6 @@ namespace Slang IRValue* inst = (IRInst*) malloc(size); memset(inst, 0, size); - IRUse* instArgs = inst->getArgs(); - auto module = builder->getModule(); if (!module || (type && type->op == kIROp_VoidType)) { @@ -793,6 +801,32 @@ namespace Slang return inst; } + IRDecoration* IRBuilder::addDecorationImpl( + IRInst* inst, + UInt decorationSize, + IRDecorationOp op) + { + auto decoration = (IRDecoration*) malloc(decorationSize); + memset(decoration, 0, decorationSize); + + decoration->op = op; + + decoration->next = inst->firstDecoration; + inst->firstDecoration = decoration; + + return decoration; + } + + IRHighLevelDeclDecoration* IRBuilder::addHighLevelDeclDecoration(IRInst* inst, Decl* decl) + { + auto decoration = addDecoration(inst, kIRDecorationOp_HighLevelDecl); + decoration->decl = decl; + return decoration; + } + + // + + struct IRDumpContext { FILE* file; diff --git a/source/slang/ir.h b/source/slang/ir.h index 319340024..fcebf5d15 100644 --- a/source/slang/ir.h +++ b/source/slang/ir.h @@ -69,6 +69,22 @@ struct IRUse void init(IRInst* user, IRInst* usedValue); }; +enum IRDecorationOp : uint16_t +{ + kIRDecorationOp_HighLevelDecl, +}; + +// A "decoration" that gets applied to an instruction. +// These usually don't affect semantics, but are useful +// for preserving high-level source information. +struct IRDecoration +{ + // Next decoration attached to the same instruction + IRDecoration* next; + + IRDecorationOp op; +}; + typedef uint32_t IRInstID; // In the IR, almost *everything* is an instruction, @@ -99,6 +115,18 @@ struct IRInst // The first use of this value (start of a linked list) IRUse* firstUse; + // The linked list of decorations attached to this instruction + IRDecoration* firstDecoration; + + IRDecoration* findDecorationImpl(IRDecorationOp op); + + template + T* findDecoration() + { + return (T*) findDecorationImpl(IRDecorationOp(T::kDecorationOp)); + } + + // The type of this value IRUse type; @@ -117,8 +145,22 @@ struct IRInst } }; +// This type alias exists because I waffled on the name for a bit. +// All existing uses of `IRValue` should move to `IRInst` typedef IRInst IRValue; +class Decl; + +// Associates an IR-level decoration with a source declaration +// in the high-level AST, that can be used to extract +// additional information that informs code emission. +struct IRHighLevelDeclDecoration : IRDecoration +{ + enum { kDecorationOp = kIRDecorationOp_HighLevelDecl }; + + Decl* decl; +}; + typedef long long IRIntegerValue; typedef double IRFloatingPointValue; @@ -360,6 +402,19 @@ struct IRBuilder IRValue* val); IRInst* emitReturn(); + + IRDecoration* addDecorationImpl( + IRInst* inst, + UInt decorationSize, + IRDecorationOp op); + + template + T* addDecoration(IRInst* inst, IRDecorationOp op) + { + return (T*) addDecorationImpl(inst, sizeof(T), op); + } + + IRHighLevelDeclDecoration* addHighLevelDeclDecoration(IRInst* inst, Decl* decl); }; void dumpIR(IRModule* module); diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 5d0a40072..781209dce 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -562,6 +562,8 @@ struct DeclLoweringVisitor : DeclVisitor auto irField = builder->createStructField(getSimpleType(fieldType)); builder->addInst(irStruct, irField); + builder->addHighLevelDeclDecoration(irField, fieldDecl); + context->shared->declValues.Add( DeclRef(fieldDecl, nullptr), LoweredValInfo::simple(irField)); @@ -573,6 +575,7 @@ struct DeclLoweringVisitor : DeclVisitor } } + builder->addHighLevelDeclDecoration(irStruct, decl); builder->addInst(irStruct); @@ -624,6 +627,8 @@ struct DeclLoweringVisitor : DeclVisitor lowerStmt(subContext, decl->Body); + getBuilder()->addHighLevelDeclDecoration(irFunc, decl); + getBuilder()->addInst(irFunc); return LoweredValInfo::simple(irFunc); -- cgit v1.2.3