From 31993854b164fb6e19e449b7be550b1e48297ef5 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Mon, 27 Nov 2017 16:33:28 -0800 Subject: Cleanups (#298) * Rename `lower.{h,cpp}` to `ast-legalize.{h,cpp}` This pass isn't really performing lowering akin to `lower-to-ir.{h,cpp}` so the file name is misleading. By renaming this pass we emphasize its role as an AST-related pass. Also update the comment at the top of `ast-legalize.h` to reflect the intended purpose of this pass in a world where we have the IR up and running. * Allow `import` as an alias for `__import` The use of double underscores to mark our new syntax has so far had two purposes: 1. It helps identify syntax that isn't meant to be exposed to users in its current form (e.g., `__generic` gets a double underscore because we want users to have a more pleasant surface syntax for generics that they write). This rationale doesn't apply to `__import`, which is a major language feature that users need to interact with. 2. It helps avoid the problem where the compiler treats something as a keyword that isn't supposed to be reserved in HLSL/GLSL and so causes existing user code to fail to parse (e.g., when the user tries to write a function called `import`). This no longer matters because we look up almost all of our keywords using the existing lexical scoping in the language (so the user can shadow almost any keyword with a local declaration). So, neither of the original two reasons applies to `__import`, and it makes sense to expose it as `import`. Doing so is a one-line change. --- source/slang/lower.cpp | 4732 ------------------------------------------------ 1 file changed, 4732 deletions(-) delete mode 100644 source/slang/lower.cpp (limited to 'source/slang/lower.cpp') diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp deleted file mode 100644 index 5a6603add..000000000 --- a/source/slang/lower.cpp +++ /dev/null @@ -1,4732 +0,0 @@ -// lower.cpp -#include "lower.h" - -#include "emit.h" -#include "type-layout.h" -#include "visitor.h" - -// DEBUGGING -#if 0 -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include -#undef WIN32_LEAN_AND_MEAN -#undef NOMINMAX -#endif -#endif - - - -namespace Slang -{ - -struct CloneVisitor - : ModifierVisitor> -{ -#define ABSTRACT_SYNTAX_CLASS(NAME, BASE) /* empty */ -#define SYNTAX_CLASS(NAME, BASE, ...) \ - RefPtr visit ## NAME(NAME* obj) { return new NAME(*obj); } - -#include "object-meta-begin.h" -#include "modifier-defs.h" -#include "object-meta-end.h" - -}; - -// - -// - -class TupleExpr; -class TupleVarDecl; -class VaryingTupleExpr; -class VaryingTupleVarDecl; - - -// The result of lowering a declaration will usually be a declaration, -// but it might also be a "tuple" declaration, in cases where we needed -// to sclarize (or partially scalarize) things to guarantee validity. -struct LoweredDecl -{ - enum class Flavor - { - Decl, // A single declaration (the default case) - Tuple, // A `TupleVarDecl` representing multiple decls - VaryingTuple, // A `VaryingTupleVarDecl` representing multiple decls - }; - - LoweredDecl() - : flavor(Flavor::Decl) - {} - - LoweredDecl(Decl* decl) - : value(decl) - , flavor(Flavor::Decl) - {} - - LoweredDecl(TupleVarDecl* decl) - : value((RefObject*) decl) - , flavor(Flavor::Tuple) - {} - - LoweredDecl(VaryingTupleVarDecl* decl) - : value((RefObject*) decl) - , flavor(Flavor::VaryingTuple) - {} - - Flavor getFlavor() const { return flavor; } - RefObject* getValue() const { return value; } - - Decl* getDecl() const - { - SLANG_ASSERT(getFlavor() == Flavor::Decl); - return (Decl*) value.Ptr(); - } - - TupleVarDecl* getTupleDecl() const - { - SLANG_ASSERT(getFlavor() == Flavor::Tuple); - return (TupleVarDecl*) value.Ptr(); - } - - VaryingTupleVarDecl* getVaryingTupleDecl() const - { - SLANG_ASSERT(getFlavor() == Flavor::VaryingTuple); - return (VaryingTupleVarDecl*) value.Ptr(); - } - - Decl* asDecl() const - { - return (getFlavor() == Flavor::Decl) ? getDecl() : nullptr; - } - - TupleVarDecl* asTupleDecl() const - { - return (getFlavor() == Flavor::Tuple) ? getTupleDecl() : nullptr; - } - - VaryingTupleVarDecl* asVaryingTupleDecl() const - { - return (getFlavor() == Flavor::VaryingTuple) ? getVaryingTupleDecl() : nullptr; - } - -private: - RefPtr value; - Flavor flavor; -}; - -struct LoweredDeclRef -{ -public: - LoweredDecl decl; - RefPtr substitutions; - - LoweredDecl getDecl() { return decl; } - - template - DeclRef As() - { - return DeclRef(decl.getDecl(), substitutions).As(); - } -}; - -// - -template -struct StructuralTransformVisitorBase -{ - V* visitor; - - RefPtr transformDeclField(Stmt* stmt) - { - return visitor->translateStmtRef(stmt); - } - - RefPtr transformDeclField(Decl* decl) - { - return visitor->translateDeclRef(decl); - } - - template - DeclRef transformDeclField(DeclRef const& decl) - { - LoweredDeclRef declRef = visitor->translateDeclRef(decl); - return declRef.As(); - } - - TypeExp transformSyntaxField(TypeExp const& typeExp) - { - TypeExp result; - result.type = visitor->transformSyntaxField(typeExp.type); - return result; - } - - QualType transformSyntaxField(QualType const& qualType) - { - QualType result = qualType; - result.type = visitor->transformSyntaxField(qualType.type); - return result; - } - - RefPtr transformSyntaxField(Expr* expr) - { - return visitor->transformSyntaxField(expr); - } - - RefPtr transformSyntaxField(Stmt* stmt) - { - return visitor->transformSyntaxField(stmt); - } - - RefPtr transformSyntaxField(DeclBase* decl) - { - return visitor->transformSyntaxField(decl); - } - - RefPtr transformSyntaxField(ScopeDecl* decl) - { - if(!decl) return nullptr; - RefPtr transformed = visitor->transformSyntaxField(decl); - return transformed.As(); - } - - template - List transformSyntaxField(List const& list) - { - List result; - for (auto item : list) - { - result.Add(transformSyntaxField(item)); - } - return result; - } -}; - -#if 0 -template -RefPtr structuralTransform( - Stmt* stmt, - V* visitor) -{ - StructuralTransformStmtVisitor transformer; - transformer.visitor = visitor; - return transformer.dispatch(stmt); -} -#endif - -template -struct StructuralTransformExprVisitor - : StructuralTransformVisitorBase - , ExprVisitor, RefPtr> -{ - void transformFields(Expr* result, Expr* obj) - { - result->type = this->transformSyntaxField(obj->type); - } - -#define ABSTRACT_SYNTAX_CLASS(NAME, BASE, ...) \ - void transformFields(NAME* result, NAME* obj) { \ - this->transformFields((BASE*) result, (BASE*) obj); \ - /* end */ - - -#define SYNTAX_CLASS(NAME, BASE, ...) \ - RefPtr visit##NAME(NAME* obj) { \ - RefPtr result = new NAME(*obj); \ - transformFields(result, obj); \ - return result; \ - } \ - ABSTRACT_SYNTAX_CLASS(NAME, BASE) \ - /* end */ - -#define SYNTAX_FIELD(TYPE, NAME) result->NAME = this->transformSyntaxField(obj->NAME); -#define DECL_FIELD(TYPE, NAME) result->NAME = this->transformDeclField(obj->NAME); - -#define FIELD(TYPE, NAME) /* empty */ - -#define END_SYNTAX_CLASS() \ - } - -#include "object-meta-begin.h" -#include "expr-defs.h" -#include "object-meta-end.h" -}; - - -template -RefPtr structuralTransform( - Expr* expr, - V* visitor) -{ - StructuralTransformExprVisitor transformer; - transformer.visitor = visitor; - return transformer.dispatch(expr); -} - - - -// The result of lowering an exrpession will usually be just a single -// expression, but it might also be a "tuple" expression that encodes -// multiple expressions. -struct LoweredExpr -{ - enum class Flavor - { - Expr, - Tuple, - VaryingTuple, - }; - - LoweredExpr() - : flavor(Flavor::Expr) - {} - - LoweredExpr(Expr* expr) - : value(expr) - , flavor(Flavor::Expr) - {} - - LoweredExpr(TupleExpr* expr) - : value((RefObject*) expr) - , flavor(Flavor::Tuple) - {} - - LoweredExpr(VaryingTupleExpr* expr) - : value((RefObject*) expr) - , flavor(Flavor::VaryingTuple) - {} - - Flavor getFlavor() const { return flavor; } - - Expr* getExpr() const - { - assert(getFlavor() == Flavor::Expr); - return (Expr*)value.Ptr(); - } - - TupleExpr* getTupleExpr() const - { - assert(getFlavor() == Flavor::Tuple); - return (TupleExpr*)value.Ptr(); - } - - - VaryingTupleExpr* getVaryingTupleExpr() const - { - assert(getFlavor() == Flavor::VaryingTuple); - return (VaryingTupleExpr*)value.Ptr(); - } - - Expr* asExpr() const - { - return (getFlavor() == Flavor::Expr) ? getExpr() : nullptr; - } - - TupleExpr* asTuple() const - { - return (getFlavor() == Flavor::Tuple) ? getTupleExpr() : nullptr; - } - - VaryingTupleExpr* asVaryingTuple() const - { - return (getFlavor() == Flavor::VaryingTuple) ? getVaryingTupleExpr() : nullptr; - } - - // Allow use in boolean contexts - operator void*() - { - return value.Ptr(); - } - -private: - RefPtr value; - Flavor flavor; -}; - -// Pseudo-syntax used during lowering -class PseudoVarDecl : public RefObject -{ -public: - NameLoc nameAndLoc; - SourceLoc loc; - TypeExp type; -}; - -class TupleVarDecl : public PseudoVarDecl -{ -public: - struct Element - { - RefPtr tupleVarMod; - LoweredDecl decl; - }; - - TupleTypeModifier* tupleType; - RefPtr primaryDecl; - List tupleDecls; -}; - -class PseudoExpr : public RefObject -{ -public: - SourceLoc loc; - QualType type; -}; - -// Pseudo-syntax used during lowering: -// represents an ordered list of expressions as a single unit -class TupleExpr : public PseudoExpr -{ -public: - struct Element - { - DeclRef tupleFieldDeclRef; - LoweredExpr expr; - }; - - // Optional reference to the "primary" value of the tuple, - // in the case of a tuple type with "orinary" fields - RefPtr primaryExpr; - - // Additional fields to store values for any non-ordinary fields - // (or fields that aren't exclusively orginary) - List tupleElements; -}; - -// Pseudo-syntax used during lowering -class VaryingTupleVarDecl : public PseudoVarDecl -{ -public: - LoweredExpr expr; -}; - -// Pseudo-syntax used during lowering: -// represents an ordered list of expressions as a single unit -class VaryingTupleExpr : public PseudoExpr -{ -public: - struct Element - { - DeclRef originalFieldDeclRef; - LoweredExpr expr; - }; - - List elements; -}; - -static SourceLoc getPosition(LoweredExpr const& expr) -{ - switch (expr.getFlavor()) - { - case LoweredExpr::Flavor::Expr: return expr.getExpr() ->loc; - case LoweredExpr::Flavor::Tuple: return expr.getTupleExpr() ->loc; - case LoweredExpr::Flavor::VaryingTuple: return expr.getVaryingTupleExpr()->loc; - default: - SLANG_UNREACHABLE("all cases handled"); - UNREACHABLE_RETURN(SourceLoc()); - } -} - - -struct SharedLoweringContext -{ - CompileRequest* compileRequest; - EntryPointRequest* entryPointRequest; - - ExtensionUsageTracker* extensionUsageTracker; - - ProgramLayout* programLayout; - EntryPointLayout* entryPointLayout; - - // The target we are going to generate code for. - // - // We may need to specialize how constructs get lowered based - // on the capabilities of the target language. - CodeGenTarget target; - - // A set of words reserved by the target - HashSet reservedWords; - - - RefPtr loweredProgram; - - Dictionary loweredDecls; - Dictionary mapLoweredDeclToOriginal; - - // Work to be done at the very start and end of the entry point - RefPtr entryPointInitializeStmt; - RefPtr entryPointFinalizeStmt; - - // Counter used for generating unique temporary names - int nameCounter = 0; - - bool isRewrite = false; - bool requiresCopyGLPositionToPositionPerView = false; -}; - -static void attachLayout( - ModifiableSyntaxNode* syntax, - Layout* layout) -{ - RefPtr modifier = new ComputedLayoutModifier(); - modifier->layout = layout; - - addModifier(syntax, modifier); -} - -void requireGLSLVersion( - EntryPointRequest* entryPoint, - ProfileVersion version); - -struct LoweringVisitor - : ExprVisitor - , StmtVisitor - , DeclVisitor - , ValVisitor, RefPtr> -{ - // - SharedLoweringContext* shared; - RefPtr substitutions; - - bool isBuildingStmt = false; - RefPtr stmtBeingBuilt; - - // If we *aren't* building a statement, then this - // is the container we should be adding declarations to - RefPtr parentDecl; - - // If we are in a context where a `return` should be turned - // into assignment to a variable (followed by a `return`), - // then this will point to that variable. - RefPtr resultVariable; - - Session* getSession() - { - return shared->compileRequest->mSession; - } - - CodeGenTarget getTarget() { return shared->target; } - - bool isReservedWord(Name* name) - { - return shared->reservedWords.Contains(name); - } - - void registerReservedWord( - String const& text) - { - Name* name = shared->compileRequest->getNamePool()->getName(text); - shared->reservedWords.Add(name); - } - - void registerReservedWords() - { -#define WORD(NAME) registerReservedWord(#NAME) - - switch (shared->target) - { - case CodeGenTarget::GLSL: - WORD(attribute); - WORD(const); - WORD(uniform); - WORD(varying); - WORD(buffer); - - WORD(shared); - WORD(coherent); - WORD(volatile); - WORD(restrict); - WORD(readonly); - WORD(writeonly); - WORD(atomic_unit); - WORD(layout); - WORD(centroid); - WORD(flat); - WORD(smooth); - WORD(noperspective); - WORD(patch); - WORD(sample); - WORD(break); - WORD(continue); - WORD(do); - WORD(for); - WORD(while); - WORD(switch); - WORD(case); - WORD(default); - WORD(if); - WORD(else); - WORD(subroutine); - WORD(in); - WORD(out); - WORD(inout); - WORD(float); - WORD(double); - WORD(int); - WORD(void); - WORD(bool); - WORD(true); - WORD(false); - WORD(invariant); - WORD(precise); - WORD(discard); - WORD(return); - - WORD(lowp); - WORD(mediump); - WORD(highp); - WORD(precision); - WORD(struct); - WORD(uint); - - WORD(common); - WORD(partition); - WORD(active); - WORD(asm); - WORD(class); - WORD(union); - WORD(enum); - WORD(typedef); - WORD(template); - WORD(this); - WORD(resource); - - WORD(goto); - WORD(inline); - WORD(noinline); - WORD(public); - WORD(static); - WORD(extern); - WORD(external); - WORD(interface); - WORD(long); - WORD(short); - WORD(half); - WORD(fixed); - WORD(unsigned); - WORD(superp); - WORD(input); - WORD(output); - WORD(filter); - WORD(sizeof); - WORD(cast); - WORD(namespace); - WORD(using); - -#define CASE(NAME) \ - WORD(NAME ## 2); WORD(NAME ## 3); WORD(NAME ## 4) - - CASE(mat); - CASE(dmat); - CASE(mat2x); - CASE(mat3x); - CASE(mat4x); - CASE(dmat2x); - CASE(dmat3x); - CASE(dmat4x); - CASE(vec); - CASE(ivec); - CASE(bvec); - CASE(dvec); - CASE(uvec); - CASE(hvec); - CASE(fvec); - -#undef CASE - -#define CASE(NAME) \ - WORD(NAME ## 1D); \ - WORD(NAME ## 2D); \ - WORD(NAME ## 3D); \ - WORD(NAME ## Cube); \ - WORD(NAME ## 1DArray); \ - WORD(NAME ## 2DArray); \ - WORD(NAME ## 3DArray); \ - WORD(NAME ## CubeArray);\ - WORD(NAME ## 2DMS); \ - WORD(NAME ## 2DMSArray) \ - /* end */ - -#define CASE2(NAME) \ - CASE(NAME); \ - CASE(i ## NAME); \ - CASE(u ## NAME) \ - /* end */ - - CASE2(sampler); - CASE2(image); - CASE2(texture); - -#undef CASE2 -#undef CASE - break; - - default: - break; - } - } - - - // - // Values - // - - RefPtr lowerVal(Val* val) - { - if (!val) return nullptr; - return ValVisitor::dispatch(val); - } - - RefPtr visitGenericParamIntVal(GenericParamIntVal* val) - { - return new GenericParamIntVal(translateDeclRef(DeclRef(val->declRef)).As()); - } - - RefPtr visitConstantIntVal(ConstantIntVal* val) - { - return val; - } - - RefPtr visitWitness(Witness* witness) - { - return witness; - } - - // - // Types - // - - RefPtr lowerType( - Type* type) - { - if (!type) return nullptr; - return TypeVisitor::dispatch(type); - } - - TypeExp lowerType( - TypeExp const& typeExp) - { - TypeExp result; - result.type = lowerType(typeExp.type); - result.exp = lowerExpr(typeExp.exp); - return result; - } - - RefPtr visitIRBasicBlockType(IRBasicBlockType* type) - { - return type; - } - - - RefPtr visitErrorType(ErrorType* type) - { - return type; - } - - RefPtr visitOverloadGroupType(OverloadGroupType* type) - { - return type; - } - - RefPtr visitInitializerListType(InitializerListType* type) - { - return type; - } - - RefPtr visitGenericDeclRefType(GenericDeclRefType* type) - { - return getGenericDeclRefType( - type->getSession(), - translateDeclRef(DeclRef(type->declRef)).As()); - } - - RefPtr visitFuncType(FuncType* type) - { - RefPtr loweredType = new FuncType(); - loweredType->setSession(getSession()); - loweredType->resultType = lowerType(type->resultType); - for (auto paramType : type->paramTypes) - { - auto loweredParamType = lowerType(paramType); - - // TODO: it seems like this step needs to scalarize - // in the case where a parameter type is a tuple... - loweredType->paramTypes.Add(loweredParamType); - } - return loweredType; - } - - RefPtr visitDeclRefType(DeclRefType* type) - { - auto loweredDeclRef = translateDeclRef(type->declRef); - return DeclRefType::Create( - type->getSession(), - loweredDeclRef.As()); - } - - RefPtr visitNamedExpressionType(NamedExpressionType* type) - { - if (shared->target == CodeGenTarget::GLSL) - { - // GLSL does not support `typedef`, so we will lower it out of existence here - return lowerType(GetType(type->declRef)); - } - - return getNamedType( - type->getSession(), - translateDeclRef(DeclRef(type->declRef)).As()); - } - - RefPtr visitFilteredTupleType(FilteredTupleType* type) - { - RefPtr loweredType = new FilteredTupleType(); - loweredType->setSession(type->getSession()); - loweredType->originalType = lowerType(type->originalType); - for (auto ee : type->elements) - { - FilteredTupleType::Element element; - element.fieldDeclRef = ee.fieldDeclRef; - element.type = lowerType(ee.type); - loweredType->elements.Add(element); - } - return loweredType; - } - - RefPtr visitTypeType(TypeType* type) - { - return getTypeType(lowerType(type->type)); - } - - RefPtr visitArrayExpressionType(ArrayExpressionType* type) - { - RefPtr loweredType = Slang::getArrayType( - lowerType(type->baseType), - lowerVal(type->ArrayLength).As()); - return loweredType; - } - - RefPtr visitGroupSharedType(GroupSharedType* type) - { - return getSession()->getGroupSharedType( - lowerType(type->valueType)); - } - - RefPtr visitParameterBlockType(ParameterBlockType* type) - { - // TODO: When doing AST-to-AST lowering, we want to lower - // a `ParameterBlock` just like a `ConstantBuffer`. - // - // HACK: for now we will try to simply lower the type - // directly to its stated element type, and see how - // that works. - - return lowerType(type->getElementType()); -// return getSession()->getConstantBufferType( -// lowerType(type->getElementType()); - } - - RefPtr transformSyntaxField(Type* type) - { - return lowerType(type); - } - - RefPtr visitIRProxyVal(IRProxyVal* val) - { - return val; - } - - // - // Expressions - // - - LoweredExpr lowerExprOrTuple( - Expr* expr) - { - if (!expr) return LoweredExpr(); - return ExprVisitor::dispatch(expr); - } - - RefPtr lowerExpr( - Expr* expr) - { - if (!expr) return nullptr; - - auto result = lowerExprOrTuple(expr); - return maybeReifyTuple(result); - } - - // catch-all - LoweredExpr visitExpr( - Expr* expr) - { - return LoweredExpr(structuralTransform(expr, this)); - } - - RefPtr transformSyntaxField(Expr* expr) - { - return lowerExpr(expr); - } - - void lowerExprCommon( - Expr* loweredExpr, - Expr* expr) - { - loweredExpr->loc = expr->loc; - loweredExpr->type.type = lowerType(expr->type.type); - } - - void lowerExprCommon( - LoweredExpr const& loweredExpr, - Expr* expr) - { - if (auto simpleExpr = loweredExpr.asExpr()) - { - lowerExprCommon(simpleExpr, expr); - } - } - - RefPtr createUncheckedVarRef( - Name* name) - { - RefPtr result = new VarExpr(); - result->name = name; - return result; - } - - - RefPtr createUncheckedVarRef( - char const* name) - { - return createUncheckedVarRef( - shared->compileRequest->getNamePool()->getName(name)); - } - - RefPtr createSimpleVarRef( - SourceLoc const& loc, - VarDeclBase* decl) - { - RefPtr result = new VarExpr(); - result->loc = loc; - result->type.type = decl->type.type; - result->declRef = makeDeclRef(decl); - result->name = decl->getName(); - return result; - } - - LoweredExpr createVarRef( - SourceLoc const& loc, - LoweredDecl const& decl) - { - switch (decl.getFlavor()) - { - case LoweredDecl::Flavor::Decl: - return LoweredExpr(createSimpleVarRef(loc, decl.getDecl()->As())); - - case LoweredDecl::Flavor::Tuple: - return createTupleRef(loc, decl.getTupleDecl()); - - case LoweredDecl::Flavor::VaryingTuple: - return createVaryingTupleRef(loc, decl.getVaryingTupleDecl()); - - default: - SLANG_UNREACHABLE("all cases handled"); - UNREACHABLE_RETURN(LoweredExpr()); - } - } - - - LoweredExpr createTupleRef( - SourceLoc const& loc, - TupleVarDecl* decl) - { - RefPtr result = new TupleExpr(); - result->loc = loc; - result->type.type = decl->type.type; - - if (auto primaryDecl = decl->primaryDecl) - { - result->primaryExpr = createSimpleVarRef(loc, primaryDecl); - } - - for (auto declElem : decl->tupleDecls) - { - auto tupleVarMod = declElem.tupleVarMod; - SLANG_RELEASE_ASSERT(tupleVarMod); - auto tupleFieldMod = tupleVarMod->tupleField; - SLANG_RELEASE_ASSERT(tupleFieldMod); - SLANG_RELEASE_ASSERT(tupleFieldMod->decl); - - TupleExpr::Element elem; - elem.tupleFieldDeclRef = makeDeclRef(tupleFieldMod->decl); - elem.expr = createVarRef(loc, declElem.decl); - result->tupleElements.Add(elem); - } - - return LoweredExpr(result); - } - - LoweredExpr createVaryingTupleRef( - SourceLoc const& /*loc*/, - VaryingTupleVarDecl* decl) - { - return decl->expr; - } - - LoweredExpr visitVarExpr( - VarExpr* expr) - { - // If the expression didn't get resolved, we can leave it as-is - if (!expr->declRef) - return expr; - - auto loweredDeclRef = translateDeclRef(expr->declRef); - auto loweredDecl = loweredDeclRef.getDecl(); - - if (auto tupleVarDecl = loweredDecl.asTupleDecl()) - { - // If we are referencing a declaration that got tuple-ified, - // then we need to produce a tuple expression as well. - - return createTupleRef(expr->loc, tupleVarDecl); - } - else if (auto varyingTupleVarDecl = loweredDecl.asVaryingTupleDecl()) - { - return createVaryingTupleRef(expr->loc, varyingTupleVarDecl); - } - - RefPtr loweredExpr = new VarExpr(); - lowerExprCommon(loweredExpr, expr); - loweredExpr->declRef = loweredDeclRef.As(); - loweredExpr->name = expr->name; - return LoweredExpr(loweredExpr); - } - - LoweredExpr visitOverloadedExpr( - OverloadedExpr* expr) - { - // The presence of an overloaded expression in the output - // means that some amount of semantic checking failed. - // Thus we don't need to worry about semantically transforming - // the expression itself, but we *do* want to ensure that any - // of the declarations that the user might have been referring - // to get lowered so they will appear in the output. - for (auto item : expr->lookupResult2.items) - { - translateDeclRef(item.declRef); - } - - return expr; - } - - Name* getName(String const& text) - { - return shared->compileRequest->getNamePool()->getName(text); - } - - Name* generateName() - { - int id = shared->nameCounter++; - - String result; - result.append("SLANG_tmp_"); - result.append(id); - return getName(result); - } - - RefPtr moveTemp(RefPtr expr) - { - RefPtr varDecl = new Variable(); - varDecl->nameAndLoc.name = generateName(); - varDecl->type.type = expr->type.type; - varDecl->initExpr = expr; - - addDecl(varDecl); - - return createSimpleVarRef(expr->loc, varDecl); - } - - // The idea of this function is to take an expression that we plan to - // use/evaluate more than once, and if needed replace it with a - // reference to a temporary (initialized with the expr) so that it - // can safely be re-evaluated. - RefPtr maybeMoveTemp( - Expr* expr) - { - // TODO: actually implement this properly! - - // Certain expressions are already in a form we can directly re-use, - // so there is no reason to move them. - if (dynamic_cast(expr)) - return expr; - if (dynamic_cast(expr)) - return expr; - - // In the general case, though, we need to introduce a temporary - return moveTemp(expr); - } - - LoweredExpr maybeMoveTemp( - LoweredExpr expr) - { - if (auto tupleExpr = expr.asTuple()) - { - RefPtr resultExpr = new TupleExpr(); - resultExpr->loc = tupleExpr->loc; - resultExpr->type = tupleExpr->type; - if (tupleExpr->primaryExpr) - { - resultExpr->primaryExpr = maybeMoveTemp(tupleExpr->primaryExpr); - } - for (auto ee : tupleExpr->tupleElements) - { - TupleExpr::Element elem; - elem.tupleFieldDeclRef = ee.tupleFieldDeclRef; - elem.expr = maybeMoveTemp(ee.expr); - - resultExpr->tupleElements.Add(elem); - } - - return LoweredExpr(resultExpr); - } - else if (auto varyingTupleExpr = expr.asVaryingTuple()) - { - RefPtr resultExpr = new VaryingTupleExpr(); - resultExpr->loc = varyingTupleExpr->loc; - resultExpr->type = varyingTupleExpr->type; - for (auto ee : varyingTupleExpr->elements) - { - VaryingTupleExpr::Element elem; - elem.originalFieldDeclRef = ee.originalFieldDeclRef; - elem.expr = maybeMoveTemp(ee.expr); - - resultExpr->elements.Add(elem); - } - - return LoweredExpr(resultExpr); - } - else - { - return LoweredExpr(maybeMoveTemp(expr.getExpr())); - } - } - - // Similar to the above, this ensures that an l-value expression - // is safe to re-evaluate, by recursively moving things off - // to temporaries where needed. - RefPtr ensureSimpleLValue( - Expr* expr) - { - // TODO: actually implement this properly! - - return expr; - } - - LoweredExpr ensureSimpleLValue( - LoweredExpr expr) - { - // TODO: actually implement this properly! - - return expr; - } - - // When constructing assignment syntax, we can either - // just leave things alone, or create code that will - // try to coerce types to "fix up" differences in - // the apparent type of things. - enum class AssignMode - { - Default, - WithFixups, - }; - - RefPtr createSimpleAssignExpr( - RefPtr leftExpr, - RefPtr rightExpr) - { - RefPtr loweredExpr = new AssignExpr(); - loweredExpr->type = leftExpr->type; - loweredExpr->left = leftExpr; - loweredExpr->right = rightExpr; - return loweredExpr; - } - - RefPtr convertExprForAssignmentWithFixups( - RefPtr leftType, - RefPtr rightExpr) - { - auto rightType = rightExpr->type.type; - if (auto leftArrayType = leftType->As()) - { - // LHS type was an array - - if (auto rightVecType = rightType->As()) - { - // RHS type was a vector - if (auto leftElemVecType = leftArrayType->baseType->As()) - { - // LHS element type was also a vector, so this is a "scalar splat - // to array" case. - } - else - { - // LHS is an array of non-vectors, while RHS is a vector, - // so in this case we want to splat out the vector elements - // to create an array and use that. - rightExpr = maybeMoveTemp(rightExpr); - - RefPtr ctorExpr = new AggTypeCtorExpr(); - ctorExpr->loc = rightExpr->loc; - ctorExpr->type.type = leftType; - ctorExpr->base.type = leftType; - - int elementCount = (int) GetIntVal(rightVecType->elementCount); - for (int ee = 0; ee < elementCount; ++ee) - { - RefPtr swizzleExpr = new SwizzleExpr(); - swizzleExpr->loc = rightExpr->loc; - swizzleExpr->type.type = rightVecType->elementType; - swizzleExpr->base = rightExpr; - swizzleExpr->elementCount = 1; - swizzleExpr->elementIndices[0] = ee; - - auto convertedArgExpr = convertExprForAssignmentWithFixups( - leftArrayType->baseType, - swizzleExpr); - - ctorExpr->Arguments.Add(convertedArgExpr); - } - - return ctorExpr; - } - } - } - - // Default case: if the types didn't match, try to insert - // an explicit cast to deal with the issue. - return createCastExpr(leftType, rightExpr); - - } - - RefPtr createConstIntExpr(IntegerLiteralValue value) - { - RefPtr expr = new ConstantExpr(); - expr->type.type = getIntType(); - expr->ConstType = ConstantExpr::ConstantType::Int; - expr->integerValue = value; - return expr; - } - - struct SeqExprBuilder - { - RefPtr expr; - RefPtr* link = nullptr; - }; - - RefPtr createSimpleVarExpr(Name* name) - { - RefPtr varExpr = new VarExpr(); - varExpr->name = name; - return varExpr; - } - - RefPtr createSimpleVarExpr(char const* name) - { - return createSimpleVarExpr(getName(name)); - } - - RefPtr createSeqExpr( - RefPtr left, - RefPtr right) - { - RefPtr seqExpr = new InfixExpr(); - seqExpr->loc = left->loc; - seqExpr->type = right->type; - seqExpr->FunctionExpr = createSimpleVarExpr(","); - seqExpr->Arguments.Add(left); - seqExpr->Arguments.Add(right); - return seqExpr; - } - - void addExpr(SeqExprBuilder* builder, RefPtr expr) - { - // No expression to add? Do nothing. - if (!expr) return; - - if (!builder->expr) - { - // No expression so far? - // Set up a single-expression result. - - builder->expr = expr; - builder->link = &builder->expr; - return; - } - - // There is an existing expression, so we need to append - // to the sequence of expressions. The invariant is - // that `link` points to the last expression in the - // sequence. - - // We will extract the old last element, and construct - // a new sequence expression ("operator comma") that - // concatenates with with our new last expression. - auto oldLastExpr = *builder->link; - auto seqExpr = createSeqExpr(oldLastExpr, expr); - - // Now we need to overwrite the old last expression, - // wherever it occured in the AST (which we handily - // stored in `link`) and set our `link` to track - // the new last expression (which will be the second - // argument to our sequence expression). - *builder->link = seqExpr; - builder->link = &seqExpr->Arguments[1]; - } - - RefPtr createSimpleAssignExprWithFixups( - RefPtr leftExpr, - RefPtr rightExpr) - { - auto leftType = leftExpr->type.type; - auto rightType = rightExpr->type.type; - - // If types are unknown, or match, then just do - // things the ordinary way. - if (!leftType - || !rightType - || leftType->As() - || rightType->As() - || leftType->Equals(rightType)) - { - return createSimpleAssignExpr(leftExpr, rightExpr); - } - - // Otherwise, start to look at the types involved, - // and see if we can do something. - - if (auto leftArrayType = leftType->As()) - { - // LHS type was an array - - if (auto rightVecType = rightType->As()) - { - // RHS type was a vector - if (auto leftElemVecType = leftArrayType->baseType->As()) - { - // LHS element type was also a vector, so this is a "scalar splat - // to array" case. - } - else - { - // LHS is an array of non-vectors, while RHS is a vector, - // so in this case we want to splat out the vector elements - // to create an array and use that. - leftExpr = maybeMoveTemp(leftExpr); - rightExpr = maybeMoveTemp(rightExpr); - - SeqExprBuilder builder; - - int elementCount = (int) GetIntVal(rightVecType->elementCount); - for (int ee = 0; ee < elementCount; ++ee) - { - // LHS array element - RefPtr arrayElemExpr = new IndexExpr(); - arrayElemExpr->loc = leftExpr->loc; - arrayElemExpr->type.type = leftArrayType->baseType; - arrayElemExpr->BaseExpression = leftExpr; - arrayElemExpr->IndexExpression = createConstIntExpr(ee); - - // RHS swizzle - RefPtr swizzleExpr = new SwizzleExpr(); - swizzleExpr->loc = rightExpr->loc; - swizzleExpr->type.type = rightVecType->elementType; - swizzleExpr->base = rightExpr; - swizzleExpr->elementCount = 1; - swizzleExpr->elementIndices[0] = ee; - - auto elemAssignExpr = createSimpleAssignExprWithFixups( - arrayElemExpr, - swizzleExpr); - - addExpr(&builder, elemAssignExpr); - } - - return builder.expr; - } - } - } - - - - - // TODO: are there any cases we can't solve with a cast? - - // Try to convert the right-hand-side expression to have the type - // we expect on the left-hand side - auto convertedRightExpr = convertExprForAssignmentWithFixups(leftType, rightExpr); - return createSimpleAssignExpr(leftExpr, convertedRightExpr); - } - - RefPtr createSimpleAssignExpr( - Expr* leftExpr, - Expr* rightExpr, - AssignMode mode) - { - switch (mode) - { - default: - return createSimpleAssignExpr(leftExpr, rightExpr); - - case AssignMode::WithFixups: - return createSimpleAssignExprWithFixups(leftExpr, rightExpr); - } - } - - LoweredExpr createAssignExpr( - LoweredExpr leftExpr, - LoweredExpr rightExpr, - AssignMode mode = AssignMode::Default) - { - auto leftTuple = leftExpr.asTuple(); - auto rightTuple = rightExpr.asTuple(); - if (leftTuple && rightTuple) - { - RefPtr resultTuple = new TupleExpr(); - resultTuple->type = leftTuple->type; - - if (leftTuple->primaryExpr) - { - SLANG_RELEASE_ASSERT(rightTuple->primaryExpr); - - resultTuple->primaryExpr = createSimpleAssignExpr( - leftTuple->primaryExpr, - rightTuple->primaryExpr, - mode); - } - - auto elementCount = leftTuple->tupleElements.Count(); - SLANG_RELEASE_ASSERT(elementCount == rightTuple->tupleElements.Count()); - for (UInt ee = 0; ee < elementCount; ++ee) - { - auto leftElement = leftTuple->tupleElements[ee]; - auto rightElement = rightTuple->tupleElements[ee]; - - TupleExpr::Element resultElement; - - resultElement.tupleFieldDeclRef = leftElement.tupleFieldDeclRef; - resultElement.expr = createAssignExpr( - leftElement.expr, - rightElement.expr, - mode); - - resultTuple->tupleElements.Add(resultElement); - } - - return LoweredExpr(resultTuple); - } - else - { - SLANG_RELEASE_ASSERT(!leftTuple && !rightTuple); - } - - auto leftVaryingTuple = leftExpr.asVaryingTuple(); - auto rightVaryingTuple = rightExpr.asVaryingTuple(); - - RefPtr leftSimpleExpr = leftExpr.asExpr(); - RefPtr rightSimpleExpr = rightExpr.asExpr(); - - if (leftVaryingTuple && rightVaryingTuple) - { - RefPtr resultTuple = new VaryingTupleExpr(); - resultTuple->type.type = leftVaryingTuple->type.type; - resultTuple->loc = leftVaryingTuple->loc; - - SLANG_RELEASE_ASSERT(resultTuple->type.type); - - UInt elementCount = leftVaryingTuple->elements.Count(); - SLANG_RELEASE_ASSERT(elementCount == rightVaryingTuple->elements.Count()); - - for (UInt ee = 0; ee < elementCount; ++ee) - { - auto leftElem = leftVaryingTuple->elements[ee]; - auto rightElem = rightVaryingTuple->elements[ee]; - - VaryingTupleExpr::Element elem; - elem.originalFieldDeclRef = leftElem.originalFieldDeclRef; - elem.expr = createAssignExpr( - leftElem.expr, - rightElem.expr, - mode); - } - - return LoweredExpr(resultTuple); - } - else if (leftVaryingTuple && rightSimpleExpr) - { - // Assigning from ordinary expression on RHS to tuple. - // This will naturally yield a tuple expression. - - RefPtr resultTuple = new VaryingTupleExpr(); - resultTuple->type.type = leftVaryingTuple->type.type; - resultTuple->loc = leftVaryingTuple->loc; - - SLANG_RELEASE_ASSERT(resultTuple->type.type); - - UInt elementCount = leftVaryingTuple->elements.Count(); - - // Move everything into temps if we can - rightSimpleExpr = maybeMoveTemp(rightSimpleExpr); - for (UInt ee = 0; ee < elementCount; ++ee) - { - auto& leftElem = leftVaryingTuple->elements[ee]; - leftElem.expr = ensureSimpleLValue(leftElem.expr); - } - - // - - for (UInt ee = 0; ee < elementCount; ++ee) - { - auto leftElem = leftVaryingTuple->elements[ee]; - - - RefPtr rightElemExpr = new MemberExpr(); - rightElemExpr->loc = rightSimpleExpr->loc; - rightElemExpr->type.type = GetType(leftElem.originalFieldDeclRef); - rightElemExpr->declRef = leftElem.originalFieldDeclRef; - rightElemExpr->name = leftElem.originalFieldDeclRef.GetName(); - rightElemExpr->BaseExpression = rightSimpleExpr; - - VaryingTupleExpr::Element elem; - elem.originalFieldDeclRef = leftElem.originalFieldDeclRef; - elem.expr = createAssignExpr( - leftElem.expr, - LoweredExpr(rightElemExpr), - mode); - - resultTuple->elements.Add(elem); - } - - return LoweredExpr(resultTuple); - } - else if (leftSimpleExpr && rightVaryingTuple) - { - // Pretty much the same as the above case, and we should - // probably try to share code eventually. - - - RefPtr resultTuple = new VaryingTupleExpr(); - resultTuple->type.type = leftSimpleExpr->type.type; - resultTuple->loc = leftSimpleExpr->loc; - - SLANG_RELEASE_ASSERT(resultTuple->type.type); - - UInt elementCount = rightVaryingTuple->elements.Count(); - - // Move everything into temps if we can - leftSimpleExpr = ensureSimpleLValue(leftSimpleExpr); - for (UInt ee = 0; ee < elementCount; ++ee) - { - auto& rightElem = rightVaryingTuple->elements[ee]; - rightElem.expr = maybeMoveTemp(rightElem.expr); - } - - - for (UInt ee = 0; ee < elementCount; ++ee) - { - auto rightElem = rightVaryingTuple->elements[ee]; - - - RefPtr leftElemExpr = new MemberExpr(); - leftElemExpr->loc = leftSimpleExpr->loc; - leftElemExpr->type.type = GetType(rightElem.originalFieldDeclRef); - leftElemExpr->declRef = rightElem.originalFieldDeclRef; - leftElemExpr->name = rightElem.originalFieldDeclRef.GetName(); - leftElemExpr->BaseExpression = leftSimpleExpr; - - VaryingTupleExpr::Element elem; - elem.originalFieldDeclRef = rightElem.originalFieldDeclRef; - elem.expr = createAssignExpr( - LoweredExpr(leftElemExpr), - rightElem.expr, - mode); - - resultTuple->elements.Add(elem); - } - - return LoweredExpr(resultTuple); - } - else if (leftSimpleExpr && rightSimpleExpr) - { - // Default case: no tuples of any kind... - - return LoweredExpr(createSimpleAssignExpr(leftSimpleExpr, rightSimpleExpr, mode)); - } - else - { - // Some case wasn't handled: diagnose! - SLANG_UNEXPECTED("bad combination of tuple types"); - } - } - - LoweredExpr visitAssignExpr( - AssignExpr* expr) - { - auto leftExpr = lowerExprOrTuple(expr->left); - auto rightExpr = lowerExprOrTuple(expr->right); - - auto loweredExpr = createAssignExpr(leftExpr, rightExpr); - lowerExprCommon(loweredExpr, expr); - return loweredExpr; - } - - RefPtr getSubscripResultType( - RefPtr type) - { - if (auto arrayType = type->As()) - { - return arrayType->baseType; - } - return nullptr; - } - - RefPtr createSimpleSubscriptExpr( - RefPtr baseExpr, - RefPtr indexExpr) - { - // Default case: just reconstrut a subscript expr - auto loweredExpr = new IndexExpr(); - - loweredExpr->type.type = getSubscripResultType(baseExpr->type.type); - - loweredExpr->BaseExpression = baseExpr; - loweredExpr->IndexExpression = indexExpr; - return loweredExpr; - } - - LoweredExpr createSubscriptExpr( - LoweredExpr baseExpr, - RefPtr indexExpr) - { - // TODO: This logic ends up duplicating the `indexExpr` - // that was given, without worrying about any side - // effects it might contain. That needs to be fixed. - - if (auto baseTuple = baseExpr.asTuple()) - { - indexExpr = maybeMoveTemp(indexExpr); - - auto loweredExpr = new TupleExpr(); - loweredExpr->type.type = getSubscripResultType(baseTuple->type.type); - - if (auto basePrimary = baseTuple->primaryExpr) - { - loweredExpr->primaryExpr = createSimpleSubscriptExpr( - basePrimary, - indexExpr); - } - for (auto elem : baseTuple->tupleElements) - { - TupleExpr::Element loweredElem; - loweredElem.tupleFieldDeclRef = elem.tupleFieldDeclRef; - loweredElem.expr = createSubscriptExpr( - elem.expr, - indexExpr); - - loweredExpr->tupleElements.Add(loweredElem); - } - - return loweredExpr; - } - else if (auto baseVaryingTuple = baseExpr.asVaryingTuple()) - { - indexExpr = maybeMoveTemp(indexExpr); - - auto loweredExpr = new VaryingTupleExpr(); - loweredExpr->type.type = getSubscripResultType(baseVaryingTuple->type.type); - - SLANG_RELEASE_ASSERT(loweredExpr->type.type); - - for (auto elem : baseVaryingTuple->elements) - { - VaryingTupleExpr::Element loweredElem; - loweredElem.originalFieldDeclRef = elem.originalFieldDeclRef; - loweredElem.expr = createSubscriptExpr( - elem.expr, - indexExpr); - } - - return loweredExpr; - } - else - { - return LoweredExpr(createSimpleSubscriptExpr( - baseExpr.getExpr(), - indexExpr)); - } - } - - LoweredExpr visitIndexExpr( - IndexExpr* subscriptExpr) - { - auto baseExpr = lowerExprOrTuple(subscriptExpr->BaseExpression); - auto indexExpr = lowerExpr(subscriptExpr->IndexExpression); - - // An attempt to subscript a tuple must be turned into a - // tuple of subscript expressions. - if (auto baseTuple = baseExpr.asTuple()) - { - return createSubscriptExpr(baseExpr, indexExpr); - } - else if (auto baseVaryingTuple = baseExpr.asVaryingTuple()) - { - return createSubscriptExpr(baseExpr, indexExpr); - } - else - { - // Default case: just reconstrut a subscript expr - RefPtr loweredExpr = new IndexExpr(); - lowerExprCommon(loweredExpr, subscriptExpr); - loweredExpr->BaseExpression = baseExpr.getExpr(); - loweredExpr->IndexExpression = indexExpr; - return LoweredExpr(loweredExpr); - } - } - - RefPtr maybeReifyTuple( - LoweredExpr expr) - { - if (auto tupleExpr = expr.asTuple()) - { - // TODO: need to diagnose - return tupleExpr->primaryExpr; - } - else if (auto varyingTupleExpr = expr.asVaryingTuple()) - { - // Need to pass an ordinary (non-tuple) expression of - // the corresponding type here. - - // TODO(tfoley): This won't work at all for an `out` or `inout` - // function argument, so we'll need to figure out a plan - // to handle that case... - - RefPtr resultExpr = new AggTypeCtorExpr(); - resultExpr->type = varyingTupleExpr->type; - resultExpr->base.type = varyingTupleExpr->type.type; - SLANG_RELEASE_ASSERT(resultExpr->type.type); - - for (auto elem : varyingTupleExpr->elements) - { - addArgs(resultExpr, elem.expr); - } - - return resultExpr; - } - - // Default case: nothing special to this expression - return expr.getExpr(); - } - - bool needGlslangBug988Workaround( - RefPtr inExpr) - { - switch (getTarget()) - { - default: - return false; - - case CodeGenTarget::GLSL: - break; - } - - // There are two conditions we care about here: - // - // (1) is the *type* of the expression something that needs the WAR - // (2) does the expression reference a constant-buffer member? - // - - // Issue (1): is the type of the expression something that needs the WAR? - - auto exprType = inExpr->type.type; - exprType = unwrapArray(exprType); - - if (!isStructType(exprType)) - return false; - - - // Issue (2): does the expression reference a constant-buffer member? - - auto expr = inExpr; - for (;;) - { - if (auto memberRefExpr = expr.As()) - { - expr = memberRefExpr->BaseExpression; - continue; - } - - if (auto derefExpr = expr.As()) - { - expr = derefExpr->base; - continue; - } - - if (auto subscriptExpr = expr.As()) - { - expr = subscriptExpr->BaseExpression; - continue; - } - - break; - } - - if (auto varExpr = expr.As()) - { - auto declRef = varExpr->declRef; - if (!declRef) - return false; - - if (auto varDeclRef = declRef.As()) - { - auto varType = GetType(varDeclRef); - - while (auto arrayType = varType->As()) - { - varType = arrayType->baseType; - } - - if (auto constantBufferType = varType->As()) - { - return true; - } - } - } - - return false; - } - - void addArg( - ExprWithArgsBase* callExpr, - RefPtr argExpr) - { - // This should be the default case where we have a perfectly - // ordinary expression, but we need to work around a glslang - // but here, where passing a member of a `uniform` block - // that has `struct` type directly to a function call causes - // invalid SPIR-V to be generated. - if (needGlslangBug988Workaround(argExpr)) - { - argExpr = moveTemp(argExpr); - } - - // Here's the actual default case where we just add an argment - callExpr->Arguments.Add(argExpr); - } - - void addArgs( - ExprWithArgsBase* callExpr, - LoweredExpr argExpr) - { - if (auto argTuple = argExpr.asTuple()) - { - if (argTuple->primaryExpr) - { - addArg(callExpr, argTuple->primaryExpr); - } - for (auto elem : argTuple->tupleElements) - { - addArgs(callExpr, elem.expr); - } - } - else if (auto varyingArgTuple = argExpr.asVaryingTuple()) - { - // Need to pass an ordinary (non-tuple) expression of - // the corresponding type here. - - callExpr->Arguments.Add(maybeReifyTuple(argExpr)); - } - else - { - addArg(callExpr, argExpr.getExpr()); - } - } - - RefPtr lowerCallExpr( - RefPtr loweredExpr, - InvokeExpr* expr) - { - lowerExprCommon(loweredExpr, expr); - - loweredExpr->FunctionExpr = lowerExpr(expr->FunctionExpr); - - for (auto arg : expr->Arguments) - { - auto loweredArg = lowerExprOrTuple(arg); - addArgs(loweredExpr, loweredArg); - } - - return loweredExpr; - } - - LoweredExpr visitInvokeExpr( - InvokeExpr* expr) - { - // Create a clone with the same class - InvokeExpr* loweredExpr = (InvokeExpr*) expr->getClass().createInstance(); - return LoweredExpr(lowerCallExpr(loweredExpr, expr)); - } - - LoweredExpr visitSelectExpr( - SelectExpr* expr) - { - // TODO: A tuple needs to be special-cased here - - return LoweredExpr(lowerCallExpr(new SelectExpr(), expr)); - } - - LoweredExpr visitDerefExpr( - DerefExpr* expr) - { - auto loweredBase = lowerExprOrTuple(expr->base); - - if (auto baseTuple = loweredBase.asTuple()) - { - // In the case of a tuple created for "resources in structs" reasons, - // only the primary expression (if any) needs to be dereferenced. - // - // We cheat a bit here and re-use the same tuple we already have, - // and just insert the deref into its primary. - // - // More or less we are lowering: - // - // *(P, T0, T1, ...) - // - // into: - // (*P, T0, T1, ...) - // - if (auto primaryExpr = baseTuple->primaryExpr) - { - RefPtr loweredPrimary = new DerefExpr(); - lowerExprCommon(loweredPrimary, expr); - loweredPrimary->base = baseTuple->primaryExpr; - baseTuple->primaryExpr = loweredPrimary; - return baseTuple; - } - else - { - // No primary expression? Then there is nothing - // to dereference. - return baseTuple; - } - } - else if (auto baseVaryingTuple = loweredBase.asVaryingTuple()) - { - // We don't expect to see this case arise for a "varying" - // tuple, since there aren't pointer-like varyings, but - // the desugaring seems natural: just dereference each - // field. - // - // TODO: implement this. - } - - // Default case is just to lower a dereference opertion - // into another dereference. - RefPtr loweredExpr = new DerefExpr(); - lowerExprCommon(loweredExpr, expr); - loweredExpr->base = loweredBase.getExpr(); - return LoweredExpr(loweredExpr); - } - - DiagnosticSink* getSink() - { - return &shared->compileRequest->mSink; - } - - LoweredExpr visitStaticMemberExpr( - StaticMemberExpr* expr) - { - auto loweredBase = lowerExprOrTuple(expr->BaseExpression); - auto loweredDeclRef = translateDeclRef(expr->declRef); - - // TODO: we should probably support type-type members here. - - RefPtr loweredExpr = new StaticMemberExpr(); - lowerExprCommon(loweredExpr, expr); - loweredExpr->BaseExpression = loweredBase.getExpr(); - loweredExpr->declRef = loweredDeclRef.As(); - loweredExpr->name = expr->name; - - return LoweredExpr(loweredExpr); - } - - LoweredExpr visitMemberExpr( - MemberExpr* expr) - { - assert(expr->BaseExpression); - auto loweredBase = lowerExprOrTuple(expr->BaseExpression); - assert(loweredBase); - - auto loweredDeclRef = translateDeclRef(expr->declRef); - - - // Are we extracting an element from a tuple? - if (auto baseTuple = loweredBase.asTuple()) - { - auto loweredFieldDecl = loweredDeclRef.As().getDecl(); - auto tupleFieldMod = loweredFieldDecl->FindModifier(); - if (tupleFieldMod) - { - // This field has a tuple part to it, so we need to search for it - - LoweredExpr tupleFieldExpr; - for (auto elem : baseTuple->tupleElements) - { - if (loweredFieldDecl == elem.tupleFieldDeclRef.getDecl()) - { - tupleFieldExpr = elem.expr; - break; - } - } - - if (!tupleFieldMod->hasAnyNonTupleFields) - { - // We need to have found something! - assert(tupleFieldExpr); - return tupleFieldExpr; - } - - auto tupleFieldTupleExpr = tupleFieldExpr.asTuple(); - SLANG_RELEASE_ASSERT(tupleFieldTupleExpr); - SLANG_RELEASE_ASSERT(!tupleFieldTupleExpr->primaryExpr); - - - RefPtr loweredPrimaryExpr = new MemberExpr(); - lowerExprCommon(loweredPrimaryExpr, expr); - loweredPrimaryExpr->BaseExpression = baseTuple->primaryExpr; - loweredPrimaryExpr->declRef = loweredDeclRef.As(); - loweredPrimaryExpr->name = expr->name; - - assert(loweredPrimaryExpr->BaseExpression); - - tupleFieldTupleExpr->primaryExpr = loweredPrimaryExpr; - return tupleFieldTupleExpr; - } - - // If the field was a non-tuple field, then we can - // simply fall through to the ordinary case below. - loweredBase = LoweredExpr(baseTuple->primaryExpr); - assert(baseTuple->primaryExpr); - } - else if (auto baseVaryingTuple = loweredBase.asVaryingTuple()) - { - // Search for the element corresponding to this field - for(auto elem : baseVaryingTuple->elements) - { - if (expr->declRef.getDecl() == elem.originalFieldDeclRef.getDecl()) - { - // We found the field! - assert(elem.expr); - return elem.expr; - } - } - - SLANG_DIAGNOSE_UNEXPECTED(getSink(), expr, "failed to find tuple field during lowering"); - } - - // Default handling: - - RefPtr loweredExpr = new MemberExpr(); - lowerExprCommon(loweredExpr, expr); - loweredExpr->BaseExpression = loweredBase.getExpr(); - loweredExpr->declRef = loweredDeclRef.As(); - loweredExpr->name = expr->name; - - assert(loweredExpr->BaseExpression); - - return LoweredExpr(loweredExpr); - } - - // - // Statements - // - - // Lowering one statement to another. - // The source statement might desugar into multiple statements, - // (or event to none), and in such a case this function wraps - // the result up as a `SeqStmt` or `EmptyStmt` as appropriate. - // - RefPtr lowerStmt( - Stmt* stmt) - { - if (!stmt) - return nullptr; - - LoweringVisitor subVisitor = *this; - subVisitor.stmtBeingBuilt = nullptr; - - subVisitor.lowerStmtImpl(stmt); - - if (!subVisitor.stmtBeingBuilt) - { - return new EmptyStmt(); - } - else - { - return subVisitor.stmtBeingBuilt; - } - } - - - // Structure to track "outer" statements during lowering - struct StmtLoweringState - { - // The next "outer" statement entry - StmtLoweringState* parent = nullptr; - - // The outer statement (both lowered and original) - Stmt* loweredStmt = nullptr; - Stmt* originalStmt = nullptr; - }; - StmtLoweringState stmtLoweringState; - - // Translate a reference from one statement to an outer statement - Stmt* translateStmtRef( - Stmt* originalStmt) - { - if (!originalStmt) return nullptr; - - for (auto state = &stmtLoweringState; state; state = state->parent) - { - if (state->originalStmt == originalStmt) - return state->loweredStmt; - } - - SLANG_DIAGNOSE_UNEXPECTED(getSink(), originalStmt, "failed to find outer statement during lowering"); - - return nullptr; - } - - // Expand a statement to be lowered into one or more statements - void lowerStmtImpl( - Stmt* stmt) - { - StmtVisitor::dispatch(stmt); - } - - LoweredDecl visitScopeDecl(ScopeDecl* decl) - { - RefPtr loweredDecl = new ScopeDecl(); - lowerDeclCommon(loweredDecl, decl); - return LoweredDecl(loweredDecl); - } - - LoweringVisitor pushScope( - RefPtr loweredStmt, - RefPtr originalStmt) - { - loweredStmt->scopeDecl = translateDeclRef(originalStmt->scopeDecl).As(); - - LoweringVisitor subVisitor = *this; - subVisitor.isBuildingStmt = true; - subVisitor.stmtBeingBuilt = nullptr; - subVisitor.parentDecl = loweredStmt->scopeDecl; - subVisitor.stmtLoweringState.parent = &stmtLoweringState; - subVisitor.stmtLoweringState.originalStmt = originalStmt; - subVisitor.stmtLoweringState.loweredStmt = loweredStmt; - return subVisitor; - } - - void addStmtImpl( - RefPtr& dest, - Stmt* stmt) - { - // add a statement to the code we are building... - if (!dest) - { - dest = stmt; - return; - } - - if (auto blockStmt = dest.As()) - { - addStmtImpl(blockStmt->body, stmt); - return; - } - - if (auto seqStmt = dest.As()) - { - seqStmt->stmts.Add(stmt); - } - else - { - RefPtr newSeqStmt = new SeqStmt(); - - newSeqStmt->stmts.Add(dest); - newSeqStmt->stmts.Add(stmt); - - dest = newSeqStmt; - } - - } - - void addStmt( - Stmt* stmt) - { - addStmtImpl(stmtBeingBuilt, stmt); - } - - void addSimpleExprStmt( - RefPtr expr) - { - if (auto infixExpr = expr.As()) - { - if (auto varExpr = infixExpr->FunctionExpr.As()) - { - if (getText(varExpr->name) == ",") - { - // Call to "operator comma" - for (auto aa : infixExpr->Arguments) - { - addSimpleExprStmt(aa); - } - return; - } - } - } - else if (auto varExpr = expr.As()) - { - // Skip an expression that is just a reference to a single variable - return; - } - - RefPtr stmt = new ExpressionStmt(); - stmt->Expression = expr; - addStmt(stmt); - } - - void addExprStmt( - LoweredExpr expr) - { - // Desugar tuples in statement position - if (auto tupleExpr = expr.asTuple()) - { - if (tupleExpr->primaryExpr) - { - addSimpleExprStmt(tupleExpr->primaryExpr); - } - for (auto ee : tupleExpr->tupleElements) - { - addExprStmt(ee.expr); - } - return; - } - else if (auto varyingTupleExpr = expr.asVaryingTuple()) - { - for (auto ee : varyingTupleExpr->elements) - { - addExprStmt(ee.expr); - } - return; - } - else - { - addSimpleExprStmt(expr.getExpr()); - } - } - - void visitBlockStmt(BlockStmt* stmt) - { - RefPtr loweredStmt = new BlockStmt(); - lowerScopeStmtFields(loweredStmt, stmt); - - LoweringVisitor subVisitor = pushScope(loweredStmt, stmt); - - loweredStmt->body = subVisitor.lowerStmt(stmt->body); - - addStmt(loweredStmt); - } - - void visitSeqStmt(SeqStmt* stmt) - { - for (auto ss : stmt->stmts) - { - lowerStmtImpl(ss); - } - } - - void visitExpressionStmt(ExpressionStmt* stmt) - { - addExprStmt(lowerExprOrTuple(stmt->Expression)); - } - - void visitDeclStmt(DeclStmt* stmt) - { - DeclVisitor::dispatch(stmt->decl); - } - - Modifiers shallowCloneModifiers(Modifiers const& oldModifiers) - { - RefPtr sharedModifiers = new SharedModifiers(); - sharedModifiers->next = oldModifiers.first; - - Modifiers newModifiers; - newModifiers.first = sharedModifiers; - return newModifiers; - } - - void lowerStmtFields( - Stmt* loweredStmt, - Stmt* originalStmt) - { - loweredStmt->loc = originalStmt->loc; - loweredStmt->modifiers = shallowCloneModifiers(originalStmt->modifiers); - } - - void lowerScopeStmtFields( - ScopeStmt* loweredStmt, - ScopeStmt* originalStmt) - { - lowerStmtFields(loweredStmt, originalStmt); - loweredStmt->scopeDecl = translateDeclRef(originalStmt->scopeDecl).As(); - } - - // Child statements reference their parent statement, - // so we need to translate that cross-reference - void lowerChildStmtFields( - ChildStmt* loweredStmt, - ChildStmt* originalStmt) - { - lowerStmtFields(loweredStmt, originalStmt); - - loweredStmt->parentStmt = translateStmtRef(originalStmt->parentStmt); - } - - void visitContinueStmt(ContinueStmt* stmt) - { - RefPtr loweredStmt = new ContinueStmt(); - lowerChildStmtFields(loweredStmt, stmt); - addStmt(loweredStmt); - } - - void visitBreakStmt(BreakStmt* stmt) - { - RefPtr loweredStmt = new BreakStmt(); - lowerChildStmtFields(loweredStmt, stmt); - addStmt(loweredStmt); - } - - void visitDefaultStmt(DefaultStmt* stmt) - { - RefPtr loweredStmt = new DefaultStmt(); - lowerChildStmtFields(loweredStmt, stmt); - addStmt(loweredStmt); - } - - void visitDiscardStmt(DiscardStmt* stmt) - { - RefPtr loweredStmt = new DiscardStmt(); - lowerStmtFields(loweredStmt, stmt); - addStmt(loweredStmt); - } - - void visitEmptyStmt(EmptyStmt* stmt) - { - RefPtr loweredStmt = new EmptyStmt(); - lowerStmtFields(loweredStmt, stmt); - addStmt(loweredStmt); - } - - void visitUnparsedStmt(UnparsedStmt* stmt) - { - RefPtr loweredStmt = new UnparsedStmt(); - lowerStmtFields(loweredStmt, stmt); - - loweredStmt->tokens = stmt->tokens; - - addStmt(loweredStmt); - } - - void visitCaseStmt(CaseStmt* stmt) - { - RefPtr loweredStmt = new CaseStmt(); - lowerChildStmtFields(loweredStmt, stmt); - - loweredStmt->expr = lowerExpr(stmt->expr); - - addStmt(loweredStmt); - } - - void visitIfStmt(IfStmt* stmt) - { - RefPtr loweredStmt = new IfStmt(); - lowerStmtFields(loweredStmt, stmt); - - loweredStmt->Predicate = lowerExpr(stmt->Predicate); - loweredStmt->PositiveStatement = lowerStmt(stmt->PositiveStatement); - loweredStmt->NegativeStatement = lowerStmt(stmt->NegativeStatement); - - addStmt(loweredStmt); - } - - void visitSwitchStmt(SwitchStmt* stmt) - { - RefPtr loweredStmt = new SwitchStmt(); - lowerScopeStmtFields(loweredStmt, stmt); - - LoweringVisitor subVisitor = pushScope(loweredStmt, stmt); - - loweredStmt->condition = subVisitor.lowerExpr(stmt->condition); - loweredStmt->body = subVisitor.lowerStmt(stmt->body); - - addStmt(loweredStmt); - } - - void lowerForStmtCommon( - RefPtr loweredStmt, - ForStmt* stmt) - { - lowerScopeStmtFields(loweredStmt, stmt); - - 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); - - addStmt(loweredStmt); - } - - void visitForStmt(ForStmt* stmt) - { - lowerForStmtCommon(new ForStmt(), stmt); - } - - void visitUnscopedForStmt(UnscopedForStmt* stmt) - { - lowerForStmtCommon(new UnscopedForStmt(), stmt); - } - - void visitCompileTimeForStmt(CompileTimeForStmt* stmt) - { - // We can either lower this here, so that emit logic doesn't have to deal with it, - // or else just translate it and then let emit deal with it. - // - // The right answer is really to lower it here, I guess. - - auto rangeBeginVal = GetIntVal(stmt->rangeBeginVal); - auto rangeEndVal = GetIntVal(stmt->rangeEndVal); - - if (rangeBeginVal >= rangeEndVal) - return; - - auto varDecl = stmt->varDecl; - - auto varType = lowerType(varDecl->type); - - for (IntegerLiteralValue ii = rangeBeginVal; ii < rangeEndVal; ++ii) - { - RefPtr constExpr = new ConstantExpr(); - constExpr->type.type = varType.type; - constExpr->ConstType = ConstantExpr::ConstantType::Int; - constExpr->integerValue = ii; - - RefPtr loweredVarDecl = new VaryingTupleVarDecl(); - loweredVarDecl->loc = varDecl->loc; - loweredVarDecl->type = varType; - loweredVarDecl->expr = LoweredExpr(constExpr); - - shared->loweredDecls[varDecl] = LoweredDecl(loweredVarDecl); - - lowerStmtImpl(stmt->body); - } - } - - void visitWhileStmt(WhileStmt* stmt) - { - RefPtr loweredStmt = new WhileStmt(); - lowerScopeStmtFields(loweredStmt, stmt); - - LoweringVisitor subVisitor = pushScope(loweredStmt, stmt); - - loweredStmt->Predicate = subVisitor.lowerExpr(stmt->Predicate); - loweredStmt->Statement = subVisitor.lowerStmt(stmt->Statement); - - addStmt(loweredStmt); - } - - void visitDoWhileStmt(DoWhileStmt* stmt) - { - RefPtr loweredStmt = new DoWhileStmt(); - lowerScopeStmtFields(loweredStmt, stmt); - - LoweringVisitor subVisitor = pushScope(loweredStmt, stmt); - - loweredStmt->Statement = subVisitor.lowerStmt(stmt->Statement); - loweredStmt->Predicate = subVisitor.lowerExpr(stmt->Predicate); - - addStmt(loweredStmt); - } - - RefPtr transformSyntaxField(Stmt* stmt) - { - return lowerStmt(stmt); - } - - void lowerStmtCommon(Stmt* loweredStmt, Stmt* stmt) - { - loweredStmt->modifiers = shallowCloneModifiers(stmt->modifiers); - } - - void assign( - LoweredExpr destExpr, - LoweredExpr srcExpr, - AssignMode mode = AssignMode::Default) - { - auto assignExpr = createAssignExpr(destExpr, srcExpr, mode); - addExprStmt(assignExpr); - } - - void assign(VarDeclBase* varDecl, LoweredExpr expr) - { - assign(LoweredExpr(createVarRef(getPosition(expr), varDecl)), expr); - } - - void assign(LoweredExpr expr, VarDeclBase* varDecl) - { - assign(expr, LoweredExpr(createVarRef(getPosition(expr), varDecl))); - } - - RefPtr createTypeExpr( - RefPtr type) - { - auto typeType = new TypeType(); - typeType->type = type; - - auto result = new SharedTypeExpr(); - result->base.type = type; - result->type.type = typeType; - - return result; - } - - RefPtr createCastExpr( - RefPtr type, - RefPtr expr) - { - RefPtr castExpr = new ExplicitCastExpr(); - castExpr->loc = expr->loc; - castExpr->type.type = type; - - castExpr->FunctionExpr = createTypeExpr(type); - castExpr->Arguments.Add(expr); - return castExpr; - } - - // Like `assign`, but with some extra logic to handle cases - // where the types don't actually line up, because of - // differences in how something is declared in HLSL vs. GLSL - void assignWithFixups( - LoweredExpr destExpr, - LoweredExpr srcExpr) - { - assign(destExpr, srcExpr, AssignMode::WithFixups); - } - - void assignWithFixups(VarDeclBase* varDecl, LoweredExpr expr) - { - assignWithFixups(LoweredExpr(createVarRef(getPosition(expr), varDecl)), expr); - } - - void assignWithFixups(LoweredExpr expr, VarDeclBase* varDecl) - { - assignWithFixups(expr, LoweredExpr(createVarRef(getPosition(expr), varDecl))); - } - - void visitReturnStmt(ReturnStmt* stmt) - { - auto loweredStmt = new ReturnStmt(); - lowerStmtCommon(loweredStmt, stmt); - - if (stmt->Expression) - { - if (resultVariable) - { - // Do it as an assignment - assign(resultVariable, lowerExprOrTuple(stmt->Expression)); - } - else - { - // Simple case - loweredStmt->Expression = lowerExpr(stmt->Expression); - } - } - - addStmt(loweredStmt); - } - - // - // Declarations - // - - RefPtr translateVal(Val* val) - { - if (auto type = dynamic_cast(val)) - return lowerType(type); - - if (auto litVal = dynamic_cast(val)) - return val; - - SLANG_UNEXPECTED("unhandled value kind"); - } - - RefPtr translateSubstitutions( - Substitutions* inSubstitutions) - { - if (!inSubstitutions) return nullptr; - if (auto genSubst = dynamic_cast(inSubstitutions)) - { - RefPtr result = new GenericSubstitution(); - result->genericDecl = translateDeclRef(genSubst->genericDecl).As(); - for (auto arg : genSubst->args) - { - result->args.Add(translateVal(arg)); - } - return result; - } - else if (auto thisSubst = dynamic_cast(inSubstitutions)) - { - RefPtr result = new ThisTypeSubstitution(); - if (result->sourceType) - result->sourceType = translateVal(result->sourceType); - return result; - } - return nullptr; - } - - static Decl* getModifiedDecl(Decl* decl) - { - if (!decl) return nullptr; - if (auto genericDecl = dynamic_cast(decl->ParentDecl)) - return genericDecl; - return decl; - } - - LoweredDeclRef translateDeclRef( - DeclRef const& decl) - { - LoweredDeclRef result; - result.decl = translateDeclRef(decl.decl); - result.substitutions = translateSubstitutions(decl.substitutions); - return result; - } - - LoweredDecl translateDeclRef( - Decl* decl) - { - if (!decl) return LoweredDecl(); - - // We don't want to translate references to built-in declarations, - // since they won't be subtituted anyway. - if (getModifiedDecl(decl)->HasModifier()) - return decl; - - // If any parent of the declaration was in the stdlib, then - // we need to skip it. - for (auto pp = decl; pp; pp = pp->ParentDecl) - { - if (pp->HasModifier()) - return decl; - } - - if (getModifiedDecl(decl)->HasModifier()) - return decl; - - LoweredDecl loweredDecl; - if (shared->loweredDecls.TryGetValue(decl, loweredDecl)) - return loweredDecl; - - // Time to force it - return lowerDecl(decl); - } - - RefPtr translateDeclRef( - ContainerDecl* decl) - { - return translateDeclRef((Decl*)decl).getDecl()->As(); - } - - LoweredDecl lowerDeclBase( - DeclBase* declBase) - { - if (Decl* decl = dynamic_cast(declBase)) - { - return lowerDecl(decl); - } - else - { - return DeclVisitor::dispatch(declBase); - } - } - - LoweredDecl lowerDecl( - Decl* decl) - { - LoweredDecl loweredDecl = DeclVisitor::dispatch(decl); - return loweredDecl; - } - - static void addMember( - RefPtr containerDecl, - RefPtr memberDecl) - { - containerDecl->Members.Add(memberDecl); - memberDecl->ParentDecl = containerDecl.Ptr(); - } - - void addDecl( - Decl* decl) - { - if (!decl) - return; - - if (isBuildingStmt) - { - RefPtr declStmt = new DeclStmt(); - declStmt->loc = decl->loc; - declStmt->decl = decl; - addStmt(declStmt); - } - - - // We will add the declaration to the current container declaration being - // translated, which the user will maintain via pua/pop. - // - - SLANG_RELEASE_ASSERT(parentDecl); - addMember(parentDecl, decl); - } - - void registerLoweredDecl(LoweredDecl loweredDecl, Decl* decl) - { - shared->loweredDecls.Add(decl, loweredDecl); - - shared->mapLoweredDeclToOriginal.Add(loweredDecl.getValue(), decl); - } - - // If the name of the declarations collides with a reserved word - // for the code generation target, then rename it to avoid the conflict - // - // Note that this does *not* implement any kind of comprehensive renaming - // to, e.g., avoid conflicts between user-defined and library functions. - void ensureDeclHasAValidName(Decl* decl) - { - // By default, we would like to emit a name in the generated - // code exactly as it appeared in the original program. - // When that isn't possible, we'd like to emit a name as - // close to the original as possible (to ensure that existing - // debugging tools still work reasonably well). - // - // One reason why a name might not be allowed as-is is that - // it could collide with a reserved word in the target language. - // Another reason is that it might not follow a naming convention - // imposed by the target (e.g., in GLSL names starting with - // `gl_` or containing `__` are reserved). - // - // Given a name that should not be allowed, we want to - // change it to a name that *is* allowed. e.g., by adding - // `_` to the end of a reserved word. - // - // The next problem this creates is that the modified name - // could not collide with an existing use of the same - // (valid) name. - // - // For now we are going to solve this problem in a simple - // and ad hoc fashion, but longer term we'll want to do - // something sytematic. - - auto name = decl->getName(); - if (isReservedWord(name)) - { - auto nameText = getText(name); - nameText.append("_"); - - decl->nameAndLoc.name = getName(nameText); - } - } - - RefPtr tryToFindLayout( - Decl* decl) - { - RefPtr loweredParent; - if (auto genericParentDecl = decl->ParentDecl->As()) - loweredParent = translateDeclRef(genericParentDecl->ParentDecl); - else - loweredParent = translateDeclRef(decl->ParentDecl); - if (loweredParent) - { - auto layoutMod = loweredParent->FindModifier(); - if (layoutMod) - { - auto parentLayout = layoutMod->layout; - if (auto structLayout = parentLayout.As()) - { - RefPtr 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) - { - registerLoweredDecl(loweredDecl, decl); - - loweredDecl->loc = decl->loc; - loweredDecl->nameAndLoc = decl->nameAndLoc; - - // Deal with renaming - we shouldn't allow decls with names that are reserved words - ensureDeclHasAValidName(loweredDecl); - - // Lower modifiers as needed - - // HACK: just doing a shallow copy of modifiers, which will - // suffice for most of them, but we need to do something - // better soon. - loweredDecl->modifiers = shallowCloneModifiers(decl->modifiers); - - // deal with layout stuff - - if (auto fieldLayout = tryToFindLayout(decl)) - { - attachLayout(loweredDecl, fieldLayout); - } - } - - // Catch-all - - LoweredDecl visitSyntaxDecl(SyntaxDecl*) - { - return LoweredDecl(); - } - - LoweredDecl visitGenericValueParamDecl(GenericValueParamDecl*) - { - SLANG_UNEXPECTED("generics should be lowered to specialized decls"); - } - - LoweredDecl visitGenericTypeParamDecl(GenericTypeParamDecl*) - { - SLANG_UNEXPECTED("generics should be lowered to specialized decls"); - } - - LoweredDecl visitGenericTypeConstraintDecl(GenericTypeConstraintDecl*) - { - SLANG_UNEXPECTED("generics should be lowered to specialized decls"); - } - - LoweredDecl visitGenericDecl(GenericDecl*) - { - SLANG_UNEXPECTED("generics should be lowered to specialized decls"); - } - - LoweredDecl visitModuleDecl(ModuleDecl*) - { - SLANG_UNEXPECTED("module decls should be lowered explicitly"); - } - - LoweredDecl visitSubscriptDecl(SubscriptDecl*) - { - // We don't expect to find direct references to a subscript - // declaration, but rather to the underlying accessors - return LoweredDecl(); - } - - LoweredDecl visitInheritanceDecl(InheritanceDecl*) - { - // We should deal with these explicitly, as part of lowering - // the type that contains them. - return LoweredDecl(); - } - - LoweredDecl visitExtensionDecl(ExtensionDecl*) - { - // Extensions won't exist in the lowered code: their members - // will turn into ordinary functions that get called explicitly - return LoweredDecl(); - } - - LoweredDecl visitAssocTypeDecl(AssocTypeDecl * /*assocType*/) - { - // not supported - SLANG_UNREACHABLE("visitAssocTypeDecl in LowerVisitor"); - UNREACHABLE_RETURN(LoweredDecl()); - } - - LoweredDecl visitGlobalGenericParamDecl(GlobalGenericParamDecl * /*decl*/) - { - // not supported - SLANG_UNREACHABLE("visitGlobalGenericParamDecl in LowerVisitor"); - UNREACHABLE_RETURN(LoweredDecl()); - } - - LoweredDecl visitTypeDefDecl(TypeDefDecl* decl) - { - if (shared->target == CodeGenTarget::GLSL) - { - // GLSL does not support `typedef`, so we will lower it out of existence here - return LoweredDecl(); - } - - RefPtr loweredDecl = new TypeDefDecl(); - lowerDeclCommon(loweredDecl, decl); - - loweredDecl->type = lowerType(decl->type); - - addMember(shared->loweredProgram, loweredDecl); - return LoweredDecl(loweredDecl); - } - - LoweredDecl visitImportDecl(ImportDecl*) - { - // We could unconditionally output the declarations in the - // imported code, but this could cause problems if any - // of those declarations used capabilities not allowed - // by the target pipeline stage (e.g., `discard` is - // an error in a GLSL vertex shader file, even if - // it is in a function that never gets called). - // - // As a result, we just ignore the `import` step, - // and allow declarations to be pulled in by - // their use sites. - // - // If this proves to be a problem, we will need - // a pass that resolves which declarations in imported - // modules are "valid" for the chosen target stage. - - // Don't actually include a representation of - // the import declaration in the output - return LoweredDecl(); - } - - LoweredDecl visitEmptyDecl(EmptyDecl* decl) - { - // Empty declarations are really only useful in GLSL, - // where they are used to hold metadata that doesn't - // attach to any particular shader parameter. - // - // TODO: Only lower empty declarations if we are - // rewriting a GLSL file, and otherwise ignore them. - // - RefPtr loweredDecl = new EmptyDecl(); - lowerDeclCommon(loweredDecl, decl); - - addDecl(loweredDecl); - - return LoweredDecl(loweredDecl); - } - - TupleTypeModifier* isTupleType(Type* type) - { - if (auto declRefType = type->As()) - { - if (auto tupleTypeMod = declRefType->declRef.getDecl()->FindModifier()) - { - return tupleTypeMod; - } - } - - return nullptr; - } - - Type* unwrapArray(Type* inType) - { - auto type = inType; - while (auto arrayType = type->As()) - { - type = arrayType->baseType; - } - return type; - } - - TupleTypeModifier* isTupleTypeOrArrayOfTupleType(Type* type) - { - return isTupleType(unwrapArray(type)); - } - - bool isResourceType(Type* type) - { - while (auto arrayType = type->As()) - { - type = arrayType->baseType; - } - - if (auto textureTypeBase = type->As()) - { - return true; - } - else if (auto samplerType = type->As()) - { - return true; - } - - // TODO: need more comprehensive coverage here - - return false; - } - - LoweredDecl visitAggTypeDecl(AggTypeDecl* decl) - { - // We want to lower any aggregate type declaration - // to just a `struct` type that contains its fields. - // - // Any non-field members (e.g., methods) will be - // lowered separately. - - RefPtr loweredDecl = new StructDecl(); - 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; - } - else if( shared->compileRequest->compileFlags & SLANG_COMPILE_FLAG_SPLIT_MIXED_TYPES ) - { - // If the user is directly asking us to do this transformation, - // then obviously we need to do it. - // - // TODO: The way this is defined here means it will even apply to user - // HLSL code (not just code written in Slang). We may want to - // reconsider that choice, and only split things that originated in Slang. - // - shouldDesugarTupleTypes = true; - } - - bool isResultATupleType = false; - bool hasAnyNonTupleFields = false; - - for (auto field : decl->getMembersOfType()) - { - // We lower the field, which will involve lowering the field type - auto loweredField = translateDeclRef(field).getDecl()->As(); - - // 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 = isTupleTypeOrArrayOfTupleType(loweredFieldType)) - { - isTupleField = true; - fieldHasTupleType = true; - if (fieldTupleTypeMod->hasAnyNonTupleFields) - { - fieldHasAnyNonTupleFields = true; - hasAnyNonTupleFields = true; - } - } - else if (isResourceType(loweredFieldType)) - { - isTupleField = true; - } - else - { - hasAnyNonTupleFields = true; - } - - if (isTupleField) - { - isResultATupleType = true; - - RefPtr 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 tupleTypeMod = new TupleTypeModifier(); - tupleTypeMod->decl = loweredDecl; - tupleTypeMod->hasAnyNonTupleFields = hasAnyNonTupleFields; - addModifier(loweredDecl, tupleTypeMod); - } - - if (isResultATupleType && !hasAnyNonTupleFields) - { - // We don't want any pure-tuple types showing up in - // the output program, so we skip that here. - } - else - { - addMember( - shared->loweredProgram, - loweredDecl); - } - - return LoweredDecl(loweredDecl); - } - - RefPtr lowerSimpleVarDeclCommon( - RefPtr loweredDecl, - VarDeclBase* decl, - TypeExp const& loweredType) - { - lowerDeclCommon(loweredDecl, decl); - - loweredDecl->type = loweredType; - loweredDecl->initExpr = lowerExpr(decl->initExpr); - - return loweredDecl; - } - - RefPtr lowerSimpleVarDeclCommon( - RefPtr loweredDecl, - VarDeclBase* decl) - { - auto loweredType = lowerType(decl->type); - return lowerSimpleVarDeclCommon(loweredDecl, decl, loweredType); - } - - struct TupleTypeSecondaryVarArraySpec - { - TupleTypeSecondaryVarArraySpec* next; - RefPtr elementCount; - }; - - struct TupleSecondaryVarInfo - { - // Parent tuple decl to add the secondary decl into - RefPtr tupleDecl; - - // Syntax class for declarations to create - SyntaxClass varDeclClass; - - // name "stem" to use for any actual variables we create - String name; - - // The parent tuple type (or array thereof) we are scalarizing - RefPtr tupleType; - - // The actual declaration of the tuple type (which will give us the fields) - DeclRef tupleTypeDecl; - - // An initializer expression to use for the tuple members - RefPtr initExpr; - - // The original layout given to the top-level variable - RefPtr primaryVarLayout; - - // The computed layout of the tuple type itself - RefPtr tupleTypeLayout; - - TupleTypeSecondaryVarArraySpec* arraySpecs = nullptr; - }; - - void createTupleTypeSecondaryVarDecls( - TupleSecondaryVarInfo const& info) - { - if (auto arrayType = info.tupleType->As()) - { - TupleTypeSecondaryVarArraySpec arraySpec; - arraySpec.next = info.arraySpecs; - arraySpec.elementCount = arrayType->ArrayLength; - - TupleSecondaryVarInfo subInfo = info; - subInfo.tupleType = arrayType->baseType; - subInfo.arraySpecs = &arraySpec; - createTupleTypeSecondaryVarDecls(subInfo); - return; - } - - // 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(info.tupleTypeDecl)) - { - if (dd.getDecl()->HasModifier()) - continue; - - auto tupleFieldMod = dd.getDecl()->FindModifier(); - if (!tupleFieldMod) - continue; - - // TODO: need to extract the initializer for this field - SLANG_RELEASE_ASSERT(!info.initExpr); - RefPtr fieldInitExpr; - - String fieldName = info.name + "_" + getText(dd.GetName()); - - auto fieldType = GetType(dd); - - Decl* originalFieldDecl; - shared->mapLoweredDeclToOriginal.TryGetValue(dd, originalFieldDecl); - SLANG_RELEASE_ASSERT(originalFieldDecl); - - RefPtr fieldLayout; - if(info.tupleTypeLayout) - { - info.tupleTypeLayout->mapVarToLayout.TryGetValue(originalFieldDecl, fieldLayout); - } - if (fieldLayout && info.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 = info.primaryVarLayout->FindResourceInfo(rr.kind)) - { - if (parentInfo->index != 0 || parentInfo->space != 0) - { - needsOffset = true; - break; - } - } - } - if (needsOffset) - { - RefPtr newFieldLayout = new VarLayout(); - newFieldLayout->typeLayout = fieldLayout->typeLayout; - newFieldLayout->flags = fieldLayout->flags; - newFieldLayout->varDecl = fieldLayout->varDecl; - newFieldLayout->systemValueSemantic = fieldLayout->systemValueSemantic; - newFieldLayout->systemValueSemanticIndex = fieldLayout->systemValueSemanticIndex; - newFieldLayout->semanticName = fieldLayout->semanticName; - newFieldLayout->semanticIndex = fieldLayout->semanticIndex; - - for (auto resInfo : fieldLayout->resourceInfos) - { - auto newResInfo = newFieldLayout->findOrAddResourceInfo(resInfo.kind); - newResInfo->index = resInfo.index; - newResInfo->space = resInfo.space; - if (auto parentInfo = info.primaryVarLayout->FindResourceInfo(resInfo.kind)) - { - newResInfo->index += parentInfo->index; - newResInfo->space += parentInfo->space; - } - } - - fieldLayout = newFieldLayout; - } - - } - - LoweredDecl fieldVarOrTupleDecl; - if (auto fieldTupleTypeMod = isTupleTypeOrArrayOfTupleType(fieldType)) - { - // If the field is itself a tuple, then recurse - RefPtr fieldTupleDecl = new TupleVarDecl(); - - TupleSecondaryVarInfo fieldInfo; - fieldInfo.tupleDecl = fieldTupleDecl; - fieldInfo.varDeclClass = info.varDeclClass; - fieldInfo.name = fieldName; - fieldInfo.tupleType = fieldType; - fieldInfo.tupleTypeDecl = makeDeclRef(fieldTupleTypeMod->decl); - fieldInfo.initExpr = fieldInitExpr; - fieldInfo.primaryVarLayout = fieldLayout; - fieldInfo.tupleTypeLayout = getBodyStructTypeLayout(fieldLayout ? fieldLayout->typeLayout : nullptr); - fieldInfo.arraySpecs = info.arraySpecs; - - fieldTupleDecl->tupleType = fieldTupleTypeMod; - createTupleTypeSecondaryVarDecls(fieldInfo); - - fieldVarOrTupleDecl = LoweredDecl(fieldTupleDecl); - } - else - { - // Otherwise the field has a simple type, and we just need to declare the variable here - - RefPtr fieldVarType = fieldType; - for (auto aa = info.arraySpecs; aa; aa = aa->next) - { - RefPtr arrayType = Slang::getArrayType( - fieldVarType, - aa->elementCount); - - fieldVarType = arrayType; - } - - RefPtr fieldVarDecl = info.varDeclClass.createInstance(); - fieldVarDecl->nameAndLoc = NameLoc(getName(fieldName)); - fieldVarDecl->type.type = fieldVarType; - - addDecl(fieldVarDecl); - - if (fieldLayout) - { - RefPtr layoutMod = new ComputedLayoutModifier(); - layoutMod->layout = fieldLayout; - addModifier(fieldVarDecl, layoutMod); - } - - fieldVarOrTupleDecl = LoweredDecl(fieldVarDecl); - } - - RefPtr fieldTupleVarMod = new TupleVarModifier(); - fieldTupleVarMod->tupleField = tupleFieldMod; - - TupleVarDecl::Element elem; - elem.decl = fieldVarOrTupleDecl; - elem.tupleVarMod = fieldTupleVarMod; - - info.tupleDecl->tupleDecls.Add(elem); - } - } - - LoweredDecl createTupleTypeVarDecls( - SyntaxClass varDeclClass, - RefPtr originalVarDecl, - String const& name, - RefPtr tupleType, - DeclRef tupleTypeDecl, - TupleTypeModifier* tupleTypeMod, - RefPtr initExpr, - RefPtr primaryVarLayout, - RefPtr tupleTypeLayout) - { - // Not handling initializers just yet... - SLANG_RELEASE_ASSERT(!initExpr); - - // We'll need a placeholder declaration to wrap the whole thing up: - RefPtr tupleDecl = new TupleVarDecl(); - tupleDecl->nameAndLoc = NameLoc(getName(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 primaryVarDecl = varDeclClass.createInstance(); - primaryVarDecl->nameAndLoc.name = getName(name); - primaryVarDecl->type.type = tupleType; - - primaryVarDecl->modifiers = shallowCloneModifiers(originalVarDecl->modifiers); - - tupleDecl->primaryDecl = primaryVarDecl; - - if (primaryVarLayout) - { - RefPtr layoutMod = new ComputedLayoutModifier(); - layoutMod->layout = primaryVarLayout; - addModifier(primaryVarDecl, layoutMod); - } - - addDecl(primaryVarDecl); - } - - TupleSecondaryVarInfo info; - info.tupleDecl = tupleDecl; - info.varDeclClass = varDeclClass; - info.name = name; - info.tupleType = tupleType; - info.tupleTypeDecl = tupleTypeDecl; - info.initExpr = initExpr; - info.primaryVarLayout = primaryVarLayout; - info.tupleTypeLayout = tupleTypeLayout; - - createTupleTypeSecondaryVarDecls(info); - - return LoweredDecl(tupleDecl); - } - - RefPtr getBodyStructTypeLayout(RefPtr typeLayout) - { - if (!typeLayout) - return nullptr; - - while (auto parameterGroupTypeLayout = typeLayout.As()) - { - typeLayout = parameterGroupTypeLayout->elementTypeLayout; - } - - while (auto arrayTypeLayout = typeLayout.As()) - { - typeLayout = arrayTypeLayout->elementTypeLayout; - } - - if (auto structTypeLayout = typeLayout.As()) - { - return structTypeLayout; - } - - return nullptr; - } - - LoweredDecl createTupleTypeVarDecls( - SyntaxClass varDeclClass, - RefPtr originalVarDecl, - String const& name, - RefPtr tupleType, - TupleTypeModifier* tupleTypeMod, - RefPtr initExpr, - RefPtr primaryVarLayout) - { - RefPtr tupleTypeLayout; - if (primaryVarLayout) - { - auto primaryTypeLayout = primaryVarLayout->typeLayout; - tupleTypeLayout = getBodyStructTypeLayout(primaryTypeLayout); - } - - return createTupleTypeVarDecls( - varDeclClass, - originalVarDecl, - name, - tupleType, - makeDeclRef(tupleTypeMod->decl), - tupleTypeMod, - initExpr, - primaryVarLayout, - tupleTypeLayout); - } - - LoweredDecl lowerVarDeclCommonInner( - VarDeclBase* decl, - SyntaxClass loweredDeclClass) - { - auto loweredType = lowerType(decl->type); - - if (auto tupleTypeMod = isTupleTypeOrArrayOfTupleType(loweredType)) - { - auto varLayout = tryToFindLayout(decl).As(); - - // 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->initExpr); - - // TODO: need to extract layout here and propagate it down! - - auto tupleDecl = createTupleTypeVarDecls( - loweredDeclClass, - decl, - getText(decl->getName()), - loweredType.type, - tupleTypeMod, - loweredInit, - varLayout); - - shared->loweredDecls.Add(decl, tupleDecl); - return tupleDecl; - } - if (auto bufferType = loweredType->As()) - { - auto varLayout = tryToFindLayout(decl).As(); - - auto elementType = bufferType->elementType; - if (auto elementTupleTypeMod = isTupleTypeOrArrayOfTupleType(elementType)) - { - auto tupleDecl = createTupleTypeVarDecls( - loweredDeclClass, - decl, - getText(decl->getName()), - loweredType.type, - elementTupleTypeMod, - nullptr, - varLayout); - - shared->loweredDecls.Add(decl, tupleDecl); - return tupleDecl; - } - } - - RefPtr loweredDecl = loweredDeclClass.createInstance(); - - // Note: we lower the declaration (including its initialization expression, if any) - // *before* we add the declaration to the current context (e.g., a statement being - // built), so that any operations inside the initialization expression that - // might need to inject statements/temporaries/whatever happen *before* - // the declaration of this variable. - auto result = lowerSimpleVarDeclCommon(loweredDecl, decl, loweredType); - addDecl(loweredDecl); - - return LoweredDecl(result); - } - - LoweredDecl lowerVarDeclCommon( - VarDeclBase* decl, - SyntaxClass loweredDeclClass) - { - // We need to add things to an appropriate scope, based on what - // we are referencing. - // - // If this is a global variable (program scope), then add it - // to the global scope. - RefPtr pp = decl->ParentDecl; - if (auto parentModuleDecl = pp.As()) - { - LoweringVisitor subVisitor = *this; - subVisitor.parentDecl = translateDeclRef(parentModuleDecl); - subVisitor.isBuildingStmt = false; - - return subVisitor.lowerVarDeclCommonInner(decl, loweredDeclClass); - } - // TODO: handle `static` function-scope variables - else - { - // The default behavior is to lower into whatever - // scope was already in places - return lowerVarDeclCommonInner(decl, loweredDeclClass); - } - } - - SourceLanguage getSourceLanguage(ModuleDecl* moduleDecl) - { - for (auto translationUnit : shared->compileRequest->translationUnits) - { - if (moduleDecl == translationUnit->SyntaxNode) - return translationUnit->sourceLanguage; - } - - for (auto loadedModuleDecl : shared->compileRequest->loadedModulesList) - { - if (moduleDecl == loadedModuleDecl) - return SourceLanguage::Slang; - } - - return SourceLanguage::Unknown; - } - - AggTypeDecl* isStructType(RefPtr type) - { - if (type->As()) return nullptr; - else if (type->As()) return nullptr; - else if (type->As()) return nullptr; - else if (type->As()) return nullptr; - else if (type->As()) return nullptr; - else if (auto declRefType = type->As()) - { - if (auto aggTypeDeclRef = declRefType->declRef.As()) - { - return aggTypeDeclRef.getDecl(); - } - } - - return nullptr; - } - - bool isImportedStructType(RefPtr type) - { - // TODO: make this use `isStructType` above - - if (type->As()) return false; - else if (type->As()) return false; - else if (type->As()) return false; - else if (type->As()) return false; - else if (type->As()) return false; - else if (auto declRefType = type->As()) - { - if (auto aggTypeDeclRef = declRefType->declRef.As()) - { - Decl* pp = aggTypeDeclRef.getDecl(); - while (pp->ParentDecl) - pp = pp->ParentDecl; - - // Did the declaration come from this translation unit? - if (pp == shared->entryPointRequest->getTranslationUnit()->SyntaxNode.Ptr()) - return false; - - return true; - } - } - - return false; - } - - LoweredDecl visitVariable( - Variable* decl) - { - if (dynamic_cast(decl->ParentDecl)) - { - auto varLayout = tryToFindLayout(decl); - if (varLayout) - { - auto inRes = varLayout->FindResourceInfo(LayoutResourceKind::VertexInput); - auto outRes = varLayout->FindResourceInfo(LayoutResourceKind::FragmentOutput); - - if( (inRes || outRes) && isImportedStructType(decl->type.type)) - { - // We are seemingly looking at a GLSL global-scope varying - // of an aggregate type which was imported from library - // code. We should destructure that into individual - // declarations. - - // We can't easily support `in out` declarations with this approach - SLANG_RELEASE_ASSERT(!(inRes && outRes)); - - LoweredExpr loweredExpr; - if (inRes) - { - loweredExpr = lowerShaderParameterToGLSLGLobals( - decl, - varLayout, - VaryingParameterDirection::Input); - } - - if (outRes) - { - loweredExpr = lowerShaderParameterToGLSLGLobals( - decl, - varLayout, - VaryingParameterDirection::Output); - } - -// SLANG_RELEASE_ASSERT(loweredExpr); - auto loweredDecl = createVaryingTupleVarDecl( - decl, - loweredExpr); - - registerLoweredDecl(LoweredDecl(loweredDecl), decl); - return LoweredDecl(loweredDecl); - } - } - } - - auto loweredDecl = lowerVarDeclCommon(decl, getClass()); - if(!loweredDecl.getValue()) - return LoweredDecl(); - - return loweredDecl; - } - - LoweredDecl visitStructField( - StructField* decl) - { - return LoweredDecl(lowerSimpleVarDeclCommon(new StructField(), decl)); - } - - LoweredDecl visitParamDecl( - ParamDecl* decl) - { - auto loweredDecl = lowerVarDeclCommon(decl, getClass()); - return loweredDecl; - } - - LoweredDecl transformSyntaxField(DeclBase* decl) - { - return lowerDeclBase(decl); - } - - - LoweredDecl visitDeclGroup( - DeclGroup* group) - { - for (auto decl : group->decls) - { - lowerDecl(decl); - } - return LoweredDecl(); - } - - LoweredDecl visitFunctionDeclBase( - FunctionDeclBase* decl) - { - // TODO: need to generate a name - - RefPtr loweredDecl = new FuncDecl(); - lowerDeclCommon(loweredDecl, decl); - - // TODO: push scope for parent decl here... - LoweringVisitor subVisitor = *this; - subVisitor.parentDecl = loweredDecl; - - // 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()) - { - subVisitor.translateDeclRef(paramDecl); - } - - auto loweredReturnType = subVisitor.lowerType(decl->ReturnType); - - loweredDecl->ReturnType = loweredReturnType; - - loweredDecl->Body = subVisitor.lowerStmt(decl->Body); - - // A lowered function always becomes a global-scope function, - // even if it had been a member function when declared. - addMember(shared->loweredProgram, loweredDecl); - - return LoweredDecl(loweredDecl); - } - - // - // Entry Points - // - - EntryPointLayout* findEntryPointLayout( - EntryPointRequest* entryPointRequest) - { - for( auto entryPointLayout : shared->programLayout->entryPoints ) - { - if(entryPointLayout->entryPoint->getName() != entryPointRequest->name) - continue; - - if(entryPointLayout->profile != entryPointRequest->profile) - continue; - - // TODO: can't easily filter on translation unit here... - // Ideally the `EntryPointRequest` should get filled in with a pointer - // the specific function declaration that represents the entry point. - - return entryPointLayout.Ptr(); - } - - return nullptr; - } - - enum class VaryingParameterDirection - { - Input, - Output, - }; - - struct VaryingParameterArraySpec - { - VaryingParameterArraySpec* next = nullptr; - IntVal* elementCount; - }; - - struct VaryingParameterVarChain - { - VaryingParameterVarChain* next = nullptr; - VarDeclBase* varDecl; - }; - - template - T* findModifier(VaryingParameterVarChain* chain) - { - for (auto c = chain; c; c = c->next) - { - auto v = c->varDecl; - if (auto mod = v->FindModifier()) - return mod; - } - return nullptr; - } - - RefPtr cloneModifier(Modifier* modifier) - { - if (!modifier) return nullptr; - - // For now we just do a shallow copy of the modifier - - CloneVisitor visitor; - return visitor.dispatch(modifier); - } - - struct VaryingParameterInfo - { - String name; - VaryingParameterDirection direction; - VaryingParameterArraySpec* arraySpecs = nullptr; - VaryingParameterVarChain* varChain = nullptr; - }; - - RefPtr createGLSLBuiltinRef( - char const* name, - RefPtr type) - { - RefPtr globalVarRef = new VarExpr(); - globalVarRef->name = getName(name); - globalVarRef->type.type = type; - return globalVarRef; - } - - bool isIntegralType( - Type* type) - { - if (auto baseType = type->As()) - { - switch (baseType->baseType) - { - default: - return false; - - case BaseType::Int: - case BaseType::UInt: - case BaseType::UInt64: - return true; - } - } - else if (auto vecType = type->As()) - { - return isIntegralType(vecType->elementType); - } - else if (auto matType = type->As()) - { - return isIntegralType(matType->getElementType()); - } - - return false; - } - - void requireGLSLVersion(ProfileVersion version) - { - if (shared->target != CodeGenTarget::GLSL) - return; - - auto entryPoint = shared->entryPointRequest; - Slang::requireGLSLVersion(entryPoint, version); - } - - RefPtr getFloatType() - { - return getSession()->getFloatType(); - } - - RefPtr getIntType() - { - return getSession()->getIntType(); - } - - RefPtr getUIntType() - { - return getSession()->getUIntType(); - } - - RefPtr getBoolType() - { - return getSession()->getBoolType(); - } - - RefPtr getVectorType( - RefPtr elementType, - RefPtr elementCount) - { - auto session = getSession(); - auto vectorGenericDecl = findMagicDecl( - session, - "Vector").As(); - auto vectorTypeDecl = vectorGenericDecl->inner; - - auto substs = new GenericSubstitution(); - substs->genericDecl = vectorGenericDecl.Ptr(); - substs->args.Add(elementType); - substs->args.Add(elementCount); - - auto declRef = DeclRef(vectorTypeDecl.Ptr(), substs); - - return DeclRefType::Create( - session, - declRef)->As(); - } - - RefPtr getConstantIntVal(IntegerLiteralValue value) - { - RefPtr intVal = new ConstantIntVal(); - intVal->value = value; - return intVal; - } - - RefPtr getVectorType( - RefPtr elementType, - int elementCount) - { - return getVectorType(elementType, getConstantIntVal(elementCount)); - } - - RefPtr getUnsizedArrayType( - RefPtr elementType) - { - RefPtr arrayType = Slang::getArrayType(elementType); - return arrayType; - } - - RefPtr getArrayType( - RefPtr elementType, - IntegerLiteralValue elementCount) - { - return Slang::getArrayType(elementType, getConstantIntVal(elementCount)); - } - - LoweredExpr lowerSimpleShaderParameterToGLSLGlobal( - VaryingParameterInfo const& info, - RefPtr varType, - RefPtr varLayout) - { - RefPtr type = varType; - - for (auto aa = info.arraySpecs; aa; aa = aa->next) - { - RefPtr arrayType = Slang::getArrayType( - type, - aa->elementCount); - - type = arrayType; - } - - assert(type); - - // We need to create a reference to the global-scope declaration - // of the proper GLSL input/output variable. This might - // be a user-defined input/output, or a system-defined `gl_` one. - RefPtr globalVarExpr; - - // Handle system-value inputs/outputs - SLANG_RELEASE_ASSERT(varLayout); - auto systemValueSemantic = varLayout->systemValueSemantic; - if (systemValueSemantic.Length() != 0) - { - auto ns = systemValueSemantic.ToLower(); - - if (ns == "sv_target") - { - // Note: we do *not* need to generate some kind of `gl_` - // builtin for fragment-shader outputs: they are just - // ordinary `out` variables, with ordinary `location`s, - // as far as GLSL is concerned. - } - else if (ns == "sv_position") - { - if (info.direction == VaryingParameterDirection::Input) - { - globalVarExpr = createGLSLBuiltinRef("gl_FragCoord", getVectorType(getFloatType(), 4)); - } - else - { - globalVarExpr = createGLSLBuiltinRef("gl_Position", getVectorType(getFloatType(), 4)); - } - } - else if (ns == "sv_clipdistance") - { - globalVarExpr = createGLSLBuiltinRef("gl_ClipDistance", getUnsizedArrayType(getFloatType())); - } - else if (ns == "sv_culldistance") - { - requireGLSLExtension(shared->extensionUsageTracker, "ARB_cull_distance"); - globalVarExpr = createGLSLBuiltinRef("gl_CullDistance", getUnsizedArrayType(getFloatType())); - } - else if (ns == "sv_coverage") - { - if (info.direction == VaryingParameterDirection::Input) - { - globalVarExpr = createGLSLBuiltinRef("gl_SampleMaskIn", getUnsizedArrayType(getIntType())); - } - else - { - globalVarExpr = createGLSLBuiltinRef("gl_SampleMask", getUnsizedArrayType(getIntType())); - } - } - else if (ns == "sv_depth") - { - globalVarExpr = createGLSLBuiltinRef("gl_FragDepth", getFloatType()); - } - else if (ns == "sv_depthgreaterequal") - { - // TODO: layout(depth_greater) out float gl_FragDepth; - globalVarExpr = createGLSLBuiltinRef("gl_FragDepth", getFloatType()); - } - else if (ns == "sv_depthlessequal") - { - // TODO: layout(depth_less) out float gl_FragDepth; - globalVarExpr = createGLSLBuiltinRef("gl_FragDepth", getFloatType()); - } - else if (ns == "sv_dispatchthreadid") - { - globalVarExpr = createGLSLBuiltinRef("gl_GlobalInvocationID", getVectorType(getUIntType(), 3)); - } - else if (ns == "sv_domainlocation") - { - globalVarExpr = createGLSLBuiltinRef("gl_TessCoord", getVectorType(getFloatType(), 3)); - } - else if (ns == "sv_groupid") - { - globalVarExpr = createGLSLBuiltinRef("gl_WorkGroupID", getVectorType(getUIntType(), 3)); - } - else if (ns == "sv_groupindex") - { - globalVarExpr = createGLSLBuiltinRef("gl_LocalInvocationIndex", getUIntType()); - } - else if (ns == "sv_groupthreadid") - { - globalVarExpr = createGLSLBuiltinRef("gl_LocalInvocationID", getVectorType(getUIntType(), 3)); - } - else if (ns == "sv_gsinstanceid") - { - globalVarExpr = createGLSLBuiltinRef("gl_InvocationID", getIntType()); - } - else if (ns == "sv_insidetessfactor") - { - globalVarExpr = createGLSLBuiltinRef("gl_TessLevelInner", getArrayType(getFloatType(), 2)); - } - else if (ns == "sv_instanceid") - { - globalVarExpr = createGLSLBuiltinRef("gl_InstanceIndex", getIntType()); - } - else if (ns == "sv_isfrontface") - { - globalVarExpr = createGLSLBuiltinRef("gl_FrontFacing", getBoolType()); - } - else if (ns == "sv_outputcontrolpointid") - { - globalVarExpr = createGLSLBuiltinRef("gl_InvocationID", getIntType()); - } - else if (ns == "sv_primitiveid") - { - globalVarExpr = createGLSLBuiltinRef("gl_PrimitiveID", getIntType()); - } - else if (ns == "sv_rendertargetarrayindex") - { - switch (shared->entryPointRequest->profile.GetStage()) - { - case Stage::Geometry: - requireGLSLVersion(ProfileVersion::GLSL_150); - break; - - case Stage::Fragment: - requireGLSLVersion(ProfileVersion::GLSL_430); - break; - - default: - requireGLSLVersion(ProfileVersion::GLSL_450); - requireGLSLExtension(shared->extensionUsageTracker, "GL_ARB_shader_viewport_layer_array"); - break; - } - - globalVarExpr = createGLSLBuiltinRef("gl_Layer", getIntType()); - } - else if (ns == "sv_sampleindex") - { - globalVarExpr = createGLSLBuiltinRef("gl_SampleID", getIntType()); - } - else if (ns == "sv_stencilref") - { - requireGLSLExtension(shared->extensionUsageTracker, "ARB_shader_stencil_export"); - globalVarExpr = createGLSLBuiltinRef("gl_FragStencilRef", getIntType()); - } - else if (ns == "sv_tessfactor") - { - globalVarExpr = createGLSLBuiltinRef("gl_TessLevelOuter", getArrayType(getFloatType(), 4)); - } - else if (ns == "sv_vertexid") - { - globalVarExpr = createGLSLBuiltinRef("gl_VertexIndex", getIntType()); - } - else if (ns == "sv_viewportarrayindex") - { - globalVarExpr = createGLSLBuiltinRef("gl_ViewportIndex", getIntType()); - } - else if (ns == "nv_x_right") - { - requireGLSLVersion(ProfileVersion::GLSL_450); - requireGLSLExtension(shared->extensionUsageTracker, "GL_NVX_multiview_per_view_attributes"); - - // The actual output in GLSL is: - // - // vec4 gl_PositionPerViewNV[]; - // - // and is meant to support an arbitrary number of views, - // while the HLSL case just defines a second position - // output. - // - // For now we will hack this by: - // 1. Mapping an `NV_X_Right` output to `gl_PositionPerViewNV[1]` - // (that is, just one element of the output array) - // 2. Adding logic to copy the traditional `gl_Position` output - // over to `gl_PositionPerViewNV[0]` - // - - globalVarExpr = createGLSLBuiltinRef("gl_PositionPerViewNV[1]", - getVectorType(getFloatType(), 4)); - - shared->requiresCopyGLPositionToPositionPerView = true; - } - else if (ns == "nv_viewport_mask") - { - requireGLSLVersion(ProfileVersion::GLSL_450); - requireGLSLExtension(shared->extensionUsageTracker, "GL_NVX_multiview_per_view_attributes"); - globalVarExpr = createGLSLBuiltinRef("gl_ViewportMaskPerViewNV", - getUnsizedArrayType(getIntType())); - } - else - { - getSink()->diagnose(info.varChain->varDecl, Diagnostics::unknownSystemValueSemantic, systemValueSemantic); - } - } - - // If we didn't match some kind of builtin input/output, - // then declare a user input/output variable instead - if (!globalVarExpr) - { - RefPtr globalVarDecl = new Variable(); - globalVarDecl->nameAndLoc.name = getName(info.name); - globalVarDecl->type.type = type; - - ensureDeclHasAValidName(globalVarDecl); - - addMember(shared->loweredProgram, globalVarDecl); - - // Add the layout information - RefPtr modifier = new ComputedLayoutModifier(); - modifier->layout = varLayout; - addModifier(globalVarDecl, modifier); - - // Add appropriate in/out modifier - switch (info.direction) - { - case VaryingParameterDirection::Input: - addModifier(globalVarDecl, new InModifier()); - break; - - case VaryingParameterDirection::Output: - addModifier(globalVarDecl, new OutModifier()); - break; - } - - // We want to copy certain modifiers from the declaration as given, - // over to the newly created global variable. The most important - // of these is any interpolation-mode modifier. - // - // Note that a shader parameter could have been nested inside - // a `struct` type, so we will look for interpolation modifiers - // starting on the "deepest" field, and working out way out. - - // Look for interpolation mode modifier - if (auto interpolationModeModifier = findModifier(info.varChain)) - { - addModifier(globalVarDecl, cloneModifier(interpolationModeModifier)); - } - // Otherwise, check if we need to add one: - else if (isIntegralType(varType)) - { - if (info.direction == VaryingParameterDirection::Input - && shared->entryPointRequest->profile.GetStage() != Stage::Fragment) - { - // Don't add extra qualification to vertex shader inputs - } - else if (info.direction == VaryingParameterDirection::Output - && shared->entryPointRequest->profile.GetStage() == Stage::Fragment) - { - // Don't add extra qualification to fragment shader outputs - } - else - { - auto mod = new HLSLNoInterpolationModifier(); - addModifier(globalVarDecl, mod); - } - } - - - RefPtr globalVarRef = new VarExpr(); - globalVarRef->loc = globalVarDecl->loc; - globalVarRef->type.type = globalVarDecl->type.type; - globalVarRef->declRef = makeDeclRef(globalVarDecl.Ptr()); - globalVarRef->name = globalVarDecl->getName(); - - globalVarExpr = globalVarRef; - } - - return LoweredExpr(globalVarExpr); - } - - LoweredExpr lowerShaderParameterToGLSLGLobalsRec( - VaryingParameterInfo const& info, - RefPtr varType, - RefPtr varLayout) - { - SLANG_RELEASE_ASSERT(varLayout); - - if (auto basicType = varType->As()) - { - // handled below - } - else if (auto vectorType = varType->As()) - { - // handled below - } - else if (auto matrixType = varType->As()) - { - // handled below - } - else if (auto arrayType = varType->As()) - { - // We will accumulate information on the array - // types that were encoutnered on our walk down - // to the leaves, and then apply these array dimensions - // to any leaf parameters. - - VaryingParameterArraySpec arraySpec; - arraySpec.next = info.arraySpecs; - arraySpec.elementCount = arrayType->ArrayLength; - - VaryingParameterInfo arrayInfo = info; - arrayInfo.arraySpecs = &arraySpec; - - // Note that we use the original `varLayout` that was passed in, - // since that is the layout that will ultimately need to be - // used on the array elements. - // - // TODO: That won't actually work if we ever had an array of - // heterogeneous stuff... - return lowerShaderParameterToGLSLGLobalsRec( - arrayInfo, - arrayType->baseType, - varLayout); - } - else if (auto declRefType = varType->As()) - { - auto declRef = declRefType->declRef; - if (auto aggTypeDeclRef = declRef.As()) - { - // The shader parameter had a structured type, so we need - // to destructure it into its constituent fields - - RefPtr tupleExpr = new VaryingTupleExpr(); - tupleExpr->type.type = varType; - - SLANG_RELEASE_ASSERT(tupleExpr->type.type); - - for (auto fieldDeclRef : getMembersOfType(aggTypeDeclRef)) - { - // Don't emit storage for `static` fields here, of course - if (fieldDeclRef.getDecl()->HasModifier()) - continue; - - VaryingParameterVarChain fieldVarChain; - fieldVarChain.next = info.varChain; - fieldVarChain.varDecl = fieldDeclRef.getDecl(); - - VaryingParameterInfo fieldInfo = info; - fieldInfo.name = info.name + "_" + getText(fieldDeclRef.GetName()); - fieldInfo.varChain = &fieldVarChain; - - // Need to find the layout for the given field... - Decl* originalFieldDecl = nullptr; - shared->mapLoweredDeclToOriginal.TryGetValue(fieldDeclRef.getDecl(), originalFieldDecl); - SLANG_RELEASE_ASSERT(originalFieldDecl); - - auto structTypeLayout = varLayout->typeLayout.As(); - SLANG_RELEASE_EXPECT(structTypeLayout, "expected a structure type layout"); - - RefPtr fieldLayout; - structTypeLayout->mapVarToLayout.TryGetValue(originalFieldDecl, fieldLayout); - SLANG_RELEASE_ASSERT(fieldLayout); - - auto loweredFieldExpr = lowerShaderParameterToGLSLGLobalsRec( - fieldInfo, - GetType(fieldDeclRef), - fieldLayout); - - VaryingTupleExpr::Element elem; - elem.originalFieldDeclRef = makeDeclRef(originalFieldDecl).As(); - elem.expr = loweredFieldExpr; - - tupleExpr->elements.Add(elem); - } - - // Okay, we are done with this parameter - return LoweredExpr(tupleExpr); - } - } - - // Default case: just try to emit things as-is - return lowerSimpleShaderParameterToGLSLGlobal(info, varType, varLayout); - } - - LoweredExpr lowerShaderParameterToGLSLGLobals( - RefPtr originalVarDecl, - RefPtr paramLayout, - VaryingParameterDirection direction) - { - auto name = originalVarDecl->getName(); - auto nameText = getText(name); - auto declRef = makeDeclRef(originalVarDecl.Ptr()); - - VaryingParameterVarChain varChain; - varChain.next = nullptr; - varChain.varDecl = originalVarDecl; - - VaryingParameterInfo info; - info.name = nameText; - info.direction = direction; - info.varChain = &varChain; - - // Ensure that we don't get name collisions on `inout` variables - switch (direction) - { - case VaryingParameterDirection::Input: - info.name = "SLANG_in_" + nameText; - break; - - case VaryingParameterDirection::Output: - info.name = "SLANG_out_" + nameText; - break; - } - - auto loweredType = lowerType(originalVarDecl->type); - - auto loweredExpr = lowerShaderParameterToGLSLGLobalsRec( - info, - loweredType.type, - paramLayout); - -#if 0 - RefPtr loweredDecl = createVaryingTupleVarDecl( - originalVarDecl, - loweredType, - loweredExpr); - - registerLoweredDecl(loweredDecl, originalVarDecl); - addDecl(loweredDecl); -#endif - - return loweredExpr; - } - - RefPtr createVaryingTupleVarDecl( - RefPtr originalVarDecl, - TypeExp const& loweredType, - LoweredExpr loweredExpr) - { - RefPtr loweredDecl = new VaryingTupleVarDecl(); - loweredDecl->nameAndLoc = originalVarDecl->nameAndLoc; - loweredDecl->type = loweredType; - loweredDecl->expr = loweredExpr; - - return loweredDecl; - } - - RefPtr createVaryingTupleVarDecl( - RefPtr originalVarDecl, - LoweredExpr loweredExpr) - { - auto loweredType = lowerType(originalVarDecl->type); - return createVaryingTupleVarDecl(originalVarDecl, loweredType, loweredExpr); - } - - struct EntryPointParamPair - { - RefPtr original; - RefPtr layout; - RefPtr lowered; - }; - - RefPtr lowerEntryPointToGLSL( - FuncDecl* entryPointDecl, - RefPtr entryPointLayout) - { - // First, loer the entry-point function as an ordinary function: - auto loweredEntryPointFunc = visitFunctionDeclBase(entryPointDecl).getDecl()->As(); - - auto mainName = getName("main"); - - // Now we will generate a `void main() { ... }` function to call the lowered code. - RefPtr mainDecl = new FuncDecl(); - mainDecl->ReturnType.type = getSession()->getVoidType(); - - - mainDecl->nameAndLoc = NameLoc(mainName); - - // If the user's entry point was called `main` then rename it here - if (loweredEntryPointFunc->getName() == mainName) - loweredEntryPointFunc->nameAndLoc = NameLoc(getName("main_")); - - RefPtr bodyStmt = new BlockStmt(); - bodyStmt->scopeDecl = new ScopeDecl(); - - // We will want to generate declarations into the body of our new `main()` - LoweringVisitor subVisitor = *this; - subVisitor.isBuildingStmt = true; - subVisitor.stmtBeingBuilt = nullptr; - subVisitor.parentDecl = bodyStmt->scopeDecl; - - // The parameters of the entry-point function will be translated to - // both a local variable (for passing to/from the entry point func), - // and to global variables (used for parameter passing) - - List params; - - // First generate declarations for the locals - for (auto paramDecl : entryPointDecl->GetParameters()) - { - RefPtr paramLayout; - entryPointLayout->mapVarToLayout.TryGetValue(paramDecl.Ptr(), paramLayout); - SLANG_RELEASE_ASSERT(paramLayout); - - RefPtr localVarDecl = new Variable(); - localVarDecl->loc = paramDecl->loc; - localVarDecl->nameAndLoc = paramDecl->getNameAndLoc(); - localVarDecl->type = lowerType(paramDecl->type); - - ensureDeclHasAValidName(localVarDecl); - - subVisitor.addDecl(localVarDecl); - - EntryPointParamPair paramPair; - paramPair.original = paramDecl; - paramPair.layout = paramLayout; - paramPair.lowered = localVarDecl; - - params.Add(paramPair); - } - - // Next generate globals for the inputs, and initialize them - for (auto paramPair : params) - { - auto paramDecl = paramPair.original; - if (paramDecl->HasModifier() - || paramDecl->HasModifier() - || !paramDecl->HasModifier()) - { - auto loweredExpr = subVisitor.lowerShaderParameterToGLSLGLobals( - paramPair.original, - paramPair.layout, - VaryingParameterDirection::Input); - - subVisitor.assignWithFixups(paramPair.lowered, loweredExpr); - } - } - - // Generate a local variable for the result, if any - RefPtr resultVarDecl; - if (!loweredEntryPointFunc->ReturnType->Equals(getSession()->getVoidType())) - { - resultVarDecl = new Variable(); - resultVarDecl->loc = loweredEntryPointFunc->loc; - resultVarDecl->nameAndLoc = NameLoc(getName("main_result")); - resultVarDecl->type = TypeExp(loweredEntryPointFunc->ReturnType); - - ensureDeclHasAValidName(resultVarDecl); - - subVisitor.addDecl(resultVarDecl); - } - - // Now generate a call to the entry-point function, using the local variables - auto entryPointDeclRef = makeDeclRef(loweredEntryPointFunc); - - auto entryPointType = getFuncType( - getSession(), - entryPointDeclRef); - - RefPtr entryPointRef = new VarExpr(); - entryPointRef->name = loweredEntryPointFunc->getName(); - entryPointRef->declRef = entryPointDeclRef; - entryPointRef->type = QualType(entryPointType); - - RefPtr callExpr = new InvokeExpr(); - callExpr->FunctionExpr = entryPointRef; - callExpr->type = QualType(loweredEntryPointFunc->ReturnType); - - // - for (auto paramPair : params) - { - auto localVarDecl = paramPair.lowered; - - RefPtr varRef = new VarExpr(); - varRef->name = localVarDecl->getName(); - varRef->declRef = makeDeclRef(localVarDecl.Ptr()); - varRef->type = QualType(localVarDecl->getType()); - - callExpr->Arguments.Add(varRef); - } - - if (resultVarDecl) - { - // Non-`void` return type, so we need to store it - subVisitor.assign(resultVarDecl, LoweredExpr(callExpr)); - } - else - { - // `void` return type: just call it - subVisitor.addExprStmt(LoweredExpr(callExpr)); - } - - - // Finally, generate logic to copy the outputs to global parameters - for (auto paramPair : params) - { - auto paramDecl = paramPair.original; - if (paramDecl->HasModifier() - || paramDecl->HasModifier()) - { - auto loweredExpr = subVisitor.lowerShaderParameterToGLSLGLobals( - paramPair.original, - paramPair.layout, - VaryingParameterDirection::Output); - - subVisitor.assignWithFixups(loweredExpr, paramPair.lowered); - } - } - if (resultVarDecl) - { - VaryingParameterInfo info; - info.name = "SLANG_out_" + getText(resultVarDecl->getName()); - info.direction = VaryingParameterDirection::Output; - info.varChain = nullptr; - - auto loweredExpr = lowerShaderParameterToGLSLGLobalsRec( - info, - resultVarDecl->type.type, - entryPointLayout->resultLayout); - - subVisitor.assignWithFixups(loweredExpr, resultVarDecl); - } - if (shared->requiresCopyGLPositionToPositionPerView) - { - subVisitor.assign( - LoweredExpr(createSimpleVarExpr("gl_PositionPerViewNV[0]")), - LoweredExpr(createSimpleVarExpr("gl_Position"))); - } - - bodyStmt->body = subVisitor.stmtBeingBuilt; - - mainDecl->Body = bodyStmt; - - - // Once we are done building the body, we append our new declaration to the program. - addMember(shared->loweredProgram, mainDecl); - return mainDecl; - -#if 0 - RefPtr loweredDecl = new FuncDecl(); - lowerDeclCommon(loweredDecl, entryPointDecl); - - // We create a sub-context appropriate for lowering the function body - - LoweringVisitor subVisitor = *this; - subVisitor.isBuildingStmt = true; - subVisitor.stmtBeingBuilt = nullptr; - - // The parameters of the entry-point function must be translated - // to global-scope declarations - for (auto paramDecl : entryPointDecl->GetParameters()) - { - subVisitor.lowerShaderParameterToGLSLGLobals(paramDecl); - } - - // The output of the function must also be translated into a - // global-scope declaration. - auto loweredReturnType = lowerType(entryPointDecl->ReturnType); - RefPtr resultGlobal; - if (!loweredReturnType->Equals(getSession()->getVoidType())) - { - resultGlobal = new Variable(); - // TODO: need a scheme for generating unique names - resultGlobal->name.Content = "_main_result"; - resultGlobal->type = loweredReturnType; - - addMember(shared->loweredProgram, resultGlobal); - } - - loweredDecl->name.Content = "main"; - loweredDecl->ReturnType.type = getSession()->getVoidType(); - - // We will emit the body statement in a context where - // a `return` statmenet will generate writes to the - // result global that we declared. - subVisitor.resultVariable = resultGlobal; - - auto loweredBody = subVisitor.lowerStmt(entryPointDecl->Body); - subVisitor.addStmt(loweredBody); - - loweredDecl->Body = subVisitor.stmtBeingBuilt; - - // TODO: need to append writes for `out` parameters here... - - addMember(shared->loweredProgram, loweredDecl); - return loweredDecl; -#endif - } - - RefPtr lowerEntryPoint( - FuncDecl* entryPointDecl, - RefPtr entryPointLayout) - { - switch( getTarget() ) - { - // Default case: lower an entry point just like any other function - default: - return visitFunctionDeclBase(entryPointDecl).getDecl()->As(); - - // For Slang->GLSL translation, we need to lower things from HLSL-style - // declarations over to GLSL conventions - case CodeGenTarget::GLSL: - return lowerEntryPointToGLSL(entryPointDecl, entryPointLayout); - } - } - - RefPtr lowerEntryPoint( - EntryPointRequest* entryPointRequest) - { - auto entryPointLayout = findEntryPointLayout(entryPointRequest); - auto entryPointDecl = entryPointLayout->entryPoint; - - return lowerEntryPoint( - entryPointDecl, - entryPointLayout); - } - - -}; - -StructTypeLayout* getGlobalStructLayout( - ProgramLayout* programLayout); - -// Determine if the user is just trying to "rewrite" their input file -// into an output file. This will affect the way we approach code -// generation, because we want to leave their code "as is" whenever -// possible. -bool isRewriteRequest( - SourceLanguage sourceLanguage, - CodeGenTarget target) -{ - // TODO: we might only consider things to be a rewrite request - // in the specific case where checking is turned off... - - switch( target ) - { - default: - return false; - - case CodeGenTarget::HLSL: - return sourceLanguage == SourceLanguage::HLSL; - - case CodeGenTarget::GLSL: - return sourceLanguage == SourceLanguage::GLSL; - } -} - - - -LoweredEntryPoint lowerEntryPoint( - EntryPointRequest* entryPoint, - ProgramLayout* programLayout, - CodeGenTarget target, - ExtensionUsageTracker* extensionUsageTracker) -{ - SharedLoweringContext sharedContext; - sharedContext.compileRequest = entryPoint->compileRequest; - sharedContext.entryPointRequest = entryPoint; - sharedContext.programLayout = programLayout; - sharedContext.target = target; - sharedContext.extensionUsageTracker = extensionUsageTracker; - - auto translationUnit = entryPoint->getTranslationUnit(); - - // Create a single module/program to hold all the lowered code - // (with the exception of instrinsic/stdlib declarations, which - // will be remain where they are) - RefPtr loweredProgram = new ModuleDecl(); - sharedContext.loweredProgram = loweredProgram; - - LoweringVisitor visitor; - visitor.shared = &sharedContext; - visitor.parentDecl = loweredProgram; - - // TODO: this should only need to take the shared context - visitor.registerReservedWords(); - - // We need to register the lowered program as the lowered version - // of the existing translation unit declaration. - - visitor.registerLoweredDecl( - LoweredDecl(loweredProgram), - translationUnit->SyntaxNode); - - // We also need to register the lowered program as the lowered version - // of any imported modules (since we will be collecting everything into - // a single module for code generation). - for (auto rr : entryPoint->compileRequest->loadedModulesList) - { - sharedContext.loweredDecls.Add( - rr, - LoweredDecl(loweredProgram)); - } - - // We also want to remember the layout information for - // that declaration, so that we can apply it during emission - attachLayout(loweredProgram, - getGlobalStructLayout(programLayout)); - - - bool isRewrite = isRewriteRequest(translationUnit->sourceLanguage, target); - sharedContext.isRewrite = isRewrite; - - sharedContext.entryPointLayout = visitor.findEntryPointLayout(entryPoint); - - LoweredEntryPoint result; - if (isRewrite) - { - for (auto dd : translationUnit->SyntaxNode->Members) - { - visitor.translateDeclRef(dd); - } - } - else - { - auto loweredEntryPoint = visitor.lowerEntryPoint(entryPoint); - result.entryPoint = loweredEntryPoint; - } - - result.program = sharedContext.loweredProgram; - - return result; -} -} -- cgit v1.2.3