diff options
| -rw-r--r-- | source/slang/diagnostic-defs.h | 3 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 43 | ||||
| -rw-r--r-- | source/slang/ir-ssa.cpp | 36 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 108 | ||||
| -rw-r--r-- | source/slang/ir.h | 7 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 17 | ||||
| -rw-r--r-- | tests/reflection/gh-55.glsl | 6 | ||||
| -rw-r--r-- | tests/reflection/image-types.glsl | 12 | ||||
| -rw-r--r-- | tests/reflection/image-types.glsl.expected | 33 | ||||
| -rw-r--r-- | tests/reflection/std430-layout.glsl | 6 |
10 files changed, 182 insertions, 89 deletions
diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h index 698591d35..82aed2d69 100644 --- a/source/slang/diagnostic-defs.h +++ b/source/slang/diagnostic-defs.h @@ -68,6 +68,9 @@ DIAGNOSTIC( 6, Error, cannotDeduceOutputFormatFromPath, DIAGNOSTIC( 6, Error, explicitOutputPathsAndMultipleTargets, "canot use both explicit output paths ('-o') and multiple targets ('-target')") +DIAGNOSTIC( 7, Error, glslIsNotSupported, + "the Slang compiler does not support GLSL as a source language"); + // // 1xxxx - Lexical anaylsis // diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index a27492c0b..0cd896ced 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -2,6 +2,7 @@ #include "emit.h" #include "ir-insts.h" +#include "ir-ssa.h" #include "legalize-types.h" #include "lower-to-ir.h" #include "mangle.h" @@ -7212,15 +7213,10 @@ emitDeclImpl(decl, nullptr); } #endif - void emitIRVarModifiers( + void emitIRMatrixLayoutModifiers( EmitContext* ctx, VarLayout* layout) { - if (!layout) - return; - - auto target = ctx->shared->target; - // We need to handle the case where the variable has // a matrix type, and has been given a non-standard // layout attribute (for HLSL, `row_major` is the @@ -7228,6 +7224,8 @@ emitDeclImpl(decl, nullptr); // if (auto matrixTypeLayout = layout->typeLayout.As<MatrixTypeLayout>()) { + auto target = ctx->shared->target; + switch (target) { case CodeGenTarget::HLSL: @@ -7269,6 +7267,17 @@ emitDeclImpl(decl, nullptr); } + } + + void emitIRVarModifiers( + EmitContext* ctx, + VarLayout* layout) + { + if (!layout) + return; + + emitIRMatrixLayoutModifiers(ctx, layout); + if (ctx->shared->target == CodeGenTarget::GLSL) { // Layout-related modifiers need to come before the declaration, @@ -7539,7 +7548,19 @@ emitDeclImpl(decl, nullptr); if(fieldType->Equals(getSession()->getVoidType())) continue; - emitIRVarModifiers(ctx, fieldLayout); + // Note: we will emit matrix-layout modifiers here, but + // we will refrain from emitting other modifiers that + // might not be appropriate to the context (e.g., we + // shouldn't go emitting `uniform` just because these + // things are uniform...). + // + // TODO: we need a more refined set of modifiers that + // we should allow on fields, because we might end + // up supporting layout that isn't the default for + // the given block type (e.g., something other than + // `std140` for a uniform block). + // + emitIRMatrixLayoutModifiers(ctx, fieldLayout); emitIRType(ctx, fieldType, getIRName(ff)); @@ -8240,6 +8261,14 @@ String emitEntryPoint( fprintf(stderr, "###\n"); #endif + // Once specialization and type legalization have been performed, + // we should perform some of our basic optimization steps again, + // to see if we can clean up any temporaries created by legalization. + // (e.g., things that used to be aggregated might now be split up, + // so that we can work with the individual fields). + constructSSA(irModule); + + // After all of the required optimization and legalization // passes have been performed, we can emit target code from // the IR module. diff --git a/source/slang/ir-ssa.cpp b/source/slang/ir-ssa.cpp index 432dfc1b1..53eefd81f 100644 --- a/source/slang/ir-ssa.cpp +++ b/source/slang/ir-ssa.cpp @@ -89,7 +89,9 @@ struct ConstructSSAContext PhiInfo* getPhiInfo(IRParam* phi) { - return *phiInfos.TryGetValue(phi); + if(auto found = phiInfos.TryGetValue(phi)) + return *found; + return nullptr; } }; @@ -219,7 +221,7 @@ PhiInfo* addPhi( } IRValue* tryRemoveTrivialPhi( - ConstructSSAContext* /*context*/, + ConstructSSAContext* context, PhiInfo* phiInfo) { auto phi = phiInfo->phi; @@ -266,6 +268,26 @@ IRValue* tryRemoveTrivialPhi( assert(!"unimplemented"); } + // Removing this phi as trivial may make other phi nodes + // become trivial. We will recognize such candidates + // by looking for phi nodes that use this node. + List<PhiInfo*> otherPhis; + for( auto u = phi->firstUse; u; u = u->nextUse ) + { + auto user = u->user; + if(!user) continue; + if(user == phi) continue; + + if( user->op == kIROp_Param ) + { + auto maybeOtherPhi = (IRParam*) user; + if( auto otherPhiInfo = context->getPhiInfo(maybeOtherPhi) ) + { + otherPhis.Add(otherPhiInfo); + } + } + } + // replace uses of the phi (including its possible uses // of itself) with the unique non-phi value. phi->replaceUsesWith(same); @@ -281,8 +303,12 @@ IRValue* tryRemoveTrivialPhi( // phi, so that we can easily look it up later. phiInfo->replacement = same; - // TODO: need to recursively consider chances to simplify - // other phi nodes now. + // Now that we've cleaned up this phi, we need to consider + // other phis that might have become trivial. + for( auto otherPhi : otherPhis ) + { + tryRemoveTrivialPhi(context, otherPhi); + } return same; } @@ -320,7 +346,7 @@ IRValue* addPhiOperands( phiInfo->operands.SetSize(operandCount); for(UInt ii = 0; ii < operandCount; ++ii) { - phiInfo->operands[ii].init(nullptr, operandValues[ii]); + phiInfo->operands[ii].init(phiInfo->phi, operandValues[ii]); } return tryRemoveTrivialPhi(context, phiInfo); diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index 50b0b83e9..3d04e9807 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -2867,47 +2867,82 @@ namespace Slang }; Flavor flavor; - Val* elementCount; + IntVal* elementCount; GlobalVaryingDeclarator* next; }; ScalarizedVal createSimpleGLSLGlobalVarying( IRBuilder* builder, - Type* type, - VarLayout* varLayout, - TypeLayout* /*typeLayout*/, - LayoutResourceKind /*kind*/, - GlobalVaryingDeclarator* /*declarator*/) - { - // TODO: We might be creating an `in` or `out` variable based on - // an `in out` function parameter. In this case we should - // rewrite the `typeLayout` to only include the information - // for the appropriate `kind`. - // - // TODO: actually, we should *always* be re-creating the layout, - // because we need to apply any offsets from the parent... - - // TODO: If there are any `declarator`s, we need to unwrap - // them here, and allow them to modify the type of the - // variable that we declare. - // - // They should probably also affect how we return the - // `ScalarizedVal`, since we need to reflect the AOS->SOA conversion. - + Type* inType, + VarLayout* inVarLayout, + TypeLayout* inTypeLayout, + LayoutResourceKind kind, + UInt bindingIndex, + GlobalVaryingDeclarator* declarator) + { // TODO: detect when the layout represents a system input/output - if( varLayout->systemValueSemantic.Length() != 0 ) + if( inVarLayout->systemValueSemantic.Length() != 0 ) { // This variable represents a system input/output, // and we should probably handle that differently, right? } + RefPtr<Type> type = inType; + RefPtr<TypeLayout> typeLayout = inTypeLayout; + for( auto dd = declarator; dd; dd = dd->next ) + { + assert(dd->flavor == GlobalVaryingDeclarator::Flavor::array); + + RefPtr<ArrayExpressionType> arrayType = builder->getSession()->getArrayType( + type, + dd->elementCount); + + RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout(); + arrayTypeLayout->type = arrayType; + arrayTypeLayout->rules = typeLayout->rules; + arrayTypeLayout->originalElementTypeLayout = typeLayout; + arrayTypeLayout->elementTypeLayout = typeLayout; + arrayTypeLayout->uniformStride = 0; + + if( auto resInfo = inTypeLayout->FindResourceInfo(kind) ) + { + // TODO: it is kind of gross to be re-running some + // of the type layout logic here. + + UInt elementCount = (UInt) GetIntVal(dd->elementCount); + arrayTypeLayout->addResourceUsage( + kind, + resInfo->count * elementCount); + } + + type = arrayType; + typeLayout = arrayTypeLayout; + } + // Simple case: just create a global variable of the matching type, // and then use the value of the global as a replacement for the // value of the original parameter. // auto globalVariable = addGlobalVariable(builder->getModule(), type); moveValueBefore(globalVariable, builder->getFunc()); + + // We need to construct a fresh layout for the variable, even + // if the original had its own layout, because it might be + // an `inout` parameter, and we only want to deal with the case + // described by our `kind` parameter. + RefPtr<VarLayout> varLayout = new VarLayout(); + varLayout->varDecl = inVarLayout->varDecl; + varLayout->typeLayout = typeLayout; + varLayout->flags = inVarLayout->flags; + varLayout->systemValueSemantic = inVarLayout->systemValueSemantic; + varLayout->systemValueSemanticIndex = inVarLayout->systemValueSemanticIndex; + varLayout->semanticName = inVarLayout->semanticName; + varLayout->semanticIndex = inVarLayout->semanticIndex; + varLayout->stage = inVarLayout->stage; + varLayout->AddResourceInfo(kind)->index = bindingIndex; + builder->addLayoutDecoration(globalVariable, varLayout); + return ScalarizedVal::address(globalVariable); } @@ -2917,20 +2952,21 @@ namespace Slang VarLayout* varLayout, TypeLayout* typeLayout, LayoutResourceKind kind, + UInt bindingIndex, GlobalVaryingDeclarator* declarator) { if( type->As<BasicExpressionType>() ) { - return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, declarator); + return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, bindingIndex, declarator); } else if( type->As<VectorExpressionType>() ) { - return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, declarator); + return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, bindingIndex, declarator); } else if( type->As<MatrixExpressionType>() ) { // TODO: a matrix-type varying should probably be handled like an array of rows - return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, declarator); + return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, bindingIndex, declarator); } else if( auto arrayType = type->As<ArrayExpressionType>() ) { @@ -2953,6 +2989,7 @@ namespace Slang varLayout, elementTypeLayout, kind, + bindingIndex, &arrayDeclarator); } else if( auto declRefType = type->As<DeclRefType>() ) @@ -2978,12 +3015,17 @@ namespace Slang // generate one variable for each. for( auto ff : structTypeLayout->fields ) { + UInt fieldBindingIndex = bindingIndex; + if(auto fieldResInfo = ff->FindResourceInfo(kind)) + fieldBindingIndex += fieldResInfo->index; + auto fieldVal = createGLSLGlobalVaryingsImpl( builder, ff->typeLayout->type, ff, ff->typeLayout, kind, + fieldBindingIndex, declarator); ScalarizedTupleValImpl::Element element; @@ -2999,7 +3041,7 @@ namespace Slang } // Default case is to fall back on the simple behavior - return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, declarator); + return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, bindingIndex, declarator); } ScalarizedVal createGLSLGlobalVaryings( @@ -3008,7 +3050,10 @@ namespace Slang VarLayout* layout, LayoutResourceKind kind) { - return createGLSLGlobalVaryingsImpl(builder, type, layout, layout->typeLayout, kind, nullptr); + UInt bindingIndex = 0; + if(auto rr = layout->FindResourceInfo(kind)) + bindingIndex = rr->index; + return createGLSLGlobalVaryingsImpl(builder, type, layout, layout->typeLayout, kind, bindingIndex, nullptr); } ScalarizedVal extractField( @@ -3062,6 +3107,13 @@ namespace Slang } break; + case ScalarizedVal::Flavor::address: + { + auto val = builder->emitLoad(right.irValue); + builder->emitStore(left.irValue, val); + } + break; + default: SLANG_UNEXPECTED("unimplemented"); break; diff --git a/source/slang/ir.h b/source/slang/ir.h index 407506116..0dc9daa9a 100644 --- a/source/slang/ir.h +++ b/source/slang/ir.h @@ -256,7 +256,7 @@ struct IRUser : IRChildValue // instructions that need "vararg" support to // allocate this field ahead of the `this` // pointer. - uint32_t argCount; + uint32_t argCount = 0; UInt getArgCount() { @@ -333,7 +333,10 @@ bool isTerminatorInst(IRInst* inst); // // In each case, the basic idea is that a block is a "label with // arguments." -struct IRParam : IRValue +// +// Note: an `IRParam` is an `IRUser` *just* so that we can use +// it as the user of other values during SSA generation. +struct IRParam : IRUser { IRParam* nextParam; IRParam* prevParam; diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index a918fa356..4238681f3 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -326,6 +326,23 @@ int CompileRequest::executeActionsInner() // Note that we *do* perform output generation as normal in pass-through mode. if (passThrough == PassThroughMode::None) { + // We currently allow GlSL files on the command line so that we can + // drive our "pass-through" mode, but we really want to issue an error + // message if the user is seriously asking us to compile them. + for (auto& translationUnit : translationUnits) + { + switch(translationUnit->sourceLanguage) + { + default: + break; + + case SourceLanguage::GLSL: + mSink.diagnose(SourceLoc(), Diagnostics::glslIsNotSupported); + return 1; + } + } + + // Parse everything from the input files requested for (auto& translationUnit : translationUnits) { diff --git a/tests/reflection/gh-55.glsl b/tests/reflection/gh-55.glsl index f6db07482..49b6d2bcc 100644 --- a/tests/reflection/gh-55.glsl +++ b/tests/reflection/gh-55.glsl @@ -1,4 +1,8 @@ -//TEST(smoke):REFLECTION:-profile ps_4_0 -target glsl +//TEST_DISABLED(smoke):REFLECTION:-profile ps_4_0 -target glsl + +// Disabled because we don't support GLSL any more. +// (kept around so we can replace with an equivalent +// test that uses HLSL input and tests GLSL layout rules) // Confirm fix for GitHub issue #55 diff --git a/tests/reflection/image-types.glsl b/tests/reflection/image-types.glsl deleted file mode 100644 index 9bba69d3d..000000000 --- a/tests/reflection/image-types.glsl +++ /dev/null @@ -1,12 +0,0 @@ -//TEST(smoke):REFLECTION:-profile ps_4_0 -target glsl - -// Confirm that we expose GLSL `image` types through reflection - -layout(rgba32f) -uniform writeonly imageBuffer iBuffer; - -layout(rgba32f) -uniform writeonly image2D i2D; - -void main() -{} diff --git a/tests/reflection/image-types.glsl.expected b/tests/reflection/image-types.glsl.expected deleted file mode 100644 index dfe477287..000000000 --- a/tests/reflection/image-types.glsl.expected +++ /dev/null @@ -1,33 +0,0 @@ -result code = 0 -standard error = { -} -standard output = { -{ - "parameters": [ - { - "name": "iBuffer", - "binding": {"kind": "descriptorTableSlot", "index": 0}, - "type": { - "kind": "resource", - "baseShape": "textureBuffer", - "access": "readWrite" - } - }, - { - "name": "i2D", - "binding": {"kind": "descriptorTableSlot", "index": 1}, - "type": { - "kind": "resource", - "baseShape": "texture2D", - "access": "readWrite" - } - } - ], - "entryPoints": [ - { - "name": "main", - "stage:": "fragment" - } - ] -} -} diff --git a/tests/reflection/std430-layout.glsl b/tests/reflection/std430-layout.glsl index 73e48a8a0..d05c83785 100644 --- a/tests/reflection/std430-layout.glsl +++ b/tests/reflection/std430-layout.glsl @@ -1,5 +1,9 @@ #version 450 -//TEST(smoke):REFLECTION:-profile ps_4_0 -target glsl +//TEST_DISABLED(smoke):REFLECTION:-profile ps_4_0 -target glsl + +// Note: disabled because we don't support GLSL input any more +// (kept around so we can replace with an equivalent +// test that uses HLSL input and tests GLSL layout rules) // Confirm fix for GitHub issue #55 |
