Enable write to global vars with /Gec flag and HLSLVersion <= 2016 (#1526)
This commit is contained in:
Родитель
a2085d4491
Коммит
afff6a3c51
|
@ -33,6 +33,15 @@ namespace dxilutil {
|
|||
llvm::Type *GetArrayEltTy(llvm::Type *Ty);
|
||||
bool HasDynamicIndexing(llvm::Value *V);
|
||||
|
||||
// Find alloca insertion point, given instruction
|
||||
llvm::Instruction *FindAllocaInsertionPt(llvm::Instruction* I);
|
||||
llvm::Instruction *FindAllocaInsertionPt(llvm::Function* F);
|
||||
llvm::Instruction *SkipAllocas(llvm::Instruction *I);
|
||||
// Get first non-alloca insertion point, to avoid inserting non-allocas before alloca
|
||||
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Instruction* I);
|
||||
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::BasicBlock* BB);
|
||||
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Function* F);
|
||||
|
||||
bool IsStaticGlobal(llvm::GlobalVariable *GV);
|
||||
bool IsSharedMemoryGlobal(llvm::GlobalVariable *GV);
|
||||
bool RemoveUnusedFunctions(llvm::Module &M, llvm::Function *EntryFunc,
|
||||
|
|
|
@ -130,6 +130,7 @@ public:
|
|||
bool AvoidFlowControl = false; // OPT_Gfa
|
||||
bool PreferFlowControl = false; // OPT_Gfp
|
||||
bool EnableStrictMode = false; // OPT_Ges
|
||||
bool EnableBackCompatMode = false; // OPT_Gec
|
||||
unsigned long HLSLVersion = 0; // OPT_hlsl_version (2015-2018)
|
||||
bool Enable16BitTypes = false; // OPT_enable_16bit_types
|
||||
bool OptDump = false; // OPT_ODump - dump optimizer commands
|
||||
|
|
|
@ -306,6 +306,7 @@ def Zsb : Flag<["-", "/"], "Zsb">, Flags<[CoreOption]>, Group<hlslcomp_Group>,
|
|||
def Gfa : Flag<["-", "/"], "Gfa">, HelpText<"Avoid flow control constructs">, Flags<[CoreOption]>, Group<hlslcomp_Group>;
|
||||
def Gfp : Flag<["-", "/"], "Gfp">, HelpText<"Prefer flow control constructs">, Flags<[CoreOption]>, Group<hlslcomp_Group>;
|
||||
// /Gdp - disable effect performance mode - unsupported
|
||||
def Gec : Flag<["-", "/"], "Gec">, HelpText<"Enable backward compatibility mode">, Flags<[CoreOption]>, Group<hlslcomp_Group>;
|
||||
def Ges : Flag<["-", "/"], "Ges">, HelpText<"Enable strict mode">, Flags<[CoreOption]>, Group<hlslcomp_Group>;
|
||||
def Gis : Flag<["-", "/"], "Gis">, HelpText<"Force IEEE strictness">, Flags<[CoreOption]>, Group<hlslcomp_Group>;
|
||||
|
||||
|
@ -368,7 +369,7 @@ def getprivate : JoinedOrSeparate<["-", "/"], "getprivate">, Flags<[DriverOption
|
|||
def nologo : Flag<["-", "/"], "nologo">, Group<hlslcore_Group>, Flags<[DriverOption]>,
|
||||
HelpText<"Suppress copyright message">;
|
||||
|
||||
// Also removed: compress, decompress, /Gch (child effect), /Gec (back compat), /Gpp (partial precision)
|
||||
// Also removed: compress, decompress, /Gch (child effect), /Gpp (partial precision)
|
||||
// /Op - no support for preshaders.
|
||||
|
||||
def flegacy_macro_expansion : Flag<["-"], "flegacy-macro-expansion">, Group<hlslcomp_Group>, Flags<[CoreOption, DriverOption]>,
|
||||
|
|
|
@ -340,9 +340,14 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
|
|||
}
|
||||
}
|
||||
|
||||
opts.EnableBackCompatMode = Args.hasFlag(OPT_Gec, OPT_INVALID, false);
|
||||
llvm::StringRef ver = Args.getLastArgValue(OPT_hlsl_version);
|
||||
if (ver.empty()) { opts.HLSLVersion = 2018; } // Default to latest version
|
||||
else {
|
||||
if (ver.empty()) {
|
||||
if (opts.EnableBackCompatMode)
|
||||
opts.HLSLVersion = 2016; // Default to max supported version with /Gec flag
|
||||
else
|
||||
opts.HLSLVersion = 2018; // Default to latest version
|
||||
} else {
|
||||
try {
|
||||
opts.HLSLVersion = std::stoul(std::string(ver));
|
||||
if (opts.HLSLVersion < 2015 || opts.HLSLVersion > 2018) {
|
||||
|
@ -365,6 +370,11 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (opts.EnableBackCompatMode && opts.HLSLVersion > 2016) {
|
||||
errors << "/Gec is not supported with HLSLVersion " << opts.HLSLVersion;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// AssemblyCodeHex not supported (Fx)
|
||||
// OutputLibrary not supported (Fl)
|
||||
opts.AssemblyCode = Args.getLastArgValue(OPT_Fc);
|
||||
|
|
|
@ -148,5 +148,33 @@ std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::StringRef BC,
|
|||
return LoadModuleFromBitcode(pBitcodeBuf.get(), Ctx, DiagStr);
|
||||
}
|
||||
|
||||
llvm::Instruction *SkipAllocas(llvm::Instruction *I) {
|
||||
// Step past any allocas:
|
||||
while (I && isa<AllocaInst>(I))
|
||||
I = I->getNextNode();
|
||||
return I;
|
||||
}
|
||||
llvm::Instruction *FindAllocaInsertionPt(llvm::Instruction* I) {
|
||||
Function *F = I->getParent()->getParent();
|
||||
if (F)
|
||||
return F->getEntryBlock().getFirstInsertionPt();
|
||||
else // BB with no parent function
|
||||
return I->getParent()->getFirstInsertionPt();
|
||||
}
|
||||
llvm::Instruction *FindAllocaInsertionPt(llvm::Function* F) {
|
||||
return F->getEntryBlock().getFirstInsertionPt();
|
||||
}
|
||||
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Instruction* I) {
|
||||
return SkipAllocas(FindAllocaInsertionPt(I));
|
||||
}
|
||||
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::BasicBlock* BB) {
|
||||
return SkipAllocas(
|
||||
BB->getFirstInsertionPt());
|
||||
}
|
||||
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Function* F) {
|
||||
return SkipAllocas(
|
||||
F->getEntryBlock().getFirstInsertionPt());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,6 +156,7 @@ public:
|
|||
unsigned RootSigMinor;
|
||||
bool IsHLSLLibrary;
|
||||
bool UseMinPrecision; // use min precision, not native precision.
|
||||
bool EnableBackCompatMode;
|
||||
// HLSL Change Ends
|
||||
|
||||
bool SPIRV = false; // SPIRV Change
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
|
||||
#include "dxc/HLSL/DxilRootSignature.h"
|
||||
#include "dxc/HLSL/DxilCBuffer.h"
|
||||
|
@ -4246,6 +4247,92 @@ void CGMSHLSLRuntime::SetPatchConstantFunctionWithAttr(
|
|||
|
||||
}
|
||||
|
||||
// Returns true a global value is being updated
|
||||
static bool GlobalHasStoreUserRec(Value *V, std::set<Value *> &visited) {
|
||||
bool isWriteEnabled = false;
|
||||
if (V && visited.find(V) == visited.end()) {
|
||||
visited.insert(V);
|
||||
for (User *U : V->users()) {
|
||||
if (isa<StoreInst>(U)) {
|
||||
return true;
|
||||
} else if (CallInst* CI = dyn_cast<CallInst>(U)) {
|
||||
Function *F = CI->getCalledFunction();
|
||||
if (!F->isIntrinsic()) {
|
||||
HLOpcodeGroup hlGroup = GetHLOpcodeGroup(F);
|
||||
switch (hlGroup) {
|
||||
case HLOpcodeGroup::NotHL:
|
||||
return true;
|
||||
case HLOpcodeGroup::HLMatLoadStore:
|
||||
{
|
||||
HLMatLoadStoreOpcode opCode = static_cast<HLMatLoadStoreOpcode>(hlsl::GetHLOpcode(CI));
|
||||
if (opCode == HLMatLoadStoreOpcode::ColMatStore || opCode == HLMatLoadStoreOpcode::RowMatStore)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case HLOpcodeGroup::HLCast:
|
||||
case HLOpcodeGroup::HLSubscript:
|
||||
if (GlobalHasStoreUserRec(U, visited))
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (isa<GEPOperator>(U) || isa<PHINode>(U) || isa<SelectInst>(U)) {
|
||||
if (GlobalHasStoreUserRec(U, visited))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isWriteEnabled;
|
||||
}
|
||||
|
||||
// Returns true if any of the direct user of a global is a store inst
|
||||
// otherwise recurse through the remaining users and check if any GEP
|
||||
// exists and which in turn has a store inst as user.
|
||||
static bool GlobalHasStoreUser(GlobalVariable *GV) {
|
||||
std::set<Value *> visited;
|
||||
Value *V = cast<Value>(GV);
|
||||
return GlobalHasStoreUserRec(V, visited);
|
||||
}
|
||||
|
||||
static GlobalVariable *CreateStaticGlobal(llvm::Module *M, GlobalVariable *GV) {
|
||||
Constant *GC = M->getOrInsertGlobal(GV->getName().str() + ".static.copy",
|
||||
GV->getType()->getPointerElementType());
|
||||
GlobalVariable *NGV = cast<GlobalVariable>(GC);
|
||||
if (GV->hasInitializer()) {
|
||||
NGV->setInitializer(GV->getInitializer());
|
||||
}
|
||||
// static global should have internal linkage
|
||||
NGV->setLinkage(GlobalValue::InternalLinkage);
|
||||
return NGV;
|
||||
}
|
||||
|
||||
static void CreateWriteEnabledStaticGlobals(llvm::Module *M,
|
||||
llvm::Function *EF) {
|
||||
std::vector<GlobalVariable *> worklist;
|
||||
for (GlobalVariable &GV : M->globals()) {
|
||||
if (!GV.isConstant() && GV.getLinkage() != GlobalValue::InternalLinkage) {
|
||||
if (GlobalHasStoreUser(&GV))
|
||||
worklist.emplace_back(&GV);
|
||||
// TODO: Ensure that constant globals aren't using initializer
|
||||
GV.setConstant(true);
|
||||
}
|
||||
}
|
||||
|
||||
IRBuilder<> Builder(
|
||||
dxilutil::FirstNonAllocaInsertionPt(&EF->getEntryBlock()));
|
||||
for (GlobalVariable *GV : worklist) {
|
||||
GlobalVariable *NGV = CreateStaticGlobal(M, GV);
|
||||
GV->replaceAllUsesWith(NGV);
|
||||
|
||||
// insert memcpy in all entryblocks
|
||||
uint64_t size = M->getDataLayout().getTypeAllocSize(
|
||||
GV->getType()->getPointerElementType());
|
||||
Builder.CreateMemCpy(NGV, GV, size, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void CGMSHLSLRuntime::FinishCodeGen() {
|
||||
// Library don't have entry.
|
||||
if (!m_bIsLib) {
|
||||
|
@ -4258,6 +4345,11 @@ void CGMSHLSLRuntime::FinishCodeGen() {
|
|||
return;
|
||||
}
|
||||
|
||||
// In back-compat mode (with /Gec flag) create a static global for each const global
|
||||
// to allow writing to it.
|
||||
// TODO: Verfiy the behavior of static globals in hull shader
|
||||
if(CGM.getLangOpts().EnableBackCompatMode && CGM.getLangOpts().HLSLVersion <= 2016)
|
||||
CreateWriteEnabledStaticGlobals(m_pHLModule->GetModule(), m_pHLModule->GetEntryFunction());
|
||||
if (m_pHLModule->GetShaderModel()->IsHS()) {
|
||||
SetPatchConstantFunction(Entry);
|
||||
}
|
||||
|
|
|
@ -2184,7 +2184,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
|
|||
|
||||
// global variable can be inside a global structure as a static member.
|
||||
// Check if the global is a static member and skip global const pass.
|
||||
bool CheckGlobalConst = true;
|
||||
// in backcompat mode, the check for global const is deferred to later stage in CGMSHLSLRuntime::FinishCodeGen()
|
||||
bool CheckGlobalConst = getLangOpts().HLSL && getLangOpts().EnableBackCompatMode && getLangOpts().HLSLVersion <= 2016 ? false : true;
|
||||
if (NestedNameSpecifier *nameSpecifier = D.getCXXScopeSpec().getScopeRep()) {
|
||||
if (nameSpecifier->getKind() == NestedNameSpecifier::SpecifierKind::TypeSpec) {
|
||||
const Type *type = D.getCXXScopeSpec().getScopeRep()->getAsType();
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// RUN: %dxc -E main -T ps_6_0 /Gec -HV 2016 > %s | FileCheck %s
|
||||
|
||||
// Writing to globals only supported with HV <= 2016
|
||||
// CHECK: define void @main
|
||||
// CHECK: ret void
|
||||
|
||||
float g_s;
|
||||
float4 g_v = float4(1.0, -1.0, 0.0, 1.0);
|
||||
// TODO: writing to a global matrix currently causes the compiler to crash. fix it.
|
||||
// int2x2 g_m;
|
||||
bool g_b = false;
|
||||
int g_a[5];
|
||||
int g_a2d[3][2];
|
||||
float4 main(uint a
|
||||
: A) : SV_Target {
|
||||
// update global scalar
|
||||
g_s = a;
|
||||
|
||||
// update global vector
|
||||
g_v = float4(a + 1, a + 2, a + 3, a + 4);
|
||||
|
||||
/*
|
||||
// update global matrix
|
||||
for (uint i = 0; i < 2; i++)
|
||||
for (uint j = 0; j < 2; j++)
|
||||
g_m[i][j] = a + i + j;
|
||||
*/
|
||||
|
||||
// update global 2d array
|
||||
for (uint i = 0; i < 3; i++)
|
||||
for (uint j = 0; j < 2; j++)
|
||||
g_a2d[i][j] = a + i + j;
|
||||
|
||||
// update global array
|
||||
for (uint i = 0; i < 5; i++)
|
||||
g_a[i] = a + i;
|
||||
|
||||
// update global boolean
|
||||
g_b = true;
|
||||
|
||||
return float4(g_s, g_s, g_s, g_s) +
|
||||
g_v +
|
||||
// float4(g_m[0][0], g_m[0][1], g_m[1][0], g_m[1][1]) +
|
||||
float4(g_a2d[0][0], g_a2d[0][1], g_a2d[1][0], g_a2d[1][1]) +
|
||||
float4(g_a[0], g_a[1], g_a[2], g_a[3]);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// RUN: %dxc -E main -T ps_6_0 /Gec -HV 2016 2> %s | FileCheck %s
|
||||
|
||||
// Modifying local const should fail even with HV <= 2016
|
||||
// CHECK: warning: /Gec flag is a deprecated functionality.
|
||||
// CHECK: error: cannot assign to variable 'l_s' with const-qualified type 'const int'
|
||||
// CHECK: note: variable 'l_s' declared const here
|
||||
|
||||
float main(uint a
|
||||
: A) : SV_Target {
|
||||
// update global scalar
|
||||
const int l_s = 1;
|
||||
l_s *= 2;
|
||||
return 1.33f * l_s;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// RUN: %dxc -T ps_6_0 -E PSMain /Gec -HV 2016 > %s | FileCheck %s
|
||||
|
||||
// CHECK: {{.*cbvar.*}} = constant float 0.000000e+00, align 4
|
||||
// CHECK: define void @PSMain()
|
||||
// CHECK: call %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32 59, %dx.types.Handle %"$Globals_buffer", i32 0)
|
||||
// CHECK: %{{[a-z0-9]+.*[a-z0-9]*}} = fadd fast float %{{[a-z0-9]+.*[a-z0-9]*}}, 5.000000e+00
|
||||
// CHECK: %{{[a-z0-9]+.*[a-z0-9]*}} = fmul fast float %{{[a-z0-9]+.*[a-z0-9]*}}, 3.000000e+00
|
||||
// CHECK: ret void
|
||||
|
||||
float cbvar;
|
||||
|
||||
void AddVal() { cbvar += 5.0; }
|
||||
void MulVal() { cbvar *= 3.0; }
|
||||
float GetVal() { return cbvar; }
|
||||
|
||||
float PSMain() : SV_Target
|
||||
{
|
||||
AddVal();
|
||||
MulVal();
|
||||
return GetVal();
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// RUN: %dxc -E main -fcgl -T ps_6_0 /Gec -HV 2016 > %s | FileCheck %s
|
||||
|
||||
// Writing to globals only supported with HV <= 2016
|
||||
|
||||
// CHECK: {{.*g_s1.*}} = constant float 0.000000e+00, align 4
|
||||
// CHECK: {{.*g_s2.*}} = constant float 0.000000e+00, align 4
|
||||
// CHECK: {{.*g_v.*}} = constant <4 x float> zeroinitializer, align 4
|
||||
// CHECK: {{.*g_m1.*}} = constant %class.matrix.int.2.2 zeroinitializer, align 4
|
||||
// CHECK: {{.*g_m2.*}} = constant %class.matrix.int.2.2 zeroinitializer, align 4
|
||||
// CHECK: {{.*g_b.*}} = constant i32 0, align 1
|
||||
// CHECK: {{.*g_a.*}} = constant [5 x i32] zeroinitializer, align 4
|
||||
// CHECK: {{.*g_a2d.*}} = constant [3 x [2 x i32]] zeroinitializer, align 4
|
||||
// CHECK-NOT: {{(.*g_s1.*)(.*static.copy.*)}} = internal global float 0.000000e+00
|
||||
// CHECK: {{(.*g_s2.*)(.*static.copy.*)}} = internal global float 0.000000e+00
|
||||
// CHECK-NOT: {{(.*g_v.*)(.*static.copy.*)}} = internal global <4 x float> zeroinitializer
|
||||
// CHECK-NOT: {{(.*g_m1.*)(.*static.copy.*)}} = internal global %class.matrix.int.2.2 zeroinitializer
|
||||
// CHECK: {{(.*g_m2.*)(.*static.copy.*)}} = internal global %class.matrix.int.2.2 zeroinitializer
|
||||
// CHECK-NOT: {{(.*g_b.*)(.*static.copy.*)}} = internal global i32 0
|
||||
// CHECK-NOT: {{(.*g_a.*)(.*static.copy.*)}} = internal global [5 x i32] zeroinitializer
|
||||
// CHECK-NOT: {{(.*g_a2d.*)(.*static.copy.*)}} = internal global [3 x [2 x i32]] zeroinitializer
|
||||
// CHECK: define <4 x float> @main
|
||||
// CHECK: ret %dx.types.Handle undef
|
||||
|
||||
float g_s1;
|
||||
float g_s2; // write enabled
|
||||
float4 g_v;
|
||||
int2x2 g_m1;
|
||||
int2x2 g_m2; // write enabled
|
||||
bool g_b;
|
||||
int g_a[5];
|
||||
int g_a2d[3][2];
|
||||
float4 main(uint a
|
||||
: A) : SV_Target {
|
||||
g_s2 = a * 2.0f;
|
||||
|
||||
for (uint i = 0; i < 2; i++)
|
||||
for (uint j = 0; j < 2; j++)
|
||||
g_m2[i][j] = a + i + j;
|
||||
|
||||
|
||||
return float4(g_s1, g_s1, g_s2, g_s2) +
|
||||
g_v +
|
||||
float4(g_m1[0][0], g_m1[0][1], g_m2[1][0], g_m2[1][1]) +
|
||||
float4(g_a2d[0][0], g_a2d[0][1], g_a2d[1][0], g_a2d[1][1]) +
|
||||
float4(g_a[0], g_a[1], g_a[2], g_a[3]);
|
||||
}
|
|
@ -813,6 +813,10 @@ public:
|
|||
compiler.createSourceManager(compiler.getFileManager());
|
||||
compiler.setTarget(
|
||||
TargetInfo::CreateTargetInfo(compiler.getDiagnostics(), targetOptions));
|
||||
if (Opts.EnableBackCompatMode) {
|
||||
auto const ID = compiler.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Warning, "/Gec flag is a deprecated functionality.");
|
||||
compiler.getDiagnostics().Report(ID);
|
||||
}
|
||||
|
||||
compiler.getFrontendOpts().Inputs.push_back(FrontendInputFile(pMainFile, IK_HLSL));
|
||||
// Setup debug information.
|
||||
|
@ -864,6 +868,7 @@ public:
|
|||
compiler.getLangOpts().RootSigMajor = 1;
|
||||
compiler.getLangOpts().RootSigMinor = rootSigMinor;
|
||||
compiler.getLangOpts().HLSLVersion = (unsigned) Opts.HLSLVersion;
|
||||
compiler.getLangOpts().EnableBackCompatMode = Opts.EnableBackCompatMode;
|
||||
|
||||
compiler.getLangOpts().UseMinPrecision = !Opts.Enable16BitTypes;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче