ソースを参照

Add lib_6_x target for offline linking use only

Tex Riddell 7 年 前
コミット
b6f8cbc420

+ 2 - 1
include/dxc/HLSL/DxilShaderModel.h

@@ -30,6 +30,7 @@ public:
   // Major/Minor version of highest shader model
   static const unsigned kHighestMajor = 6;
   static const unsigned kHighestMinor = 3;
+  static const unsigned kOfflineMinor = 0xF;
 
   bool IsPS() const     { return m_Kind == Kind::Pixel; }
   bool IsVS() const     { return m_Kind == Kind::Vertex; }
@@ -93,7 +94,7 @@ private:
               unsigned m_NumInputRegs, unsigned m_NumOutputRegs,
               bool m_bUAVs, bool m_bTypedUavs, unsigned m_UAVRegsLim);
 
-  static const unsigned kNumShaderModels = 48;
+  static const unsigned kNumShaderModels = 49;
   static const ShaderModel ms_ShaderModels[kNumShaderModels];
 
   static const ShaderModel *GetInvalid();

+ 31 - 16
lib/DxcSupport/HLSLOptions.cpp

@@ -174,17 +174,29 @@ StringRefUtf16::StringRefUtf16(llvm::StringRef value) {
 }
 
 static bool GetTargetVersionFromString(llvm::StringRef ref, unsigned *major, unsigned *minor) {
-  try {
-    *major = (unsigned)std::stoul(std::string(1, ref[ref.size() - 3]));
-    *minor = (unsigned)std::stoul(std::string(1, ref[ref.size() - 1]));
-    return true;
-  }
-  catch (std::invalid_argument &) {
+  *major = *minor = -1;
+  unsigned len = ref.size();
+  if (len < 6 || len > 11) // length: ps_6_0 to rootsig_1_0
     return false;
-  }
-  catch (std::out_of_range &) {
+  if (ref[len - 4] != '_' || ref[len - 2] != '_')
     return false;
-  }
+
+  char cMajor = ref[len - 3];
+  char cMinor = ref[len - 1];
+
+  if (cMajor >= '0' && cMajor <= '9')
+    *major = cMajor - '0';
+  else
+    return false;
+
+  if (cMinor == 'x')
+    *minor = 0xF;
+  else if (cMinor >= '0' && cMinor <= '9')
+    *minor = cMinor - '0';
+  else
+    return false;
+
+  return true;
 }
 
 namespace hlsl {
@@ -266,16 +278,11 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
       // Set entry point to impossible name.
       opts.EntryPoint = "lib.no::entry";
     }
-    if (Args.getLastArg(OPT_exports) &&
-        Args.hasFlag(OPT_export_shaders_only)) {
-      errors << "-exports option cannot be used with -export-shaders-only";
-      return 1;
-    }
   } else {
     if (Args.getLastArg(OPT_exports)) {
       errors << "library profile required when using -exports option";
       return 1;
-    } else if (Args.hasFlag(OPT_export_shaders_only)) {
+    } else if (Args.hasFlag(OPT_export_shaders_only, OPT_INVALID, false)) {
       errors << "library profile required when using -export-shaders-only option";
       return 1;
     }
@@ -370,7 +377,10 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   unsigned Major = 0;
   unsigned Minor = 0;
   if (!opts.TargetProfile.empty()) {
-    GetTargetVersionFromString(opts.TargetProfile, &Major, &Minor);
+    if (!GetTargetVersionFromString(opts.TargetProfile, &Major, &Minor)) {
+      errors << "unable to parse shader model.";
+      return 1;
+    }
   }
 
   if (opts.TargetProfile.empty() || Major < 6 || (Major == 6 && Minor < 2)) {
@@ -506,6 +516,11 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
     return 1;
   }
 
+  if (opts.IsLibraryProfile() && Minor == 0xF) {
+    // Disable validation for offline link only target
+    opts.DisableValidation = true;
+  }
+
   // SPIRV Change Starts
 #ifdef ENABLE_SPIRV_CODEGEN
   const bool genSpirv = opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);

+ 3 - 0
lib/HLSL/DxilCondenseResources.cpp

@@ -506,6 +506,9 @@ public:
 
     bChanged |= AllocateDxilResources(DM);
 
+    if (m_bIsLib && DM.GetShaderModel()->GetMinor() == ShaderModel::kOfflineMinor)
+      return bChanged;
+
     // Make sure no select on resource.
     bChanged |= RemovePhiOnResource();
 

+ 1 - 0
lib/HLSL/DxilLinker.cpp

@@ -1046,6 +1046,7 @@ void DxilLinkJob::RunPreparePass(Module &M) {
   PM.add(createGlobalDCEPass());
 
   PM.add(createDxilLowerCreateHandleForLibPass());
+  PM.add(createDxilTranslateRawBuffer());
   PM.add(createDxilFinalizeModulePass());
   PM.add(createComputeViewIdStatePass());
   PM.add(createDxilDeadFunctionEliminationPass());

+ 2 - 1
lib/HLSL/DxilMetadataHelper.cpp

@@ -183,7 +183,8 @@ void DxilMDHelper::LoadDxilShaderModel(const ShaderModel *&pSM) {
   unsigned Major = ConstMDToUint32(pShaderModelMD->getOperand(kDxilShaderModelMajorIdx));
   unsigned Minor = ConstMDToUint32(pShaderModelMD->getOperand(kDxilShaderModelMinorIdx));
   string ShaderModelName = pShaderTypeMD->getString();
-  ShaderModelName += "_" + std::to_string(Major) + "_" + std::to_string(Minor);
+  ShaderModelName += "_" + std::to_string(Major) + "_" +
+    (Minor == ShaderModel::kOfflineMinor ? "x" : std::to_string(Minor));
   pSM = ShaderModel::GetByName(ShaderModelName.c_str());
   if (!pSM->IsValidForDxil()) {
     char ErrorMsgTxt[40];

+ 16 - 0
lib/HLSL/DxilShaderModel.cpp

@@ -59,6 +59,8 @@ bool ShaderModel::IsValidForDxil() const {
       case 2:
       case 3:
         return true;
+      case kOfflineMinor:
+        return m_Kind == Kind::Library;
       }
     }
     break;
@@ -139,6 +141,12 @@ const ShaderModel *ShaderModel::GetByName(const char *pszName) {
         break;
       }
       else return GetInvalid();
+    case 'x':
+      if (kind == Kind::Library && Major == 6) {
+        Minor = kOfflineMinor;
+        break;
+      }
+      else return GetInvalid();
     default:  return GetInvalid();
   }
   if (pszName[Idx++] != 0)
@@ -161,6 +169,7 @@ void ShaderModel::GetDxilVersion(unsigned &DxilMajor, unsigned &DxilMinor) const
     DxilMinor = 2;
     break;
   case 3:
+  case kOfflineMinor: // Always update this to highest dxil version
     DxilMinor = 3;
     break;
   default:
@@ -185,6 +194,10 @@ void ShaderModel::GetMinValidatorVersion(unsigned &ValMajor, unsigned &ValMinor)
   case 3:
     ValMinor = 3;
     break;
+  case kOfflineMinor:
+    ValMajor = 0;
+    ValMinor = 0;
+    break;
   default:
     DXASSERT(0, "IsValidForDxil() should have caught this.");
     break;
@@ -265,6 +278,9 @@ const ShaderModel ShaderModel::ms_ShaderModels[kNumShaderModels] = {
   SM(Kind::Library,  6, 2, "lib_6_2",  32, 32,  true,  true,  UINT_MAX),
   SM(Kind::Library,  6, 3, "lib_6_3",  32, 32,  true,  true,  UINT_MAX),
 
+  // lib_6_x is for offline linking only, and relaxes restrictions
+  SM(Kind::Library,  6, kOfflineMinor, "lib_6_x",  32, 32,  true,  true,  UINT_MAX),
+
   SM(Kind::Invalid,  0, 0, "invalid", 0,  0,   false, false, 0),
 };
 

+ 1 - 1
lib/HLSL/DxilValidation.cpp

@@ -520,7 +520,7 @@ struct ValidationContext {
   }
 
   void EmitGlobalValueError(GlobalValue *GV, ValidationRule rule) {
-    EmitFormatError(rule, { GV->getName().str() });
+    EmitFormatError(rule, { dxilutil::DemangleFunctionName(GV->getName()) });
   }
 
   // This is the least desirable mechanism, as it has no context.

+ 2 - 1
tools/clang/lib/CodeGen/CGHLSLMS.cpp

@@ -4615,7 +4615,8 @@ void CGMSHLSLRuntime::FinishCodeGen() {
   }
 
   // Disallow resource arguments in (non-entry) function exports
-  if (m_bIsLib) {
+  // unless offline linking target.
+  if (m_bIsLib && m_pHLModule->GetShaderModel()->GetMinor() != ShaderModel::kOfflineMinor) {
     for (Function &f : m_pHLModule->GetModule()->functions()) {
       // Skip llvm intrinsics, non-external linkage, entry/patch constant func, and HL intrinsics
       if (!f.isIntrinsic() &&

+ 38 - 0
tools/clang/test/CodeGenHLSL/quick-test/lib_res_param_x.hlsl

@@ -0,0 +1,38 @@
+// RUN: %dxc -T lib_6_x  %s | FileCheck %s
+
+// resources in return/params allowed for lib_6_x
+// CHECK: alloca %struct.T
+// CHECK: store %struct.RWByteAddressBuffer
+// CHECK: call void @"\01?resStruct@@YA?AUT2@@UT@@V?$vector@I$01@@@Z"(%struct.T2
+// CHECK: %[[ptr:[^, ]]] = getelementptr inbounds %struct.T2
+// CHECK: %[[val:[^, ]]] = load %"class.RWStructuredBuffer<D>", %"class.RWStructuredBuffer<D>"* %[[ptr]]
+// CHECK: call %dx.types.Handle @"dx.op.createHandleForLib.class.RWStructuredBuffer<D>"(i32 160, %"class.RWStructuredBuffer<D>" %[[val]])
+
+
+struct T {
+RWByteAddressBuffer outputBuffer;
+RWByteAddressBuffer outputBuffer2;
+};
+
+struct D {
+  float4 a;
+  int4 b;
+};
+
+struct T2 {
+   RWStructuredBuffer<D> uav;
+};
+
+T2 resStruct(T t, uint2 id);
+
+RWByteAddressBuffer outputBuffer;
+RWByteAddressBuffer outputBuffer2;
+
+[numthreads(8, 8, 1)]
+void main( uint2 id : SV_DispatchThreadID )
+{
+    T t = {outputBuffer,outputBuffer2};
+    T2 t2 = resStruct(t, id);
+    uint counter = t2.uav.IncrementCounter();
+    t2.uav[counter].b.xy = id;
+}

+ 18 - 0
tools/clang/test/CodeGenHLSL/quick-test/lib_select_res_x.hlsl

@@ -0,0 +1,18 @@
+// RUN: %dxc -T lib_6_x -Od -Zi -auto-binding-space 11 %s | FileCheck %s
+
+// lib_6_x allows phi on resource, targeting offline linking only.
+// CHECK: phi %struct.ByteAddressBuffer
+
+RWByteAddressBuffer outputBuffer : register(u0);
+ByteAddressBuffer ReadBuffer : register(t0);
+ByteAddressBuffer ReadBuffer1 : register(t1);
+
+void test( uint cond)
+{
+	ByteAddressBuffer buffer = ReadBuffer;
+        if (cond > 2)
+           buffer = ReadBuffer1;
+
+	uint v= buffer.Load(0);
+    outputBuffer.Store(0, v);
+}

+ 18 - 0
tools/clang/test/CodeGenHLSL/quick-test/lib_select_res_x2.hlsl

@@ -0,0 +1,18 @@
+// RUN: %dxc -T lib_6_x -auto-binding-space 11 %s | FileCheck %s
+
+// lib_6_x allows select on resource, targeting offline linking only.
+// CHECK: select i1 %{{[^, ]+}}, %struct.ByteAddressBuffer
+
+RWByteAddressBuffer outputBuffer : register(u0);
+ByteAddressBuffer ReadBuffer : register(t0);
+ByteAddressBuffer ReadBuffer1 : register(t1);
+
+void test( uint cond)
+{
+	ByteAddressBuffer buffer = ReadBuffer;
+        if (cond > 2)
+           buffer = ReadBuffer1;
+
+	uint v= buffer.Load(0);
+    outputBuffer.Store(0, v);
+}

+ 34 - 0
tools/clang/test/CodeGenHLSL/quick-test/res_select2_x.hlsl

@@ -0,0 +1,34 @@
+// RUN: %dxc -T lib_6_x -auto-binding-space 11 %s | FileCheck %s
+
+// lib_6_x does not reduce phi/select of resource or handle in lib.
+// CHECK: phi %"class.RWBuffer
+// CHECK: select i1 %{{[^,]+}}, %"class.
+// CHECK: ret <4 x float>
+
+RWBuffer<float4> BufArray[2][2][3];
+
+float4 test(int i, int j, int m) {
+  RWBuffer<float4> a = BufArray[m][0][0];
+  RWBuffer<float4> b = BufArray[0][m][1];
+  RWBuffer<float4> c = BufArray[0][1][m];
+  RWBuffer<float4> bufarr[2][3] = BufArray[m];
+
+  RWBuffer<float4> buf = c;
+  while (i > 9) {
+     while (j < 4) {
+        if (i < m)
+          buf = b;
+        else
+          bufarr[i%2][j%3] = buf;
+        buf[j] = i;
+        j++;
+     }
+     if (m > j)
+       buf = a;
+     buf[m] = i;
+     i--;
+  }
+  buf[i] = j;
+  bufarr[m%2][j%3][j] = m;
+  return j;
+}

+ 50 - 0
tools/clang/test/CodeGenHLSL/quick-test/res_select3_x.hlsl

@@ -0,0 +1,50 @@
+// RUN: %dxc -T lib_6_x -auto-binding-space 11 %s | FileCheck %s
+
+// lib_6_x allows phi/select of resource in lib.
+// phi/select of handle should not be produced in this case, but would be allowed if it were.
+
+// CHECK: entry:
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: phi %"class.
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: select i1 %{{[^,]+}}, %"class.
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+
+// Make sure get dimensions returns 24
+// CHECK: ret i32 24
+
+struct MyStruct {
+  float2 a;
+  int b;
+  float3 c;
+};
+
+RWStructuredBuffer<MyStruct> BufArray[3];
+
+uint test(int i, int j, int m) {
+  RWStructuredBuffer<MyStruct> a = BufArray[0];
+  RWStructuredBuffer<MyStruct> b = BufArray[1];
+  RWStructuredBuffer<MyStruct> c = BufArray[2];
+
+  RWStructuredBuffer<MyStruct> buf = c;
+  while (i > 9) {
+     while (j < 4) {
+        if (i < m)
+          buf = b;
+        buf[j].b = i;
+        j++;
+     }
+     if (m > j)
+       buf = a;
+     buf[m].b = i;
+     i--;
+  }
+  buf[i].b = j;
+  uint dim = 0;
+  uint stride = 0;
+  buf.GetDimensions(dim, stride);
+  return stride;
+}

+ 48 - 0
tools/clang/test/CodeGenHLSL/quick-test/res_select4_x.hlsl

@@ -0,0 +1,48 @@
+// RUN: %dxc -T lib_6_x -auto-binding-space 11 %s | FileCheck %s
+
+// lib_6_x allows phi/select of resource in lib.
+// phi/select of handle should not be produced in this case, but would be allowed if it were.
+
+// CHECK: entry:
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: phi %"class.
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: select i1 %{{[^,]+}}, %"class.
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+
+// Make sure get dimensions returns 24
+// CHECK: ret i32 24
+
+struct MyStruct {
+  float2 a;
+  int b;
+  float3 c;
+};
+
+RWStructuredBuffer<MyStruct> a;
+RWStructuredBuffer<MyStruct> b;
+RWStructuredBuffer<MyStruct> c;
+
+uint test(int i, int j, int m) {
+  RWStructuredBuffer<MyStruct> buf = c;
+  while (i > 9) {
+     while (j < 4) {
+        if (i < m)
+          buf = b;
+        buf[j].b = i;
+        j++;
+     }
+     if (m > j)
+       buf = a;
+     buf[m].b = i;
+     i--;
+  }
+  buf[i].b = j;
+  uint dim = 0;
+  uint stride = 0;
+  buf.GetDimensions(dim, stride);
+  return stride;
+}

+ 44 - 0
tools/clang/test/CodeGenHLSL/quick-test/res_select5_x.hlsl

@@ -0,0 +1,44 @@
+// RUN: %dxc -T lib_6_x -auto-binding-space 11 %s | FileCheck %s
+
+// lib_6_x allows phi/select of resource in lib.
+// phi/select of handle should not be produced in this case, but would be allowed if it were.
+
+// CHECK: entry:
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: phi %"class.
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: select i1 %{{[^,]+}}, %"class.
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: ret <4 x float>
+
+RWBuffer<float4> BufArray[2][2][3];
+RWBuffer<float4> Buf2;
+
+float4 test(int i, int j, int m) {
+  RWBuffer<float4> a = BufArray[m][0][0];
+  RWBuffer<float4> b = BufArray[0][m][1];
+  RWBuffer<float4> c = BufArray[0][1][m];
+  RWBuffer<float4> bufarr[2][3] = BufArray[m];
+
+  RWBuffer<float4> buf = c;
+  while (i > 9) {
+     while (j < 4) {
+        if (i < m)
+          buf = b;
+        else
+          bufarr[i%2][j%3] = Buf2;  // Illegal: assign different global resource
+        buf[j] = i;
+        j++;
+     }
+     if (m > j)
+       buf = a;
+     buf[m] = i;
+     i--;
+  }
+  buf[i] = j;
+  bufarr[m%2][j%3][j] = m;
+  return j;
+}

+ 4 - 8
tools/clang/unittests/HLSL/LinkerTest.cpp

@@ -47,13 +47,13 @@ public:
   TEST_METHOD(RunLinkMatArrayParam);
   TEST_METHOD(RunLinkMatParam);
   TEST_METHOD(RunLinkMatParamToLib);
-  //TEST_METHOD(RunLinkResRet);
+  TEST_METHOD(RunLinkResRet);
   TEST_METHOD(RunLinkToLib);
   TEST_METHOD(RunLinkToLibExport);
   TEST_METHOD(RunLinkFailReDefineGlobal);
   TEST_METHOD(RunLinkFailProfileMismatch);
   TEST_METHOD(RunLinkFailEntryNoProps);
-  //TEST_METHOD(RunLinkFailSelectRes);
+  TEST_METHOD(RunLinkFailSelectRes);
   TEST_METHOD(RunLinkToLibWithUnresolvedFunctions);
   TEST_METHOD(RunLinkToLibWithUnresolvedFunctionsExports);
   TEST_METHOD(RunLinkToLibWithExportNamesSwapped);
@@ -85,7 +85,7 @@ public:
     CComPtr<IDxcOperationResult> pResult;
     CComPtr<IDxcBlob> pProgram;
 
-    CA2W shWide("lib_6_1", CP_UTF8);
+    CA2W shWide("lib_6_x", CP_UTF8);
     VERIFY_SUCCEEDED(
         m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
     VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"", shWide,
@@ -359,7 +359,6 @@ TEST_F(LinkerTest, RunLinkMatParamToLib) {
        {"bitcast <12 x float>* %1 to %class.matrix.float.4.3*"}, {});
 }
 
-#if 0 // unsupported for lib_6_3, but possibly future or offline-only target
 TEST_F(LinkerTest, RunLinkResRet) {
   CComPtr<IDxcBlob> pEntryLib;
   CompileLib(L"..\\CodeGenHLSL\\shader-compat-suite\\lib_out_param_res.hlsl", &pEntryLib);
@@ -377,7 +376,6 @@ TEST_F(LinkerTest, RunLinkResRet) {
 
   Link(L"test", L"ps_6_0", pLinker, {libName, libName2}, {}, {"alloca"});
 }
-#endif
 
 TEST_F(LinkerTest, RunLinkToLib) {
   LPCWSTR option[] = {L"-Zi"};
@@ -424,7 +422,6 @@ TEST_F(LinkerTest, RunLinkToLibExport) {
     {L"-exports", L"renamed_test,cloned_test=\\01?mat_test@@YA?AV?$vector@M$02@@V?$vector@M$03@@0AIAV?$matrix@M$03$02@@@Z;main"});
 }
 
-#if 0 // unsupported for lib_6_3, but possibly future or offline-only target
 TEST_F(LinkerTest, RunLinkFailSelectRes) {
   if (m_ver.SkipDxilVersion(1, 3)) return;
   CComPtr<IDxcBlob> pEntryLib;
@@ -442,9 +439,8 @@ TEST_F(LinkerTest, RunLinkFailSelectRes) {
   RegisterDxcModule(libName2, pLib, pLinker);
 
   LinkCheckMsg(L"main", L"ps_6_0", pLinker, {libName, libName2},
-               {"Local resource must map to global resource"});
+               {"local resource not guaranteed to map to unique global resource"});
 }
-#endif
 
 TEST_F(LinkerTest, RunLinkToLibWithUnresolvedFunctions) {
   LPCWSTR option[] = { L"-Zi" };