Enable write to global vars with /Gec flag and HLSLVersion <= 2016 (#1526)

This commit is contained in:
Vishal Sharma 2018-09-07 19:51:39 -07:00 коммит произвёл GitHub
Родитель a2085d4491
Коммит afff6a3c51
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 279 добавлений и 4 удалений

Просмотреть файл

@ -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;