Skip to content

Commit 598bd84

Browse files
Karpov-Ruslanarcady-lunarg
authored andcommitted
Implement GL_EXT_function_control_attributes
1 parent 85e2c34 commit 598bd84

20 files changed

Lines changed: 5237 additions & 4960 deletions

SPIRV/GlslangToSpv.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
233233
spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
234234
spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
235235
spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, std::vector<unsigned int>& operands) const;
236+
spv::FunctionControlMask TranslateFunctionControl(unsigned int) const;
236237
spv::StorageClass TranslateStorageClass(const glslang::TType&);
237238
void TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>&, std::vector<unsigned>&) const;
238239
void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType);
@@ -1428,6 +1429,18 @@ spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const g
14281429
return spv::SelectionControlMask::MaskNone;
14291430
}
14301431

1432+
spv::FunctionControlMask TGlslangToSpvTraverser::TranslateFunctionControl(unsigned int functionControl) const
1433+
{
1434+
spv::FunctionControlMask control = spv::FunctionControlMask::MaskNone;
1435+
1436+
if (functionControl & glslang::EfcInline)
1437+
control = control | spv::FunctionControlMask::Inline;
1438+
if (functionControl & glslang::EfcDontInline)
1439+
control = control | spv::FunctionControlMask::DontInline;
1440+
1441+
return control;
1442+
}
1443+
14311444
// return a non-0 dependency if the dependency argument must be set
14321445
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode,
14331446
std::vector<unsigned int>& operands) const
@@ -7493,6 +7506,7 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF
74937506
builder.setDebugSourceLocation(glslFunction->getLoc().line, glslFunction->getLoc().getFilename());
74947507

74957508
if (isShaderEntryPoint(glslFunction)) {
7509+
shaderEntry->setFunctionControl(TranslateFunctionControl(glslFunction->getFunctionControl()));
74967510
// For HLSL, the entry function is actually a compiler generated function to resolve the difference of
74977511
// entry function signature between HLSL and SPIR-V. So we don't emit debug information for that.
74987512
if (glslangIntermediate->getSource() != glslang::EShSourceHlsl) {
@@ -7551,6 +7565,7 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF
75517565
TranslatePrecisionDecoration(glslFunction->getType()), convertGlslangToSpvType(glslFunction->getType()),
75527566
glslFunction->getName().c_str(), convertGlslangLinkageToSpv(glslFunction->getLinkType()), paramTypes,
75537567
paramDecorations, &functionBlock);
7568+
function->setFunctionControl(TranslateFunctionControl(glslFunction->getFunctionControl()));
75547569
builder.setupFunctionDebugInfo(function, glslFunction->getName().c_str(), paramTypes, paramNames);
75557570
if (implicitThis)
75567571
function->setImplicitThis();

SPIRV/spvIR.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,10 @@ class Function {
481481
Id getReturnType() const { return functionInstruction.getTypeId(); }
482482
Id getFuncId() const { return functionInstruction.getResultId(); }
483483
Id getFuncTypeId() const { return functionInstruction.getIdOperand(1); }
484+
void setFunctionControl(FunctionControlMask functionControl)
485+
{
486+
functionInstruction.setImmediateOperand(0, static_cast<unsigned>(functionControl));
487+
}
484488
void setReturnPrecision(Decoration precision)
485489
{
486490
if (precision == Decoration::RelaxedPrecision)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
spv.functionControlAttributes.error.frag
2+
ERROR: 0:7: 'sameDeclaration' : function attributes are incompatible
3+
ERROR: 0:14: 'prototypeConflict' : function attributes are incompatible
4+
ERROR: 2 compilation errors. No code generated.
5+
6+
7+
SPIR-V is not generated for failed compile or link
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
spv.functionControlAttributes.frag
2+
// Module Version 10000
3+
// Generated by (magic number): 8000b
4+
// Id's are bound by 61
5+
6+
Capability Shader
7+
1: ExtInstImport "GLSL.std.450"
8+
MemoryModel Logical GLSL450
9+
EntryPoint Fragment 4 "main" 57
10+
ExecutionMode 4 OriginUpperLeft
11+
Source GLSL 450
12+
SourceExtension "GL_EXT_function_control_attributes"
13+
Name 4 "main"
14+
Name 10 "inlineFn(i1;"
15+
Name 9 "i"
16+
Name 13 "noinlineFn(i1;"
17+
Name 12 "i"
18+
Name 16 "backFn(i1;"
19+
Name 15 "i"
20+
Name 19 "prototypeFn(i1;"
21+
Name 18 "i"
22+
Name 41 "value"
23+
Name 42 "param"
24+
Name 44 "param"
25+
Name 49 "param"
26+
Name 57 "color"
27+
Decorate 57(color) Location 0
28+
2: TypeVoid
29+
3: TypeFunction 2
30+
6: TypeInt 32 1
31+
7: TypePointer Function 6(int)
32+
8: TypeFunction 6(int) 7(ptr)
33+
22: 6(int) Constant 1
34+
27: 6(int) Constant 2
35+
32: 6(int) Constant 3
36+
37: 6(int) Constant 4
37+
54: TypeFloat 32
38+
55: TypeVector 54(float) 4
39+
56: TypePointer Output 55(fvec4)
40+
57(color): 56(ptr) Variable Output
41+
4(main): 2 Function None 3
42+
5: Label
43+
41(value): 7(ptr) Variable Function
44+
42(param): 7(ptr) Variable Function
45+
44(param): 7(ptr) Variable Function
46+
49(param): 7(ptr) Variable Function
47+
Store 42(param) 22
48+
43: 6(int) FunctionCall 10(inlineFn(i1;) 42(param)
49+
Store 41(value) 43
50+
45: 6(int) Load 41(value)
51+
Store 44(param) 45
52+
46: 6(int) FunctionCall 13(noinlineFn(i1;) 44(param)
53+
47: 6(int) Load 41(value)
54+
48: 6(int) IAdd 47 46
55+
Store 41(value) 48
56+
50: 6(int) Load 41(value)
57+
Store 49(param) 50
58+
51: 6(int) FunctionCall 19(prototypeFn(i1;) 49(param)
59+
52: 6(int) Load 41(value)
60+
53: 6(int) IAdd 52 51
61+
Store 41(value) 53
62+
58: 6(int) Load 41(value)
63+
59: 54(float) ConvertSToF 58
64+
60: 55(fvec4) CompositeConstruct 59 59 59 59
65+
Store 57(color) 60
66+
Return
67+
FunctionEnd
68+
10(inlineFn(i1;): 6(int) Function Inline 8
69+
9(i): 7(ptr) FunctionParameter
70+
11: Label
71+
21: 6(int) Load 9(i)
72+
23: 6(int) IAdd 21 22
73+
ReturnValue 23
74+
FunctionEnd
75+
13(noinlineFn(i1;): 6(int) Function DontInline 8
76+
12(i): 7(ptr) FunctionParameter
77+
14: Label
78+
26: 6(int) Load 12(i)
79+
28: 6(int) IAdd 26 27
80+
ReturnValue 28
81+
FunctionEnd
82+
16(backFn(i1;): 6(int) Function Inline 8
83+
15(i): 7(ptr) FunctionParameter
84+
17: Label
85+
31: 6(int) Load 15(i)
86+
33: 6(int) IAdd 31 32
87+
ReturnValue 33
88+
FunctionEnd
89+
19(prototypeFn(i1;): 6(int) Function Inline 8
90+
18(i): 7(ptr) FunctionParameter
91+
20: Label
92+
36: 6(int) Load 18(i)
93+
38: 6(int) IAdd 36 37
94+
ReturnValue 38
95+
FunctionEnd
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#version 450
2+
3+
#extension GL_EXT_function_control_attributes : enable
4+
5+
layout(location = 0) out vec4 color;
6+
7+
[[inline, noinline]] int sameDeclaration(int i)
8+
{
9+
return i;
10+
}
11+
12+
[[inline]] int prototypeConflict(int i);
13+
14+
[[noinline]] int prototypeConflict(int i)
15+
{
16+
return i;
17+
}
18+
19+
void main()
20+
{
21+
color = vec4(0.0);
22+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#version 450
2+
3+
#extension GL_EXT_function_control_attributes : enable
4+
5+
layout(location = 0) out vec4 color;
6+
7+
[[inline]] int inlineFn(int i)
8+
{
9+
return i + 1;
10+
}
11+
12+
[[noinline]] int noinlineFn(int i)
13+
{
14+
return i + 2;
15+
}
16+
17+
int backFn(int i) [[inline]]
18+
{
19+
return i + 3;
20+
}
21+
22+
[[inline]] int prototypeFn (int i);
23+
24+
int prototypeFn(int i)
25+
{
26+
return i + 4;
27+
}
28+
29+
void main()
30+
{
31+
int value = inlineFn(1);
32+
value += noinlineFn(value);
33+
value += prototypeFn(value);
34+
color = vec4(float(value));
35+
}

glslang/Include/intermediate.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,12 @@ enum TLinkType {
11041104
ELinkExport,
11051105
};
11061106

1107+
enum TFunctionControl {
1108+
EfcNone = 0,
1109+
EfcInline = 0x1,
1110+
EfcDontInline = 0x2,
1111+
};
1112+
11071113
class TIntermTraverser;
11081114
class TIntermVariableDecl;
11091115
class TIntermOperator;
@@ -1730,7 +1736,7 @@ typedef TVector<TStorageQualifier> TQualifierList;
17301736
//
17311737
class TIntermAggregate : public TIntermOperator {
17321738
public:
1733-
TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(nullptr) {
1739+
TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(nullptr) {
17341740
endLoc.init();
17351741
}
17361742
TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(nullptr) {
@@ -1764,6 +1770,8 @@ class TIntermAggregate : public TIntermOperator {
17641770

17651771
void setLinkType(TLinkType l) { linkType = l; }
17661772
TLinkType getLinkType() const { return linkType; }
1773+
void setFunctionControl(unsigned int fc) { functionControl = fc; }
1774+
unsigned int getFunctionControl() const { return functionControl; }
17671775
protected:
17681776
TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
17691777
TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
@@ -1776,6 +1784,7 @@ class TIntermAggregate : public TIntermOperator {
17761784
TPragmaTable* pragmaTable;
17771785
TSpirvInstruction spirvInst;
17781786
TLinkType linkType = ELinkNone;
1787+
unsigned int functionControl = EfcNone;
17791788

17801789
// Marking the end source location of the aggregate.
17811790
// This is currently only set for a compound statement or a function body, pointing to '}'.

glslang/MachineIndependent/ParseHelper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,13 @@ TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunct
12591259
}
12601260
if (!parameterTypesDiffer && prevDec->getType() != function.getType())
12611261
error(loc, "overloaded functions must have the same return type", function.getName().c_str(), "");
1262+
1263+
function.addFunctionControl(prevDec->getFunctionControl());
1264+
unsigned functionControl = function.getFunctionControl();
1265+
if (function.hasIncompatibleFunctionControl())
1266+
error(loc, "function attributes are incompatible", function.getName().c_str(), "");
1267+
if (!builtIn)
1268+
symbol->getAsFunction()->setFunctionControl(functionControl);
12621269
}
12631270

12641271
arrayObjectCheck(loc, function.getType(), "array in function return type");

glslang/MachineIndependent/ParseHelper.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ class TParseContext : public TParseContextBase {
490490
// Determine loop control from attributes
491491
void handleLoopAttributes(const TAttributes& attributes, TIntermNode*);
492492
// Function attributes
493-
void handleFunctionAttributes(const TSourceLoc&, const TAttributes&);
493+
void handleFunctionAttributes(const TSourceLoc&, TFunction&, const TAttributes&);
494494

495495
// GL_EXT_spirv_intrinsics
496496
TSpirvRequirement* makeSpirvRequirement(const TSourceLoc& loc, const TString& name,

glslang/MachineIndependent/Scan.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "../Include/Types.h"
4949
#include "SymbolTable.h"
5050
#include "ParseHelper.h"
51+
#include "Versions.h"
5152
#include "attribute.h"
5253
#include "glslang_tab.cpp.h"
5354
#include "ScanContext.h"
@@ -807,6 +808,8 @@ const std::unordered_map<const char*, int, str_hash, str_eq> KeywordMap {
807808
{"vector",VECTOR},
808809
{"resourceheap",RESOURCEHEAP},
809810
{"samplerheap",SAMPLERHEAP},
811+
{"inline", INLINE},
812+
{"noinline", NOINLINE},
810813
};
811814
const std::unordered_set<const char*, str_hash, str_eq> ReservedSet {
812815
"common",
@@ -820,8 +823,6 @@ const std::unordered_set<const char*, str_hash, str_eq> ReservedSet {
820823
"template",
821824
"this",
822825
"goto",
823-
"inline",
824-
"noinline",
825826
"public",
826827
"static",
827828
"extern",
@@ -2077,6 +2078,12 @@ int TScanContext::tokenizeIdentifier()
20772078
return keyword;
20782079
return identifierOrType();
20792080

2081+
case INLINE:
2082+
case NOINLINE:
2083+
if (!parseContext.extensionTurnedOn(E_GL_EXT_function_control_attributes))
2084+
return reservedWord();
2085+
return keyword;
2086+
20802087
default:
20812088
parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc);
20822089
return 0;

0 commit comments

Comments
 (0)