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(-) 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