Commit 15fa7ef5 by John Kessenich Committed by GregF

HLSL: Remove workarounds for assigning to opaques.

This assumes it will be combined with optimizing transforms that eliminate assignments to opaques.
parent dabd1bf2
hlsl.aliasOpaque.frag hlsl.aliasOpaque.frag
WARNING: AST will form illegal SPIR-V; need to transform to legalize
Shader version: 500 Shader version: 500
gl_FragCoord origin is upper left gl_FragCoord origin is upper left
0:? Sequence 0:? Sequence
...@@ -21,18 +22,24 @@ gl_FragCoord origin is upper left ...@@ -21,18 +22,24 @@ gl_FragCoord origin is upper left
0:17 Function Definition: @main( ( temp 4-component vector of float) 0:17 Function Definition: @main( ( temp 4-component vector of float)
0:17 Function Parameters: 0:17 Function Parameters:
0:? Sequence 0:? Sequence
0:19 'gss2' ( uniform sampler) 0:19 move second child to first child ( temp sampler)
0:20 'gss' ( uniform sampler) 0:? 'os.ss' ( temp sampler)
0:21 'gtex' ( uniform texture2D) 0:19 'gss2' ( uniform sampler)
0:20 move second child to first child ( temp sampler)
0:? 'os.ss' ( temp sampler)
0:20 'gss' ( uniform sampler)
0:21 move second child to first child ( temp texture2D)
0:? 'os.tex' ( temp texture2D)
0:21 'gtex' ( uniform texture2D)
0:22 move second child to first child ( temp float) 0:22 move second child to first child ( temp float)
0:? 'os.a' ( temp float) 0:? 'os.a' ( temp float)
0:22 Constant: 0:22 Constant:
0:22 3.000000 0:22 3.000000
0:28 Branch: Return with expression 0:28 Branch: Return with expression
0:28 Function Call: osCall(struct-OS-p1-f1-t211; ( temp 4-component vector of float) 0:28 Function Call: osCall(struct-OS-p1-f1-t211; ( temp 4-component vector of float)
0:? 'gss' ( uniform sampler) 0:? 'os.ss' ( temp sampler)
0:? 'os.a' ( temp float) 0:? 'os.a' ( temp float)
0:? 'gtex' ( uniform texture2D) 0:? 'os.tex' ( temp texture2D)
0:17 Function Definition: main( ( temp void) 0:17 Function Definition: main( ( temp void)
0:17 Function Parameters: 0:17 Function Parameters:
0:? Sequence 0:? Sequence
...@@ -71,18 +78,24 @@ gl_FragCoord origin is upper left ...@@ -71,18 +78,24 @@ gl_FragCoord origin is upper left
0:17 Function Definition: @main( ( temp 4-component vector of float) 0:17 Function Definition: @main( ( temp 4-component vector of float)
0:17 Function Parameters: 0:17 Function Parameters:
0:? Sequence 0:? Sequence
0:19 'gss2' ( uniform sampler) 0:19 move second child to first child ( temp sampler)
0:20 'gss' ( uniform sampler) 0:? 'os.ss' ( temp sampler)
0:21 'gtex' ( uniform texture2D) 0:19 'gss2' ( uniform sampler)
0:20 move second child to first child ( temp sampler)
0:? 'os.ss' ( temp sampler)
0:20 'gss' ( uniform sampler)
0:21 move second child to first child ( temp texture2D)
0:? 'os.tex' ( temp texture2D)
0:21 'gtex' ( uniform texture2D)
0:22 move second child to first child ( temp float) 0:22 move second child to first child ( temp float)
0:? 'os.a' ( temp float) 0:? 'os.a' ( temp float)
0:22 Constant: 0:22 Constant:
0:22 3.000000 0:22 3.000000
0:28 Branch: Return with expression 0:28 Branch: Return with expression
0:28 Function Call: osCall(struct-OS-p1-f1-t211; ( temp 4-component vector of float) 0:28 Function Call: osCall(struct-OS-p1-f1-t211; ( temp 4-component vector of float)
0:? 'gss' ( uniform sampler) 0:? 'os.ss' ( temp sampler)
0:? 'os.a' ( temp float) 0:? 'os.a' ( temp float)
0:? 'gtex' ( uniform texture2D) 0:? 'os.tex' ( temp texture2D)
0:17 Function Definition: main( ( temp void) 0:17 Function Definition: main( ( temp void)
0:17 Function Parameters: 0:17 Function Parameters:
0:? Sequence 0:? Sequence
...@@ -97,12 +110,12 @@ gl_FragCoord origin is upper left ...@@ -97,12 +110,12 @@ gl_FragCoord origin is upper left
// Module Version 10000 // Module Version 10000
// Generated by (magic number): 80001 // Generated by (magic number): 80001
// Id's are bound by 48 // Id's are bound by 53
Capability Shader Capability Shader
1: ExtInstImport "GLSL.std.450" 1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450 MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main" 46 EntryPoint Fragment 4 "main" 51
ExecutionMode 4 OriginUpperLeft ExecutionMode 4 OriginUpperLeft
Source HLSL 500 Source HLSL 500
Name 4 "main" Name 4 "main"
...@@ -111,16 +124,18 @@ gl_FragCoord origin is upper left ...@@ -111,16 +124,18 @@ gl_FragCoord origin is upper left
Name 15 "s.a" Name 15 "s.a"
Name 16 "s.tex" Name 16 "s.tex"
Name 20 "@main(" Name 20 "@main("
Name 35 "gss2" Name 35 "os.ss"
Name 36 "gss" Name 36 "gss2"
Name 37 "gtex" Name 38 "gss"
Name 38 "os.a" Name 40 "os.tex"
Name 40 "param" Name 41 "gtex"
Name 46 "@entryPointOutput" Name 43 "os.a"
Decorate 35(gss2) DescriptorSet 0 Name 45 "param"
Decorate 36(gss) DescriptorSet 0 Name 51 "@entryPointOutput"
Decorate 37(gtex) DescriptorSet 0 Decorate 36(gss2) DescriptorSet 0
Decorate 46(@entryPointOutput) Location 0 Decorate 38(gss) DescriptorSet 0
Decorate 41(gtex) DescriptorSet 0
Decorate 51(@entryPointOutput) Location 0
2: TypeVoid 2: TypeVoid
3: TypeFunction 2 3: TypeFunction 2
6: TypeSampler 6: TypeSampler
...@@ -137,16 +152,18 @@ gl_FragCoord origin is upper left ...@@ -137,16 +152,18 @@ gl_FragCoord origin is upper left
28: 8(float) Constant 1045220557 28: 8(float) Constant 1045220557
29: 8(float) Constant 1050253722 29: 8(float) Constant 1050253722
30: 27(fvec2) ConstantComposite 28 29 30: 27(fvec2) ConstantComposite 28 29
35(gss2): 7(ptr) Variable UniformConstant 35(os.ss): 7(ptr) Variable UniformConstant
36(gss): 7(ptr) Variable UniformConstant 36(gss2): 7(ptr) Variable UniformConstant
37(gtex): 11(ptr) Variable UniformConstant 38(gss): 7(ptr) Variable UniformConstant
39: 8(float) Constant 1077936128 40(os.tex): 11(ptr) Variable UniformConstant
45: TypePointer Output 12(fvec4) 41(gtex): 11(ptr) Variable UniformConstant
46(@entryPointOutput): 45(ptr) Variable Output 44: 8(float) Constant 1077936128
50: TypePointer Output 12(fvec4)
51(@entryPointOutput): 50(ptr) Variable Output
4(main): 2 Function None 3 4(main): 2 Function None 3
5: Label 5: Label
47: 12(fvec4) FunctionCall 20(@main() 52: 12(fvec4) FunctionCall 20(@main()
Store 46(@entryPointOutput) 47 Store 51(@entryPointOutput) 52
Return Return
FunctionEnd FunctionEnd
17(osCall(struct-OS-p1-f1-t211;): 12(fvec4) Function None 13 17(osCall(struct-OS-p1-f1-t211;): 12(fvec4) Function None 13
...@@ -164,11 +181,17 @@ gl_FragCoord origin is upper left ...@@ -164,11 +181,17 @@ gl_FragCoord origin is upper left
FunctionEnd FunctionEnd
20(@main(): 12(fvec4) Function None 19 20(@main(): 12(fvec4) Function None 19
21: Label 21: Label
38(os.a): 9(ptr) Variable Function 43(os.a): 9(ptr) Variable Function
40(param): 9(ptr) Variable Function 45(param): 9(ptr) Variable Function
Store 38(os.a) 39 37: 6 Load 36(gss2)
41: 8(float) Load 38(os.a) Store 35(os.ss) 37
Store 40(param) 41 39: 6 Load 38(gss)
42: 12(fvec4) FunctionCall 17(osCall(struct-OS-p1-f1-t211;) 36(gss) 40(param) 37(gtex) Store 35(os.ss) 39
ReturnValue 42 42: 10 Load 41(gtex)
Store 40(os.tex) 42
Store 43(os.a) 44
46: 8(float) Load 43(os.a)
Store 45(param) 46
47: 12(fvec4) FunctionCall 17(osCall(struct-OS-p1-f1-t211;) 35(os.ss) 45(param) 40(os.tex)
ReturnValue 47
FunctionEnd FunctionEnd
hlsl.array.flatten.frag hlsl.array.flatten.frag
WARNING: AST will form illegal SPIR-V; need to transform to legalize
Shader version: 500 Shader version: 500
gl_FragCoord origin is upper left gl_FragCoord origin is upper left
0:? Sequence 0:? Sequence
......
...@@ -234,7 +234,8 @@ public: ...@@ -234,7 +234,8 @@ public:
hlslOffsets(false), hlslOffsets(false),
useStorageBuffer(false), useStorageBuffer(false),
hlslIoMapping(false), hlslIoMapping(false),
textureSamplerTransformMode(EShTexSampTransKeep) textureSamplerTransformMode(EShTexSampTransKeep),
needToLegalize(false)
{ {
localSize[0] = 1; localSize[0] = 1;
localSize[1] = 1; localSize[1] = 1;
...@@ -610,6 +611,9 @@ public: ...@@ -610,6 +611,9 @@ public:
void addProcessArgument(const std::string& arg) { processes.addArgument(arg); } void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); } const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
void setNeedsLegalization() { needToLegalize = true; }
bool needsLegalization() const { return needToLegalize; }
const char* const implicitThisName; const char* const implicitThisName;
protected: protected:
...@@ -708,6 +712,8 @@ protected: ...@@ -708,6 +712,8 @@ protected:
// for OpModuleProcessed, or equivalent // for OpModuleProcessed, or equivalent
TProcesses processes; TProcesses processes;
bool needToLegalize;
private: private:
void operator=(TIntermediate&); // prevent assignments void operator=(TIntermediate&); // prevent assignments
}; };
......
...@@ -166,11 +166,6 @@ bool HlslParseContext::shouldConvertLValue(const TIntermNode* node) const ...@@ -166,11 +166,6 @@ bool HlslParseContext::shouldConvertLValue(const TIntermNode* node) const
if (lhsAsAggregate != nullptr && lhsAsAggregate->getOp() == EOpImageLoad) if (lhsAsAggregate != nullptr && lhsAsAggregate->getOp() == EOpImageLoad)
return true; return true;
// If it's a syntactic write to a sampler, we will use that to establish
// a compile-time alias.
if (node->getAsTyped()->getBasicType() == EbtSampler)
return true;
return false; return false;
} }
...@@ -239,6 +234,13 @@ bool HlslParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, T ...@@ -239,6 +234,13 @@ bool HlslParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, T
} }
} }
// We tolerate samplers as l-values, even though they are nominally
// illegal, because we expect a later optimization to eliminate them.
if (node->getType().getBasicType() == EbtSampler) {
intermediate.setNeedsLegalization();
return false;
}
// Let the base class check errors // Let the base class check errors
return TParseContextBase::lValueErrorCheck(loc, op, node); return TParseContextBase::lValueErrorCheck(loc, op, node);
} }
...@@ -274,10 +276,6 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char* ...@@ -274,10 +276,6 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char*
// *** If we get here, we're going to apply some conversion to an l-value. // *** If we get here, we're going to apply some conversion to an l-value.
// Spin off sampler aliasing
if (node->getAsTyped()->getBasicType() == EbtSampler)
return handleSamplerLvalue(loc, op, node);
// Helper to create a load. // Helper to create a load.
const auto makeLoad = [&](TIntermSymbol* rhsTmp, TIntermTyped* object, TIntermTyped* coord, const TType& derefType) { const auto makeLoad = [&](TIntermSymbol* rhsTmp, TIntermTyped* object, TIntermTyped* coord, const TType& derefType) {
TIntermAggregate* loadOp = new TIntermAggregate(EOpImageLoad); TIntermAggregate* loadOp = new TIntermAggregate(EOpImageLoad);
...@@ -524,58 +522,6 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char* ...@@ -524,58 +522,6 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char*
return node; return node;
} }
// Deal with sampler aliasing: turning assignments into aliases
// Return a placeholder node for higher-level code that think assignments must
// generate code.
TIntermTyped* HlslParseContext::handleSamplerLvalue(const TSourceLoc& loc, const char* op, TIntermTyped*& node)
{
// Can only alias an assignment: "s1 = s2"
TIntermBinary* binary = node->getAsBinaryNode();
if (binary == nullptr || node->getAsOperator()->getOp() != EOpAssign ||
binary->getLeft()->getAsSymbolNode() == nullptr ||
binary->getRight()->getAsSymbolNode() == nullptr) {
error(loc, "can't modify sampler", op, "");
return node;
}
if (controlFlowNestingLevel > 0)
warn(loc, "sampler or image aliased under control flow; consumption must be in same path", op, "");
TIntermTyped* set = setOpaqueLvalue(binary->getLeft(), binary->getRight());
if (set == nullptr)
warn(loc, "could not create alias for sampler", op, "");
else
node = set;
return node;
}
// Do an opaque assignment that needs to turn into an alias.
// Return nullptr if it can't be done, otherwise return a placeholder
// node for higher-level code that think assignments must generate code.
TIntermTyped* HlslParseContext::setOpaqueLvalue(TIntermTyped* leftTyped, TIntermTyped* rightTyped)
{
// Best is if we are aliasing a flattened struct member "S.s1 = s2",
// in which case we want to update the flattening information with the alias,
// making everything else work seamlessly.
TIntermSymbol* left = leftTyped->getAsSymbolNode();
TIntermSymbol* right = rightTyped->getAsSymbolNode();
for (auto fit = flattenMap.begin(); fit != flattenMap.end(); ++fit) {
for (auto mit = fit->second.members.begin(); mit != fit->second.members.end(); ++mit) {
if ((*mit)->getUniqueId() == left->getId()) {
// found it: update with alias to the existing variable, and don't emit any code
(*mit) = new TVariable(&right->getName(), right->getType());
(*mit)->setUniqueId(right->getId());
// replace node (rest of compiler expects either an error or code to generate)
// with pointless access
return right;
}
}
}
return nullptr;
}
void HlslParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>& tokens) void HlslParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>& tokens)
{ {
if (pragmaCallback) if (pragmaCallback)
...@@ -2513,41 +2459,6 @@ TIntermAggregate* HlslParseContext::assignClipCullDistance(const TSourceLoc& loc ...@@ -2513,41 +2459,6 @@ TIntermAggregate* HlslParseContext::assignClipCullDistance(const TSourceLoc& loc
return assignList; return assignList;
} }
// For a declaration with an initializer, where the initialized symbol is flattened,
// and possibly contains opaque values, such that the initializer should never exist
// as emitted code, because even creating the initializer would write opaques.
//
// If possible, decompose this into individual member-wise assignments, which themselves
// are expected to then not exist for opaque types, because they will turn into aliases.
//
// Return a node that contains the non-aliased assignments that must continue to exist.
TIntermTyped* HlslParseContext::executeFlattenedInitializer(const TSourceLoc& loc, TIntermSymbol* symbol,
TIntermAggregate& initializer)
{
// We need individual RHS initializers per member to do this
const TTypeList* typeList = symbol->getType().getStruct();
if (typeList == nullptr || initializer.getSequence().size() != typeList->size()) {
warn(loc, "cannot do member-wise aliasing for opaque members with this initializer", "=", "");
return handleAssign(loc, EOpAssign, symbol, &initializer);
}
TIntermAggregate* initList = nullptr;
// synthesize an access to each member, and then an assignment to it
for (int member = 0; member < (int)typeList->size(); ++member) {
TIntermTyped* memberInitializer = initializer.getSequence()[member]->getAsTyped();
TIntermTyped* flattenedMember = flattenAccess(symbol, member);
if (flattenedMember->getType().containsOpaque())
setOpaqueLvalue(flattenedMember, memberInitializer);
else
initList = intermediate.growAggregate(initList, handleAssign(loc, EOpAssign, flattenedMember,
memberInitializer));
}
if (initList)
initList->setOperator(EOpSequence);
return initList;
}
// Some simple source assignments need to be flattened to a sequence // Some simple source assignments need to be flattened to a sequence
// of AST assignments. Catch these and flatten, otherwise, pass through // of AST assignments. Catch these and flatten, otherwise, pass through
// to intermediate.addAssign(). // to intermediate.addAssign().
...@@ -2560,6 +2471,10 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op ...@@ -2560,6 +2471,10 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
if (left == nullptr || right == nullptr) if (left == nullptr || right == nullptr)
return nullptr; return nullptr;
// writing to opaques will require fixing transforms
if (left->getType().containsOpaque())
intermediate.setNeedsLegalization();
if (left->getAsOperator() && left->getAsOperator()->getOp() == EOpMatrixSwizzle) if (left->getAsOperator() && left->getAsOperator()->getOp() == EOpMatrixSwizzle)
return handleAssignToMatrixSwizzle(loc, op, left, right); return handleAssignToMatrixSwizzle(loc, op, left, right);
...@@ -2720,7 +2635,8 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op ...@@ -2720,7 +2635,8 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
const int elementsL = left->getType().isArray() ? left->getType().getOuterArraySize() : 1; const int elementsL = left->getType().isArray() ? left->getType().getOuterArraySize() : 1;
const int elementsR = right->getType().isArray() ? right->getType().getOuterArraySize() : 1; const int elementsR = right->getType().isArray() ? right->getType().getOuterArraySize() : 1;
// The arrays may not be the same size, e.g, if the size has been forced for EbvTessLevelInner or Outer. // The arrays might not be the same size,
// e.g., if the size has been forced for EbvTessLevelInner/Outer.
const int elementsToCopy = std::min(elementsL, elementsR); const int elementsToCopy = std::min(elementsL, elementsR);
// array case // array case
...@@ -7616,20 +7532,10 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm ...@@ -7616,20 +7532,10 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm
// normal assigning of a value to a variable... // normal assigning of a value to a variable...
specializationCheck(loc, initializer->getType(), "initializer"); specializationCheck(loc, initializer->getType(), "initializer");
TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc); TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc);
TIntermNode* initNode = handleAssign(loc, EOpAssign, intermSymbol, initializer);
// If we are flattening, it could be due to setting opaques, which must be handled if (initNode == nullptr)
// as aliases, and the 'initializer' node cannot actually be emitted, because it assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
// itself stores the result of the constructor, and we can't store to opaques. return initNode;
// handleAssign() will emit the initializer.
TIntermNode* initNode = nullptr;
if (flattened && intermSymbol->getType().containsOpaque())
return executeFlattenedInitializer(loc, intermSymbol, *initializer->getAsAggregate());
else {
initNode = handleAssign(loc, EOpAssign, intermSymbol, initializer);
if (initNode == nullptr)
assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
return initNode;
}
} }
return nullptr; return nullptr;
...@@ -9517,6 +9423,11 @@ void HlslParseContext::finish() ...@@ -9517,6 +9423,11 @@ void HlslParseContext::finish()
error(mipsOperatorMipArg.back().loc, "unterminated mips operator:", "", ""); error(mipsOperatorMipArg.back().loc, "unterminated mips operator:", "", "");
} }
// Communicate out (esp. for command line) that we formed AST that will make
// illegal AST SPIR-V and it needs transforms to legalize it.
if (intermediate.needsLegalization())
infoSink.info << "WARNING: AST will form illegal SPIR-V; need to transform to legalize";
removeUnusedStructBufferCounters(); removeUnusedStructBufferCounters();
addPatchConstantInvocation(); addPatchConstantInvocation();
fixTextureShadowModes(); fixTextureShadowModes();
......
...@@ -88,7 +88,6 @@ public: ...@@ -88,7 +88,6 @@ public:
void remapNonEntryPointIO(TFunction& function); void remapNonEntryPointIO(TFunction& function);
TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*); TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*);
void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg); void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg);
TIntermTyped* executeFlattenedInitializer(const TSourceLoc&, TIntermSymbol*, TIntermAggregate&);
TIntermTyped* handleAssign(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right); TIntermTyped* handleAssign(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right);
TIntermTyped* handleAssignToMatrixSwizzle(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right); TIntermTyped* handleAssignToMatrixSwizzle(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right);
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermTyped*); TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermTyped*);
...@@ -191,8 +190,6 @@ public: ...@@ -191,8 +190,6 @@ public:
// Apply L-value conversions. E.g, turning a write to a RWTexture into an ImageStore. // Apply L-value conversions. E.g, turning a write to a RWTexture into an ImageStore.
TIntermTyped* handleLvalue(const TSourceLoc&, const char* op, TIntermTyped*& node); TIntermTyped* handleLvalue(const TSourceLoc&, const char* op, TIntermTyped*& node);
TIntermTyped* handleSamplerLvalue(const TSourceLoc&, const char* op, TIntermTyped*& node);
TIntermTyped* setOpaqueLvalue(TIntermTyped* left, TIntermTyped* right);
bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override; bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override;
TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&); TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment