Skip to content

Commit ae373d4

Browse files
committed
Use a SmallVector of pairs instead of DenseMap to collect Function
pointers and corresponding shader flag masks. This follows the recommendations in LLVM Programmer's Manual as the current usage pattern has distinct phases of insertion of computed shader flags followed by querying. Upon insertion, the Smallvector is sorted and binary search is used for querying. Necessary comparison function of pairs is also implemented. Added a simple DiagnosticInfoShaderFlags for emitting diagnostics. Added tests to verify shader flags masks collected per-function.
1 parent 397f70b commit ae373d4

File tree

8 files changed

+218
-49
lines changed

8 files changed

+218
-49
lines changed

llvm/lib/Target/DirectX/DXContainerGlobals.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ GlobalVariable *DXContainerGlobals::getFeatureFlags(Module &M) {
8484
// of the shader flags of all functions in the module. Need to verify
8585
// and modify the computation of feature flags to be used.
8686
uint64_t ConsolidatedFeatureFlags = 0;
87-
for (const auto &FuncFlags : MSFI.FuncShaderFlagsMap) {
87+
for (const auto &FuncFlags : MSFI.FuncShaderFlagsVec) {
8888
ConsolidatedFeatureFlags |= FuncFlags.second.getFeatureFlags();
8989
}
9090

llvm/lib/Target/DirectX/DXILShaderFlags.cpp

Lines changed: 114 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,43 +13,114 @@
1313

1414
#include "DXILShaderFlags.h"
1515
#include "DirectX.h"
16+
#include "llvm/ADT/STLExtras.h"
17+
#include "llvm/IR/DiagnosticInfo.h"
18+
#include "llvm/IR/DiagnosticPrinter.h"
1619
#include "llvm/IR/Instruction.h"
1720
#include "llvm/IR/Module.h"
1821
#include "llvm/Support/FormatVariadic.h"
22+
#include "llvm/Support/raw_ostream.h"
1923

2024
using namespace llvm;
2125
using namespace llvm::dxil;
2226

23-
static void updateFlags(DXILModuleShaderFlagsInfo &MSFI, const Instruction &I) {
24-
ComputedShaderFlags &FSF = MSFI.FuncShaderFlagsMap[I.getFunction()];
27+
namespace {
28+
/// A simple Wrapper DiagnosticInfo that generates Module-level diagnostic
29+
/// for ShaderFlagsAnalysis pass
30+
class DiagnosticInfoShaderFlags : public DiagnosticInfo {
31+
private:
32+
const Twine &Msg;
33+
const Module &Mod;
34+
35+
public:
36+
/// \p M is the module for which the diagnostic is being emitted. \p Msg is
37+
/// the message to show. Note that this class does not copy this message, so
38+
/// this reference must be valid for the whole life time of the diagnostic.
39+
DiagnosticInfoShaderFlags(const Module &M, const Twine &Msg,
40+
DiagnosticSeverity Severity = DS_Error)
41+
: DiagnosticInfo(DK_Unsupported, Severity), Msg(Msg), Mod(M) {}
42+
43+
void print(DiagnosticPrinter &DP) const override {
44+
DP << Mod.getName() << ": " << Msg << '\n';
45+
}
46+
};
47+
} // namespace
48+
49+
static void updateFlags(ComputedShaderFlags &CSF, const Instruction &I) {
2550
Type *Ty = I.getType();
26-
if (Ty->isDoubleTy()) {
27-
FSF.Doubles = true;
51+
bool DoubleTyInUse = Ty->isDoubleTy();
52+
for (Value *Op : I.operands()) {
53+
DoubleTyInUse |= Op->getType()->isDoubleTy();
54+
}
55+
56+
if (DoubleTyInUse) {
57+
CSF.Doubles = true;
2858
switch (I.getOpcode()) {
2959
case Instruction::FDiv:
3060
case Instruction::UIToFP:
3161
case Instruction::SIToFP:
3262
case Instruction::FPToUI:
3363
case Instruction::FPToSI:
34-
FSF.DX11_1_DoubleExtensions = true;
64+
// TODO: To be set if I is a call to DXIL intrinsic DXIL::Opcode::Fma
65+
CSF.DX11_1_DoubleExtensions = true;
3566
break;
3667
}
3768
}
3869
}
3970

71+
static bool compareFuncSFPairs(const FuncShaderFlagsMask &First,
72+
const FuncShaderFlagsMask &Second) {
73+
// Construct string representation of the functions in each pair
74+
// as "retTypefunctionNamearg1Typearg2Ty..." where the function signature is
75+
// retType functionName(arg1Type, arg2Ty,...). Spaces, braces and commas are
76+
// omitted in the string representation of the signature. This allows
77+
// determining a consistent lexicographical order of all functions by their
78+
// signatures.
79+
std::string FirstFunSig;
80+
std::string SecondFunSig;
81+
raw_string_ostream FRSO(FirstFunSig);
82+
raw_string_ostream SRSO(SecondFunSig);
83+
84+
// Return type
85+
First.first->getReturnType()->print(FRSO);
86+
Second.first->getReturnType()->print(SRSO);
87+
// Function name
88+
FRSO << First.first->getName();
89+
SRSO << Second.first->getName();
90+
// Argument types
91+
for (const Argument &Arg : First.first->args()) {
92+
Arg.getType()->print(FRSO);
93+
}
94+
for (const Argument &Arg : Second.first->args()) {
95+
Arg.getType()->print(SRSO);
96+
}
97+
FRSO.flush();
98+
SRSO.flush();
99+
100+
return FRSO.str().compare(SRSO.str()) < 0;
101+
}
102+
40103
static DXILModuleShaderFlagsInfo computeFlags(Module &M) {
41104
DXILModuleShaderFlagsInfo MSFI;
42-
for (const auto &F : M) {
105+
for (auto &F : M) {
43106
if (F.isDeclaration())
44107
continue;
45-
if (!MSFI.FuncShaderFlagsMap.contains(&F)) {
46-
ComputedShaderFlags CSF{};
47-
MSFI.FuncShaderFlagsMap[&F] = CSF;
108+
// Each of the functions in a module are unique. Hence no prior shader flags
109+
// mask of the function should be present.
110+
if (MSFI.hasShaderFlagsMask(&F)) {
111+
M.getContext().diagnose(DiagnosticInfoShaderFlags(
112+
M, "Shader Flags mask for Function '" + Twine(F.getName()) +
113+
"' already exits"));
48114
}
115+
ComputedShaderFlags CSF{};
49116
for (const auto &BB : F)
50117
for (const auto &I : BB)
51-
updateFlags(MSFI, I);
118+
updateFlags(CSF, I);
119+
// Insert shader flag mask for function F
120+
MSFI.FuncShaderFlagsVec.push_back({&F, CSF});
52121
}
122+
// Sort MSFI.FuncShaderFlagsVec for later lookup that uses binary search
123+
llvm::sort(MSFI.FuncShaderFlagsVec, compareFuncSFPairs);
53124
return MSFI;
54125
}
55126

@@ -71,6 +142,38 @@ void ComputedShaderFlags::print(raw_ostream &OS) const {
71142
OS << ";\n";
72143
}
73144

145+
void DXILModuleShaderFlagsInfo::print(raw_ostream &OS) const {
146+
OS << "; Shader Flags mask for Module:\n";
147+
ModuleFlags.print(OS);
148+
for (auto SF : FuncShaderFlagsVec) {
149+
OS << "; Shader Flags mask for Function: " << SF.first->getName() << "\n";
150+
SF.second.print(OS);
151+
}
152+
}
153+
154+
const ComputedShaderFlags
155+
DXILModuleShaderFlagsInfo::getShaderFlagsMask(const Function *Func) const {
156+
FuncShaderFlagsMask V{Func, {}};
157+
auto Iter = llvm::lower_bound(FuncShaderFlagsVec, V, compareFuncSFPairs);
158+
if (Iter == FuncShaderFlagsVec.end()) {
159+
Func->getContext().diagnose(DiagnosticInfoShaderFlags(
160+
*(Func->getParent()), "Shader Flags information of Function '" +
161+
Twine(Func->getName()) + "' not found"));
162+
}
163+
if (Iter->first != Func) {
164+
Func->getContext().diagnose(DiagnosticInfoShaderFlags(
165+
*(Func->getParent()),
166+
"Inconsistent Shader Flags information of Function '" +
167+
Twine(Func->getName()) + "' retrieved"));
168+
}
169+
return Iter->second;
170+
}
171+
172+
bool DXILModuleShaderFlagsInfo::hasShaderFlagsMask(const Function *Func) const {
173+
FuncShaderFlagsMask V{Func, {}};
174+
return llvm::binary_search(FuncShaderFlagsVec, V);
175+
}
176+
74177
AnalysisKey ShaderFlagsAnalysis::Key;
75178

76179
DXILModuleShaderFlagsInfo ShaderFlagsAnalysis::run(Module &M,
@@ -86,12 +189,7 @@ bool ShaderFlagsAnalysisWrapper::runOnModule(Module &M) {
86189
PreservedAnalyses ShaderFlagsAnalysisPrinter::run(Module &M,
87190
ModuleAnalysisManager &AM) {
88191
DXILModuleShaderFlagsInfo Flags = AM.getResult<ShaderFlagsAnalysis>(M);
89-
OS << "; Shader Flags mask for Module:\n";
90-
Flags.ModuleFlags.print(OS);
91-
for (auto SF : Flags.FuncShaderFlagsMap) {
92-
OS << "; Shader Flags mash for Function: " << SF.first->getName() << "\n";
93-
SF.second.print(OS);
94-
}
192+
Flags.print(OS);
95193
return PreservedAnalyses::all();
96194
}
97195

llvm/lib/Target/DirectX/DXILShaderFlags.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#ifndef LLVM_TARGET_DIRECTX_DXILSHADERFLAGS_H
1515
#define LLVM_TARGET_DIRECTX_DXILSHADERFLAGS_H
1616

17-
#include "llvm/ADT/DenseMap.h"
1817
#include "llvm/IR/Function.h"
1918
#include "llvm/IR/PassManager.h"
2019
#include "llvm/Pass.h"
@@ -66,14 +65,18 @@ struct ComputedShaderFlags {
6665
LLVM_DUMP_METHOD void dump() const { print(); }
6766
};
6867

69-
using FunctionShaderFlagsMap =
70-
SmallDenseMap<Function const *, ComputedShaderFlags>;
68+
using FuncShaderFlagsMask = std::pair<Function const *, ComputedShaderFlags>;
69+
using FunctionShaderFlagsVec = SmallVector<FuncShaderFlagsMask>;
7170
struct DXILModuleShaderFlagsInfo {
7271
// Shader Flag mask representing module-level properties
7372
ComputedShaderFlags ModuleFlags;
74-
// Map representing shader flag mask representing properties of each of the
75-
// functions in the module
76-
FunctionShaderFlagsMap FuncShaderFlagsMap;
73+
// Vector of Function-Shader Flag mask pairs representing properties of each
74+
// of the functions in the module
75+
FunctionShaderFlagsVec FuncShaderFlagsVec;
76+
77+
const ComputedShaderFlags getShaderFlagsMask(const Function *Func) const;
78+
bool hasShaderFlagsMask(const Function *Func) const;
79+
void print(raw_ostream &OS = dbgs()) const;
7780
};
7881

7982
class ShaderFlagsAnalysis : public AnalysisInfoMixin<ShaderFlagsAnalysis> {

llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ static void translateMetadata(Module &M, const DXILResourceMap &DRM,
318318
// to be used as shader flags mask value associated with top-level library
319319
// entry metadata.
320320
uint64_t ConsolidatedMask = ShaderFlags.ModuleFlags;
321-
for (const auto &FunFlags : ShaderFlags.FuncShaderFlagsMap) {
321+
for (const auto &FunFlags : ShaderFlags.FuncShaderFlagsVec) {
322322
ConsolidatedMask |= FunFlags.second;
323323
}
324324
EntryFnMDNodes.emplace_back(
@@ -329,20 +329,15 @@ static void translateMetadata(Module &M, const DXILResourceMap &DRM,
329329
}
330330

331331
for (const EntryProperties &EntryProp : MMDI.EntryPropertyVec) {
332-
auto FSFIt = ShaderFlags.FuncShaderFlagsMap.find(EntryProp.Entry);
333-
if (FSFIt == ShaderFlags.FuncShaderFlagsMap.end()) {
334-
M.getContext().diagnose(DiagnosticInfoTranslateMD(
335-
M, "Shader Flags of Function '" + Twine(EntryProp.Entry->getName()) +
336-
"' not found"));
337-
}
332+
ComputedShaderFlags ECSF = ShaderFlags.getShaderFlagsMask(EntryProp.Entry);
338333
// If ShaderProfile is Library, mask is already consolidated in the
339334
// top-level library node. Hence it is not emitted.
340335
uint64_t EntryShaderFlags = 0;
341336
if (MMDI.ShaderProfile != Triple::EnvironmentType::Library) {
342337
// TODO: Create a consolidated shader flag mask of all the entry
343338
// functions and its callees. The following is correct only if
344-
// (*FSIt).first has no call instructions.
345-
EntryShaderFlags = (*FSFIt).second | ShaderFlags.ModuleFlags;
339+
// EntryProp.Entry has no call instructions.
340+
EntryShaderFlags = ECSF | ShaderFlags.ModuleFlags;
346341
}
347342
if (MMDI.ShaderProfile != Triple::EnvironmentType::Library) {
348343
if (EntryProp.ShaderStage != MMDI.ShaderProfile) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
2+
3+
target triple = "dxil-pc-shadermodel6.7-library"
4+
define double @div(double %a, double %b) #0 {
5+
%res = fdiv double %a, %b
6+
ret double %res
7+
}
8+
9+
attributes #0 = { convergent norecurse nounwind "hlsl.export"}
10+
11+
; DXC: - Name: SFI0
12+
; DXC-NEXT: Size: 8
13+
; DXC-NEXT: Flags:
14+
; DXC-NEXT: Doubles: true
15+
; DXC-NOT: {{[A-Za-z]+: +true}}
16+
; DXC: DX11_1_DoubleExtensions: true
17+
; DXC-NOT: {{[A-Za-z]+: +true}}
18+
; DXC: NextUnusedBit: false
19+
; DXC: ...
Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,74 @@
11
; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
2-
; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
32

43
target triple = "dxil-pc-shadermodel6.7-library"
54

6-
; CHECK: ; Shader Flags Value: 0x00000044
7-
; CHECK: ; Note: shader requires additional functionality:
5+
; CHECK: ; Shader Flags mask for Module:
6+
; CHECK-NEXT: ; Shader Flags Value: 0x00000000
7+
; CHECK-NEXT: ;
8+
; CHECK-NEXT: ; Shader Flags mask for Function: test_fdiv_double
9+
; CHECK-NEXT: ; Shader Flags Value: 0x00000044
10+
; CHECK-NEXT: ;
11+
; CHECK-NEXT: ; Note: shader requires additional functionality:
812
; CHECK-NEXT: ; Double-precision floating point
913
; CHECK-NEXT: ; Double-precision extensions for 11.1
1014
; CHECK-NEXT: ; Note: extra DXIL module flags:
11-
; CHECK-NEXT: {{^;$}}
12-
define double @div(double %a, double %b) #0 {
15+
; CHECK-NEXT: ;
16+
; CHECK-NEXT: ; Shader Flags mask for Function: test_sitofp_i64
17+
; CHECK-NEXT: ; Shader Flags Value: 0x00000044
18+
; CHECK-NEXT: ;
19+
; CHECK-NEXT: ; Note: shader requires additional functionality:
20+
; CHECK-NEXT: ; Double-precision floating point
21+
; CHECK-NEXT: ; Double-precision extensions for 11.1
22+
; CHECK-NEXT: ; Note: extra DXIL module flags:
23+
; CHECK-NEXT: ;
24+
; CHECK-NEXT: ; Shader Flags mask for Function: test_uitofp_i64
25+
; CHECK-NEXT: ; Shader Flags Value: 0x00000044
26+
; CHECK-NEXT: ;
27+
; CHECK-NEXT: ; Note: shader requires additional functionality:
28+
; CHECK-NEXT: ; Double-precision floating point
29+
; CHECK-NEXT: ; Double-precision extensions for 11.1
30+
; CHECK-NEXT: ; Note: extra DXIL module flags:
31+
; CHECK-NEXT: ;
32+
; CHECK-NEXT: ; Shader Flags mask for Function: test_fptoui_i32
33+
; CHECK-NEXT: ; Shader Flags Value: 0x00000044
34+
; CHECK-NEXT: ;
35+
; CHECK-NEXT: ; Note: shader requires additional functionality:
36+
; CHECK-NEXT: ; Double-precision floating point
37+
; CHECK-NEXT: ; Double-precision extensions for 11.1
38+
; CHECK-NEXT: ; Note: extra DXIL module flags:
39+
; CHECK-NEXT: ;
40+
; CHECK-NEXT: ; Shader Flags mask for Function: test_fptosi_i64
41+
; CHECK-NEXT: ; Shader Flags Value: 0x00000044
42+
; CHECK-NEXT: ;
43+
; CHECK-NEXT: ; Note: shader requires additional functionality:
44+
; CHECK-NEXT: ; Double-precision floating point
45+
; CHECK-NEXT: ; Double-precision extensions for 11.1
46+
; CHECK-NEXT: ; Note: extra DXIL module flags:
47+
; CHECK-NEXT: ;
48+
49+
define double @test_fdiv_double(double %a, double %b) #0 {
1350
%res = fdiv double %a, %b
1451
ret double %res
1552
}
1653

17-
attributes #0 = { convergent norecurse nounwind "hlsl.export"}
54+
define double @test_uitofp_i64(i64 %a) #0 {
55+
%r = uitofp i64 %a to double
56+
ret double %r
57+
}
58+
59+
define double @test_sitofp_i64(i64 %a) #0 {
60+
%r = sitofp i64 %a to double
61+
ret double %r
62+
}
1863

19-
; DXC: - Name: SFI0
20-
; DXC-NEXT: Size: 8
21-
; DXC-NEXT: Flags:
22-
; DXC-NEXT: Doubles: true
23-
; DXC-NOT: {{[A-Za-z]+: +true}}
24-
; DXC: DX11_1_DoubleExtensions: true
25-
; DXC-NOT: {{[A-Za-z]+: +true}}
26-
; DXC: NextUnusedBit: false
27-
; DXC: ...
64+
define i32 @test_fptoui_i32(double %a) #0 {
65+
%r = fptoui double %a to i32
66+
ret i32 %r
67+
}
68+
69+
define i64 @test_fptosi_i64(double %a) #0 {
70+
%r = fptosi double %a to i64
71+
ret i64 %r
72+
}
73+
74+
attributes #0 = { convergent norecurse nounwind "hlsl.export"}

llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
target triple = "dxil-pc-shadermodel6.7-library"
55

6-
; CHECK: ; Shader Flags Value: 0x00000004
6+
; CHECK: ; Shader Flags mask for Module:
7+
; CHECK-NEXT: ; Shader Flags Value: 0x00000000
8+
; CHECK: ; Shader Flags mask for Function: add
9+
; CHECK-NEXT: ; Shader Flags Value: 0x00000004
710
; CHECK: ; Note: shader requires additional functionality:
811
; CHECK-NEXT: ; Double-precision floating point
912
; CHECK-NEXT: ; Note: extra DXIL module flags:

llvm/test/CodeGen/DirectX/ShaderFlags/no_flags.ll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
target triple = "dxil-pc-shadermodel6.7-library"
44

5-
; CHECK: ; Shader Flags Value: 0x00000000
5+
; CHECK: ; Shader Flags mask for Module:
6+
; CHECK-NEXT: ; Shader Flags Value: 0x00000000
7+
;
8+
; CHECK: ; Shader Flags mask for Function: add
9+
; CHECK-NEXT: ; Shader Flags Value: 0x00000000
610
define i32 @add(i32 %a, i32 %b) {
711
%sum = add i32 %a, %b
812
ret i32 %sum

0 commit comments

Comments
 (0)