diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-07-10 15:40:42 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-07-11 12:07:09 -0700 |
| commit | bd7105ff8683a680d1270eca8cd74f9002144dbd (patch) | |
| tree | 2e4911b6da6573d334117a08130be5c945c31b15 /source/slang/lower.cpp | |
| parent | 672332936ad7a4610ce0595493152c117476e823 (diff) | |
Initial work on handling resources in structs during cross-compilation
- The basic idea is that during the "lowering" pass, some types (notably: aggregate types that contain resource variables) will get turned into "tuple" types, which are pseduo-types that aren't meant to survive lowering.
- An attempt to declare a variable with a tuple type expands into a tuple of declarations
- An attempt to reference such a tuple-ified variable leads to a tuple of expressions
- An attempt to extract a member from such a tuple expression will pick the appropriate sub-element
- Dereference a tuple by dereferencing the primary expression
- Expand a tuple in the argument list to a call into N arguments (by recursively flattening the tuple)
- Don't create tuple types when not generating GLSL
- Make sure to preserve the specialized type of a call expression through lowering, since emission of unchecked calls relies on that info.
- TODO: maybe the infix/prefix/postifx/select information should come in as a side-band? Should we have modifiers on expressions?
- Make sure to offset the layout for a nested field based on teh base offset of its parent variable, when generating declarations for nested fields
Diffstat (limited to 'source/slang/lower.cpp')
| -rw-r--r-- | source/slang/lower.cpp | 815 |
1 files changed, 716 insertions, 99 deletions
diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index d77e573d4..4f1342075 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -168,7 +168,7 @@ RefPtr<ExpressionSyntaxNode> structuralTransform( // // Pseudo-syntax used during lowering -class TupleDecl : public VarDeclBase +class TupleVarDecl : public VarDeclBase { public: virtual void accept(IDeclVisitor *, void *) override @@ -176,7 +176,9 @@ public: throw "unexpected"; } - List<RefPtr<VarDeclBase>> decls; + TupleTypeModifier* tupleType; + RefPtr<VarDeclBase> primaryDecl; + List<RefPtr<VarDeclBase>> tupleDecls; }; // Pseudo-syntax used during lowering: @@ -189,7 +191,19 @@ public: throw "unexpected"; } - List<RefPtr<ExpressionSyntaxNode>> exprs; + struct Element + { + DeclRef<VarDeclBase> tupleFieldDeclRef; + RefPtr<ExpressionSyntaxNode> expr; + }; + + // Optional reference to the "primary" value of the tuple, + // in the case of a tuple type with "orinary" fields + RefPtr<ExpressionSyntaxNode> primaryExpr; + + // Additional fields to store values for any non-ordinary fields + // (or fields that aren't exclusively orginary) + List<Element> tupleElements; }; struct SharedLoweringContext @@ -263,7 +277,7 @@ struct LoweringVisitor void registerReservedWords() { - #define WORD(NAME) registerReservedWord(#NAME) +#define WORD(NAME) registerReservedWord(#NAME) switch (shared->target) { @@ -355,7 +369,7 @@ struct LoweringVisitor WORD(namespace); WORD(using); - #define CASE(NAME) \ +#define CASE(NAME) \ WORD(NAME ## 2); WORD(NAME ## 3); WORD(NAME ## 4) CASE(mat); @@ -374,9 +388,9 @@ struct LoweringVisitor CASE(hvec); CASE(fvec); - #undef CASE +#undef CASE - #define CASE(NAME) \ +#define CASE(NAME) \ WORD(NAME ## 1D); \ WORD(NAME ## 2D); \ WORD(NAME ## 3D); \ @@ -389,22 +403,22 @@ struct LoweringVisitor WORD(NAME ## 2DMSArray) \ /* end */ - #define CASE2(NAME) \ +#define CASE2(NAME) \ CASE(NAME); \ CASE(i ## NAME); \ CASE(u ## NAME) \ /* end */ - CASE2(sampler); - CASE2(image); - CASE2(texture); + CASE2(sampler); + CASE2(image); + CASE2(texture); - #undef CASE2 - #undef CASE +#undef CASE2 +#undef CASE break; - default: - break; + default: + break; } } @@ -436,7 +450,7 @@ struct LoweringVisitor RefPtr<ExpressionType> lowerType( ExpressionType* type) { - if(!type) return nullptr; + if (!type) return nullptr; return TypeVisitor::dispatch(type); } @@ -546,7 +560,7 @@ struct LoweringVisitor CodePosition const& loc, VarDeclBase* decl) { - if (auto tupleDecl = dynamic_cast<TupleDecl*>(decl)) + if (auto tupleDecl = dynamic_cast<TupleVarDecl*>(decl)) { return createTupleRef(loc, tupleDecl); } @@ -561,17 +575,30 @@ struct LoweringVisitor } RefPtr<ExpressionSyntaxNode> createTupleRef( - CodePosition const& loc, - TupleDecl* decl) + CodePosition const& loc, + TupleVarDecl* decl) { RefPtr<TupleExpr> result = new TupleExpr(); result->Position = loc; result->Type.type = decl->Type.type; - for (auto dd : decl->decls) + if (auto primaryDecl = decl->primaryDecl) { - auto expr = createVarRef(loc, dd); - result->exprs.Add(expr); + result->primaryExpr = createVarRef(loc, primaryDecl); + } + + for (auto dd : decl->tupleDecls) + { + auto tupleVarMod = dd->FindModifier<TupleVarModifier>(); + assert(tupleVarMod); + auto tupleFieldMod = tupleVarMod->tupleField; + assert(tupleFieldMod); + assert(tupleFieldMod->decl); + + TupleExpr::Element elem; + elem.tupleFieldDeclRef = makeDeclRef(tupleFieldMod->decl); + elem.expr = createVarRef(loc, dd); + result->tupleElements.Add(elem); } return result; @@ -587,12 +614,12 @@ struct LoweringVisitor auto loweredDeclRef = translateDeclRef(expr->declRef); auto loweredDecl = loweredDeclRef.getDecl(); - if (auto tupleDecl = dynamic_cast<TupleDecl*>(loweredDecl)) + if (auto tupleVarDecl = dynamic_cast<TupleVarDecl*>(loweredDecl)) { // If we are referencing a declaration that got tuple-ified, // then we need to produce a tuple expression as well. - return createTupleRef(expr->Position, tupleDecl); + return createTupleRef(expr->Position, tupleVarDecl); } RefPtr<VarExpressionSyntaxNode> loweredExpr = new VarExpressionSyntaxNode(); @@ -601,23 +628,149 @@ struct LoweringVisitor return loweredExpr; } + void addArgs( + InvokeExpressionSyntaxNode* callExpr, + RefPtr<ExpressionSyntaxNode> argExpr) + { + if (auto argTuple = argExpr.As<TupleExpr>()) + { + if (argTuple->primaryExpr) + { + addArgs(callExpr, argTuple->primaryExpr); + for (auto elem : argTuple->tupleElements) + { + addArgs(callExpr, elem.expr); + } + } + } + else + { + callExpr->Arguments.Add(argExpr); + } + } + + RefPtr<ExpressionSyntaxNode> lowerCallExpr( + RefPtr<InvokeExpressionSyntaxNode> loweredExpr, + InvokeExpressionSyntaxNode* expr) + { + lowerExprCommon(loweredExpr, expr); + + loweredExpr->FunctionExpr = lowerExpr(expr->FunctionExpr); + + for (auto arg : expr->Arguments) + { + auto loweredArg = lowerExpr(arg); + addArgs(loweredExpr, loweredArg); + } + + return loweredExpr; + } + + RefPtr<ExpressionSyntaxNode> visitInvokeExpressionSyntaxNode( + InvokeExpressionSyntaxNode* expr) + { + return lowerCallExpr(new InvokeExpressionSyntaxNode(), expr); + } + + RefPtr<ExpressionSyntaxNode> visitInfixExpr( + InfixExpr* expr) + { + return lowerCallExpr(new InfixExpr(), expr); + } + + RefPtr<ExpressionSyntaxNode> visitPrefixExpr( + PrefixExpr* expr) + { + return lowerCallExpr(new PrefixExpr(), expr); + } + + RefPtr<ExpressionSyntaxNode> visitSelectExpressionSyntaxNode( + SelectExpressionSyntaxNode* expr) + { + // TODO: A tuple needs to be special-cased here + + return lowerCallExpr(new SelectExpressionSyntaxNode(), expr); + } + + RefPtr<ExpressionSyntaxNode> visitPostfixExpr( + PostfixExpr* expr) + { + return lowerCallExpr(new PostfixExpr(), expr); + } + + RefPtr<ExpressionSyntaxNode> visitDerefExpr( + DerefExpr* expr) + { + auto loweredBase = lowerExpr(expr->base); + + if (auto baseTuple = loweredBase.As<TupleExpr>()) + { + if (auto primaryExpr = baseTuple->primaryExpr) + { + RefPtr<DerefExpr> loweredPrimary = new DerefExpr(); + lowerExprCommon(loweredPrimary, expr); + loweredPrimary->base = baseTuple->primaryExpr; + baseTuple->primaryExpr = loweredPrimary; + return baseTuple; + } + } + + RefPtr<DerefExpr> loweredExpr = new DerefExpr(); + lowerExprCommon(loweredExpr, expr); + loweredExpr->base = loweredBase; + return loweredExpr; + } + RefPtr<ExpressionSyntaxNode> visitMemberExpressionSyntaxNode( MemberExpressionSyntaxNode* expr) { auto loweredBase = lowerExpr(expr->BaseExpression); + auto loweredDeclRef = translateDeclRef(expr->declRef); + // Are we extracting an element from a tuple? if (auto baseTuple = loweredBase.As<TupleExpr>()) { - // We need to find the correct member expression, - // based on the actual tuple type. + auto tupleFieldMod = loweredDeclRef.getDecl()->FindModifier<TupleFieldModifier>(); + if (tupleFieldMod) + { + // This field has a tuple part to it, so we need to search for it - throw "unimplemented"; + RefPtr<ExpressionSyntaxNode> tupleFieldExpr; + for (auto elem : baseTuple->tupleElements) + { + if (loweredDeclRef.getDecl() == elem.tupleFieldDeclRef.getDecl()) + { + tupleFieldExpr = elem.expr; + break; + } + } + + if (!tupleFieldMod->hasAnyNonTupleFields) + return tupleFieldExpr; + + auto tupleFieldTupleExpr = tupleFieldExpr.As<TupleExpr>(); + assert(tupleFieldTupleExpr); + assert(!tupleFieldTupleExpr->primaryExpr); + + + RefPtr<MemberExpressionSyntaxNode> loweredPrimaryExpr = new MemberExpressionSyntaxNode(); + lowerExprCommon(loweredPrimaryExpr, expr); + loweredPrimaryExpr->BaseExpression = baseTuple->primaryExpr; + loweredPrimaryExpr->declRef = loweredDeclRef; + loweredPrimaryExpr->name = expr->name; + + tupleFieldTupleExpr->primaryExpr = loweredPrimaryExpr; + return tupleFieldTupleExpr; + } + + // If the field was a non-tupe field, then we can + // simply fall through to the ordinary case below. + loweredBase = baseTuple->primaryExpr; } // Default handling: - auto loweredDeclRef = translateDeclRef(expr->declRef); - assert(!dynamic_cast<TupleDecl*>(loweredDeclRef.getDecl())); + assert(!dynamic_cast<TupleVarDecl*>(loweredDeclRef.getDecl())); RefPtr<MemberExpressionSyntaxNode> loweredExpr = new MemberExpressionSyntaxNode(); lowerExprCommon(loweredExpr, expr); @@ -640,7 +793,7 @@ struct LoweringVisitor RefPtr<StatementSyntaxNode> lowerStmt( StatementSyntaxNode* stmt) { - if(!stmt) + if (!stmt) return nullptr; LoweringVisitor subVisitor = *this; @@ -648,7 +801,7 @@ struct LoweringVisitor subVisitor.lowerStmtImpl(stmt); - if( !subVisitor.stmtBeingBuilt ) + if (!subVisitor.stmtBeingBuilt) { return new EmptyStatementSyntaxNode(); } @@ -675,11 +828,11 @@ struct LoweringVisitor StatementSyntaxNode* translateStmtRef( StatementSyntaxNode* originalStmt) { - if(!originalStmt) return nullptr; + if (!originalStmt) return nullptr; - for( auto state = &stmtLoweringState; state; state = state->parent ) + for (auto state = &stmtLoweringState; state; state = state->parent) { - if(state->originalStmt == originalStmt) + if (state->originalStmt == originalStmt) return state->loweredStmt; } @@ -723,7 +876,7 @@ struct LoweringVisitor StatementSyntaxNode* stmt) { // add a statement to the code we are building... - if( !dest ) + if (!dest) { dest = stmt; return; @@ -782,7 +935,7 @@ struct LoweringVisitor void visitSeqStmt(SeqStmt* stmt) { - for( auto ss : stmt->stmts ) + for (auto ss : stmt->stmts) { lowerStmtImpl(ss); } @@ -885,9 +1038,9 @@ struct LoweringVisitor RefPtr<IfStatementSyntaxNode> loweredStmt = new IfStatementSyntaxNode(); lowerStmtFields(loweredStmt, stmt); - loweredStmt->Predicate = lowerExpr(stmt->Predicate); - loweredStmt->PositiveStatement = lowerStmt(stmt->PositiveStatement); - loweredStmt->NegativeStatement = lowerStmt(stmt->NegativeStatement); + loweredStmt->Predicate = lowerExpr(stmt->Predicate); + loweredStmt->PositiveStatement = lowerStmt(stmt->PositiveStatement); + loweredStmt->NegativeStatement = lowerStmt(stmt->NegativeStatement); addStmt(loweredStmt); } @@ -899,8 +1052,8 @@ struct LoweringVisitor LoweringVisitor subVisitor = pushScope(loweredStmt, stmt); - loweredStmt->condition = subVisitor.lowerExpr(stmt->condition); - loweredStmt->body = subVisitor.lowerStmt(stmt->body); + loweredStmt->condition = subVisitor.lowerExpr(stmt->condition); + loweredStmt->body = subVisitor.lowerStmt(stmt->body); addStmt(loweredStmt); } @@ -913,10 +1066,10 @@ struct LoweringVisitor LoweringVisitor subVisitor = pushScope(loweredStmt, stmt); - loweredStmt->InitialStatement = subVisitor.lowerStmt(stmt->InitialStatement); - loweredStmt->SideEffectExpression = subVisitor.lowerExpr(stmt->SideEffectExpression); - loweredStmt->PredicateExpression = subVisitor.lowerExpr(stmt->PredicateExpression); - loweredStmt->Statement = subVisitor.lowerStmt(stmt->Statement); + loweredStmt->InitialStatement = subVisitor.lowerStmt(stmt->InitialStatement); + loweredStmt->SideEffectExpression = subVisitor.lowerExpr(stmt->SideEffectExpression); + loweredStmt->PredicateExpression = subVisitor.lowerExpr(stmt->PredicateExpression); + loweredStmt->Statement = subVisitor.lowerStmt(stmt->Statement); addStmt(loweredStmt); } @@ -938,8 +1091,8 @@ struct LoweringVisitor LoweringVisitor subVisitor = pushScope(loweredStmt, stmt); - loweredStmt->Predicate = subVisitor.lowerExpr(stmt->Predicate); - loweredStmt->Statement = subVisitor.lowerStmt(stmt->Statement); + loweredStmt->Predicate = subVisitor.lowerExpr(stmt->Predicate); + loweredStmt->Statement = subVisitor.lowerStmt(stmt->Statement); addStmt(loweredStmt); } @@ -951,8 +1104,8 @@ struct LoweringVisitor LoweringVisitor subVisitor = pushScope(loweredStmt, stmt); - loweredStmt->Statement = subVisitor.lowerStmt(stmt->Statement); - loweredStmt->Predicate = subVisitor.lowerExpr(stmt->Predicate); + loweredStmt->Statement = subVisitor.lowerStmt(stmt->Statement); + loweredStmt->Predicate = subVisitor.lowerExpr(stmt->Predicate); addStmt(loweredStmt); } @@ -1057,10 +1210,10 @@ struct LoweringVisitor return result; } - RefPtr<Decl> translateDeclRef( + RefPtr<Decl> translateDeclRef( Decl* decl) { - if (!decl) return nullptr; + if (!decl) return nullptr; // We don't want to translate references to built-in declarations, // since they won't be subtituted anyway. @@ -1069,7 +1222,7 @@ struct LoweringVisitor // If any parent of the declaration was in the stdlib, then // we need to skip it. - for(auto pp = decl; pp; pp = pp->ParentDecl) + for (auto pp = decl; pp; pp = pp->ParentDecl) { if (pp->HasModifier<FromStdLibModifier>()) return decl; @@ -1086,11 +1239,11 @@ struct LoweringVisitor return lowerDecl(decl); } - RefPtr<ContainerDecl> translateDeclRef( - ContainerDecl* decl) - { - return translateDeclRef((Decl*)decl).As<ContainerDecl>(); - } + RefPtr<ContainerDecl> translateDeclRef( + ContainerDecl* decl) + { + return translateDeclRef((Decl*)decl).As<ContainerDecl>(); + } RefPtr<DeclBase> lowerDeclBase( DeclBase* declBase) @@ -1123,7 +1276,10 @@ struct LoweringVisitor void addDecl( Decl* decl) { - if(isBuildingStmt) + if (!decl) + return; + + if (isBuildingStmt) { RefPtr<VarDeclrStatementSyntaxNode> declStmt = new VarDeclrStatementSyntaxNode(); declStmt->Position = decl->Position; @@ -1184,6 +1340,31 @@ struct LoweringVisitor } } + RefPtr<VarLayout> tryToFindLayout( + Decl* decl) + { + auto loweredParent = translateDeclRef(decl->ParentDecl); + if (loweredParent) + { + auto layoutMod = loweredParent->FindModifier<ComputedLayoutModifier>(); + if (layoutMod) + { + auto parentLayout = layoutMod->layout; + if (auto structLayout = parentLayout.As<StructTypeLayout>()) + { + RefPtr<VarLayout> fieldLayout; + if (structLayout->mapVarToLayout.TryGetValue(decl, fieldLayout)) + { + return fieldLayout; + } + } + + // TODO: are there other cases to handle here? + } + } + return nullptr; + } + void lowerDeclCommon( Decl* loweredDecl, Decl* decl) @@ -1205,24 +1386,9 @@ struct LoweringVisitor // deal with layout stuff - auto loweredParent = translateDeclRef(decl->ParentDecl); - if (loweredParent) + if (auto fieldLayout = tryToFindLayout(decl)) { - auto layoutMod = loweredParent->FindModifier<ComputedLayoutModifier>(); - if (layoutMod) - { - auto parentLayout = layoutMod->layout; - if (auto structLayout = parentLayout.As<StructTypeLayout>()) - { - RefPtr<VarLayout> fieldLayout; - if (structLayout->mapVarToLayout.TryGetValue(decl, fieldLayout)) - { - attachLayout(loweredDecl, fieldLayout); - } - } - - // TODO: are there other cases to handle here? - } + attachLayout(loweredDecl, fieldLayout); } } @@ -1297,7 +1463,7 @@ struct LoweringVisitor return loweredDecl; } - RefPtr<ImportDecl> visitImportDecl(ImportDecl* decl) + RefPtr<ImportDecl> visitImportDecl(ImportDecl*) { // We could unconditionally output the declarations in the // imported code, but this could cause problems if any @@ -1336,6 +1502,35 @@ struct LoweringVisitor return loweredDecl; } + TupleTypeModifier* isTupleType(ExpressionType* type) + { + if (auto declRefType = type->As<DeclRefType>()) + { + if (auto tupleTypeMod = declRefType->declRef.getDecl()->FindModifier<TupleTypeModifier>()) + { + return tupleTypeMod; + } + } + + return nullptr; + } + + bool isResourceType(ExpressionType* type) + { + if (auto textureTypeBase = type->As<TextureTypeBase>()) + { + return true; + } + else if (auto samplerType = type->As<SamplerStateType>()) + { + return true; + } + + // TODO: need more comprehensive coverage here + + return false; + } + RefPtr<Decl> visitAggTypeDecl(AggTypeDecl* decl) { // We want to lower any aggregate type declaration @@ -1344,19 +1539,103 @@ struct LoweringVisitor // Any non-field members (e.g., methods) will be // lowered separately. - // TODO: also need to figure out how to handle fields - // with types that should not be allowed in a `struct` - // for the chosen target. - // (also: what to do if there are no fields left - // after removing invalid ones?) - RefPtr<StructSyntaxNode> loweredDecl = new StructSyntaxNode(); lowerDeclCommon(loweredDecl, decl); + // We need to be ready to turn this type into a "tuple" type, + // if it has any members that can't normally be kept in a `struct` + // + // We don't want to do this unconditionally, though, because + // then we'll end up changing the meaning of user code in + // languages like HLSL that support such nesting. + + bool shouldDesugarTupleTypes = false; + if (getTarget() == CodeGenTarget::GLSL) + { + // Always desugar this stuff for GLSL, since it doesn't + // support nesting of resources in structs. + // + // TODO: Need a way to make this more fine-grained to + // handle cases where a nested member might be allowed + // due to, e.g., bindless textures. + shouldDesugarTupleTypes = true; + } + + bool isResultATupleType = false; + bool hasAnyNonTupleFields = false; + for (auto field : decl->getMembersOfType<VarDeclBase>()) { - // TODO: anything more to do than this? - addMember(loweredDecl, translateDeclRef(field)); + // We lower the field, which will involve lowering the field type + auto loweredField = translateDeclRef(field).As<VarDeclBase>(); + + // Add the field to the result declaration + addMember(loweredDecl, loweredField); + + // Don't consider any of the following desugaring logic, + // if we aren't supposed to be desugaring this type + if (!shouldDesugarTupleTypes) + { + hasAnyNonTupleFields = true; + continue; + } + + // If the field is of a type that requires special handling, + // we need to make a note of it. + auto loweredFieldType = loweredField->Type.type; + bool isTupleField = false; + bool fieldHasAnyNonTupleFields = false; + bool fieldHasTupleType = false; + if (auto fieldTupleTypeMod = isTupleType(loweredFieldType)) + { + isTupleField = true; + fieldHasTupleType = true; + if (fieldTupleTypeMod->hasAnyNonTupleFields) + { + fieldHasAnyNonTupleFields = true; + hasAnyNonTupleFields = true; + } + } + if (isResourceType(loweredFieldType)) + { + isTupleField = true; + } + else + { + hasAnyNonTupleFields = true; + } + + if (isTupleField) + { + isResultATupleType = true; + + RefPtr<TupleFieldModifier> tupleFieldMod = new TupleFieldModifier(); + tupleFieldMod->decl = loweredField; + tupleFieldMod->hasAnyNonTupleFields = fieldHasAnyNonTupleFields; + tupleFieldMod->isNestedTuple = fieldHasTupleType; + + addModifier(loweredField, tupleFieldMod); + } + } + + // An empty `struct` must be treated as a tuple type, + // in order to ensure that we don't mess up layout logic + // + // (Also, GLSL doesn't allow empty structs IIRC) + // + // Note: in this one case we are desugaring things even + // when targetting HLSL, just to keep things manageable. + if (!hasAnyNonTupleFields) + { + isResultATupleType = true; + } + + if (isResultATupleType) + { + RefPtr<TupleTypeModifier> tupleTypeMod = new TupleTypeModifier(); + tupleTypeMod->decl = loweredDecl; + tupleTypeMod->hasAnyNonTupleFields = hasAnyNonTupleFields; + addModifier(loweredDecl, tupleTypeMod); } addMember( @@ -1366,17 +1645,351 @@ struct LoweringVisitor return loweredDecl; } - RefPtr<VarDeclBase> lowerVarDeclCommon( + RefPtr<VarDeclBase> lowerSimpleVarDeclCommon( RefPtr<VarDeclBase> loweredDecl, - VarDeclBase* decl) + VarDeclBase* decl, + TypeExp const& loweredType) { lowerDeclCommon(loweredDecl, decl); - loweredDecl->Type = lowerType(decl->Type); + loweredDecl->Type = loweredType; loweredDecl->Expr = lowerExpr(decl->Expr); return loweredDecl; } + RefPtr<VarDeclBase> lowerSimpleVarDeclCommon( + RefPtr<VarDeclBase> loweredDecl, + VarDeclBase* decl) + { + auto loweredType = lowerType(decl->Type); + return lowerSimpleVarDeclCommon(loweredDecl, decl, loweredType); + } + + void createTupleTypeSecondaryVarDecls( + RefPtr<TupleVarDecl> tupleDecl, + SyntaxClass<VarDeclBase> varDeclClass, + String const& name, + RefPtr<ExpressionType> tupleType, + DeclRef<AggTypeDecl> tupleTypeDecl, + RefPtr<ExpressionSyntaxNode> initExpr, + RefPtr<VarLayout> primaryVarLayout, + RefPtr<StructTypeLayout> tupleTypeLayout) + { + // Next, we need to go through the declarations in the aggregate + // type, and deal with all of those that should be tuple-ified. + for (auto dd : getMembersOfType<VarDeclBase>(tupleTypeDecl)) + { + if (dd.getDecl()->HasModifier<HLSLStaticModifier>()) + continue; + + auto tupleFieldMod = dd.getDecl()->FindModifier<TupleFieldModifier>(); + if (!tupleFieldMod) + continue; + + // TODO: need to extract the initializer for this field + assert(!initExpr); + RefPtr<ExpressionSyntaxNode> fieldInitExpr; + + String fieldName = name + "_" + dd.GetName(); + + auto fieldType = GetType(dd); + + Decl* originalFieldDecl; + shared->mapLoweredDeclToOriginal.TryGetValue(dd, originalFieldDecl); + assert(originalFieldDecl); + + RefPtr<VarLayout> fieldLayout; + if(tupleTypeLayout) + { + tupleTypeLayout->mapVarToLayout.TryGetValue(originalFieldDecl, fieldLayout); + } + if (fieldLayout && primaryVarLayout) + { + // The layout for a field may need to be adjusted + // based on a base offset stored in the primary + // variable. + // + // For example, if the primary variable was recoreded + // to start at descriptor-table slot N, then the + // field layout might say it uses slot k, but that + // needs to be understood relative to the parent, + // so we want slot N + k... and actuall N + k + 1, + // in the case where the parent itself took up + // space of that type... + + bool needsOffset = false; + for (auto rr : fieldLayout->resourceInfos) + { + if (auto parentInfo = primaryVarLayout->FindResourceInfo(rr.kind)) + { + if (parentInfo->index != 0 || parentInfo->space != 0) + { + needsOffset = true; + break; + } + + // Even if the base offset of the parent is zero, we may still + // need to offset the child, because the parent consumes a + // resources of the same kind... + if (primaryVarLayout->typeLayout->type->As<UniformParameterBlockType>()) + { + switch (rr.kind) + { + default: + break; + + case LayoutResourceKind::ConstantBuffer: + case LayoutResourceKind::DescriptorTableSlot: + needsOffset = true; + break; + } + if (needsOffset) + break; + } + } + } + if (needsOffset) + { + RefPtr<VarLayout> newFieldLayout = new VarLayout(); + newFieldLayout->typeLayout = fieldLayout->typeLayout; + newFieldLayout->flags = fieldLayout->flags; + newFieldLayout->varDecl = fieldLayout->varDecl; + newFieldLayout->systemValueSemantic = fieldLayout->systemValueSemantic; + newFieldLayout->systemValueSemanticIndex = fieldLayout->systemValueSemanticIndex; + + for (auto resInfo : fieldLayout->resourceInfos) + { + auto newResInfo = newFieldLayout->findOrAddResourceInfo(resInfo.kind); + newResInfo->index = resInfo.index; + newResInfo->space = resInfo.space; + if (auto parentInfo = primaryVarLayout->FindResourceInfo(resInfo.kind)) + { + newResInfo->index += parentInfo->index; + newResInfo->space += parentInfo->space; + + // Very special-case hack to deal with the case where the parent + // itself consumes a resources of the same type as the field. + if (primaryVarLayout->typeLayout->type->As<UniformParameterBlockType>()) + { + switch (resInfo.kind) + { + default: + break; + + case LayoutResourceKind::ConstantBuffer: + case LayoutResourceKind::DescriptorTableSlot: + newResInfo->index += 1; + break; + } + } + } + } + + fieldLayout = newFieldLayout; + } + + } + + RefPtr<VarDeclBase> fieldVarOrTupleDecl; + if (auto fieldTupleTypeMod = isTupleType(fieldType)) + { + // If the field is itself a tuple, then recurse + RefPtr<TupleVarDecl> fieldTupleDecl = new TupleVarDecl(); + fieldTupleDecl->tupleType = fieldTupleTypeMod; + createTupleTypeSecondaryVarDecls( + fieldTupleDecl, + varDeclClass, + fieldName, + fieldType, + makeDeclRef(fieldTupleTypeMod->decl), + fieldInitExpr, + fieldLayout, + getBodyStructTypeLayout(fieldLayout->typeLayout)); + + fieldVarOrTupleDecl = fieldTupleDecl; + } + else + { + // Otherwise the field has a simple type, and we just need to declare the variable here + RefPtr<VarDeclBase> fieldVarDecl = varDeclClass.createInstance(); + fieldVarDecl->Name.Content = fieldName; + fieldVarDecl->Type.type = fieldType; + + addDecl(fieldVarDecl); + + if (fieldLayout) + { + RefPtr<ComputedLayoutModifier> layoutMod = new ComputedLayoutModifier(); + layoutMod->layout = fieldLayout; + addModifier(fieldVarDecl, layoutMod); + } + + fieldVarOrTupleDecl = fieldVarDecl; + } + + RefPtr<TupleVarModifier> fieldTupleVarMod = new TupleVarModifier(); + fieldTupleVarMod->tupleField = tupleFieldMod; + addModifier(fieldVarOrTupleDecl, fieldTupleVarMod); + + tupleDecl->tupleDecls.Add(fieldVarOrTupleDecl); + } + } + + RefPtr<VarDeclBase> createTupleTypeVarDecls( + SyntaxClass<VarDeclBase> varDeclClass, + RefPtr<VarDeclBase> originalVarDecl, + String const& name, + RefPtr<ExpressionType> tupleType, + DeclRef<AggTypeDecl> tupleTypeDecl, + TupleTypeModifier* tupleTypeMod, + RefPtr<ExpressionSyntaxNode> initExpr, + RefPtr<VarLayout> primaryVarLayout, + RefPtr<StructTypeLayout> tupleTypeLayout) + { + // Not handling initializers just yet... + assert(!initExpr); + + // We'll need a placeholder declaration to wrap the whole thing up: + RefPtr<TupleVarDecl> tupleDecl = new TupleVarDecl(); + tupleDecl->Name.Content = name; + + // First, if the tuple type had any "ordinary" data, + // then we go ahead and create a declaration for that stuff + if (tupleTypeMod->hasAnyNonTupleFields) + { + RefPtr<VarDeclBase> primaryVarDecl = varDeclClass.createInstance(); + primaryVarDecl->Name.Content = name; + primaryVarDecl->Type.type = tupleType; + + primaryVarDecl->modifiers = originalVarDecl->modifiers; + + tupleDecl->primaryDecl = primaryVarDecl; + + if (primaryVarLayout) + { + RefPtr<ComputedLayoutModifier> layoutMod = new ComputedLayoutModifier(); + layoutMod->layout = primaryVarLayout; + addModifier(primaryVarDecl, layoutMod); + } + + addDecl(primaryVarDecl); + } + + createTupleTypeSecondaryVarDecls( + tupleDecl, + varDeclClass, + name, + tupleType, + tupleTypeDecl, + initExpr, + primaryVarLayout, + tupleTypeLayout); + + return tupleDecl; + } + + RefPtr<StructTypeLayout> getBodyStructTypeLayout(RefPtr<TypeLayout> typeLayout) + { + if (!typeLayout) + return nullptr; + + while (auto parameterBlockTypeLayout = typeLayout.As<ParameterBlockTypeLayout>()) + { + typeLayout = parameterBlockTypeLayout->elementTypeLayout; + } + + if (auto structTypeLayout = typeLayout.As<StructTypeLayout>()) + { + return structTypeLayout; + } + + return nullptr; + } + + RefPtr<VarDeclBase> createTupleTypeVarDecls( + SyntaxClass<VarDeclBase> varDeclClass, + RefPtr<VarDeclBase> originalVarDecl, + String const& name, + RefPtr<ExpressionType> tupleType, + TupleTypeModifier* tupleTypeMod, + RefPtr<ExpressionSyntaxNode> initExpr, + RefPtr<VarLayout> primaryVarLayout) + { + RefPtr<StructTypeLayout> tupleTypeLayout; + if (primaryVarLayout) + { + auto primaryTypeLayout = primaryVarLayout->typeLayout; + tupleTypeLayout = getBodyStructTypeLayout(primaryTypeLayout); + } + + return createTupleTypeVarDecls( + varDeclClass, + originalVarDecl, + name, + tupleType, + makeDeclRef(tupleTypeMod->decl), + tupleTypeMod, + initExpr, + primaryVarLayout, + tupleTypeLayout); + } + + RefPtr<VarDeclBase> lowerVarDeclCommon( + VarDeclBase* decl, + SyntaxClass<VarDeclBase> loweredDeclClass) + { + auto loweredType = lowerType(decl->Type); + + if (auto tupleTypeMod = isTupleType(loweredType)) + { + auto varLayout = tryToFindLayout(decl).As<VarLayout>(); + + // The type for the variable is a "tuple type" + // so we need to go ahead and create multiple variables + // to represent it. + + // If the variable had an initializer, we expect it + // to resolve to a tuple *value* + auto loweredInit = lowerExpr(decl->Expr); + + // TODO: need to extract layout here and propagate it down! + + auto tupleDecl = createTupleTypeVarDecls( + loweredDeclClass, + decl, + decl->getName(), + loweredType.type, + tupleTypeMod, + loweredInit, + varLayout); + + shared->loweredDecls.Add(decl, tupleDecl); + return nullptr; + } + if (auto bufferType = loweredType->As<UniformParameterBlockType>()) + { + auto varLayout = tryToFindLayout(decl).As<VarLayout>(); + + auto elementType = bufferType->elementType; + if (auto elementTupleTypeMod = isTupleType(elementType)) + { + auto tupleDecl = createTupleTypeVarDecls( + loweredDeclClass, + decl, + decl->getName(), + loweredType.type, + elementTupleTypeMod, + nullptr, + varLayout); + + shared->loweredDecls.Add(decl, tupleDecl); + return nullptr; + } + } + + RefPtr<VarDeclBase> loweredDecl = loweredDeclClass.createInstance(); + return lowerSimpleVarDeclCommon(loweredDecl, decl, loweredType); + } SourceLanguage getSourceLanguage(ProgramSyntaxNode* moduleDecl) { @@ -1398,7 +2011,9 @@ struct LoweringVisitor RefPtr<VarDeclBase> visitVariable( Variable* decl) { - auto loweredDecl = lowerVarDeclCommon(new Variable(), decl); + auto loweredDecl = lowerVarDeclCommon(decl, getClass<Variable>()); + if(!loweredDecl) + return nullptr; // We need to add things to an appropriate scope, based on what // we are referencing. @@ -1426,13 +2041,15 @@ struct LoweringVisitor RefPtr<VarDeclBase> visitStructField( StructField* decl) { - return lowerVarDeclCommon(new StructField(), decl); + return lowerSimpleVarDeclCommon(new StructField(), decl); } RefPtr<VarDeclBase> visitParameterSyntaxNode( ParameterSyntaxNode* decl) { - return lowerVarDeclCommon(new ParameterSyntaxNode(), decl); + auto loweredDecl = lowerVarDeclCommon(decl, getClass<ParameterSyntaxNode>()); + addDecl(loweredDecl); + return loweredDecl; } RefPtr<DeclBase> transformSyntaxField(DeclBase* decl) @@ -1460,24 +2077,24 @@ struct LoweringVisitor lowerDeclCommon(loweredDecl, decl); // TODO: push scope for parent decl here... + LoweringVisitor subVisitor = *this; + subVisitor.parentDecl = loweredDecl; - // TODO: need to copy over relevant modifiers + // If we are a being called recurisvely, then we need to + // be careful not to let the context get polluted + subVisitor.resultVariable = nullptr; + subVisitor.stmtBeingBuilt = nullptr; + subVisitor.isBuildingStmt = false; for (auto paramDecl : decl->GetParameters()) { - addMember(loweredDecl, translateDeclRef(paramDecl)); + subVisitor.translateDeclRef(paramDecl); } - auto loweredReturnType = lowerType(decl->ReturnType); + auto loweredReturnType = subVisitor.lowerType(decl->ReturnType); loweredDecl->ReturnType = loweredReturnType; - // If we are a being called recurisvely, then we need to - // be careful not to let the context get polluted - LoweringVisitor subVisitor = *this; - subVisitor.resultVariable = nullptr; - subVisitor.stmtBeingBuilt = nullptr; - loweredDecl->Body = subVisitor.lowerStmt(decl->Body); // A lowered function always becomes a global-scope function, |
