2
0
Эх сурвалжийг харах

Merged PR 107: Add lib_6_x for offline linking only and -export-shaders-only

Add lib_6_x for offline linking only and -export-shaders-only

- Add lib_6_x target for offline linking use only
- Implement -export-shaders-only to limit function exports to shaders on lib targets
- Fix disable validation case downgrading Dxil as if valver is 1.0
Tex Riddell 7 жил өмнө
parent
commit
156c45dd42

+ 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();

+ 1 - 0
include/dxc/Support/HLSLOptions.h

@@ -156,6 +156,7 @@ public:
   bool DisaseembleHex = false; //OPT_Lx
   bool LegacyMacroExpansion = false; // OPT_flegacy_macro_expansion
   unsigned long AutoBindingSpace = UINT_MAX; // OPT_auto_binding_space
+  bool ExportShadersOnly = false; // OPT_export_shaders_only
 
   bool IsRootSignatureProfile();
   bool IsLibraryProfile();

+ 7 - 3
include/dxc/Support/HLSLOptions.td

@@ -232,8 +232,12 @@ def rootsig_define : Separate<["-", "/"], "rootsig-define">, Group<hlslcomp_Grou
 def enable_16bit_types: Flag<["-", "/"], "enable-16bit-types">, Flags<[CoreOption, DriverOption]>, Group<hlslcomp_Group>,
   HelpText<"Enable 16bit types and disable min precision types. Available in HLSL 2018 and shader model 6.2">;
 def ignore_line_directives : Flag<["-", "/"], "ignore-line-directives">, HelpText<"Ignore line directives">, Flags<[CoreOption]>, Group<hlslcomp_Group>;
-def auto_binding_space : Separate<["-", "/"], "auto-binding-space">, Group<hlslcomp_Group>, Flags<[CoreOption]>, HelpText<"Set auto binding space - enables auto resource binding in libraries">;
-def exports : Separate<["-", "/"], "exports">, Group<hlslcomp_Group>, Flags<[CoreOption]>, HelpText<"Specify exports when compiling a library: export1[[,export1_clone,...]=internal_name][;...]">;
+def auto_binding_space : Separate<["-", "/"], "auto-binding-space">, Group<hlslcomp_Group>, Flags<[CoreOption]>,
+  HelpText<"Set auto binding space - enables auto resource binding in libraries">;
+def exports : Separate<["-", "/"], "exports">, Group<hlslcomp_Group>, Flags<[CoreOption]>,
+  HelpText<"Specify exports when compiling a library: export1[[,export1_clone,...]=internal_name][;...]">;
+def export_shaders_only : Flag<["-", "/"], "export-shaders-only">, Group<hlslcomp_Group>, Flags<[CoreOption]>,
+  HelpText<"Only export shaders when compiling a library">;
 
 // SPIRV Change Starts
 def spirv : Flag<["-"], "spirv">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
@@ -268,7 +272,7 @@ def Wno_vk_ignored_features : Joined<["-"], "Wno-vk-ignored-features">, Group<sp
 // fxc-based flags that don't match those previously defined.
 
 def target_profile : JoinedOrSeparate<["-", "/"], "T">, Flags<[CoreOption]>, Group<hlslcomp_Group>, MetaVarName<"<profile>">,
-  HelpText<"Set target profile. \n\t<profile>: ps_6_0, ps_6_1, ps_6_2, vs_6_0, vs_6_1, vs_6_2, \n\t\t cs_6_0, cs_6_1, cs_6_2, gs_6_0, gs_6_1, gs_6_2, \n\t\t ds_6_0, ds_6_1, ds_6_2, hs_6_0, hs_6_1, hs_6_2, \n\t\t lib_6_0, lib_6_1, lib_6_2">;
+  HelpText<"Set target profile. \n\t<profile>: ps_6_0, ps_6_1, ps_6_2, ps_6_3, \n\t\t vs_6_0, vs_6_1, vs_6_2, vs_6_3, \n\t\t cs_6_0, cs_6_1, cs_6_2, cs_6_3, \n\t\t gs_6_0, gs_6_1, gs_6_2, gs_6_3, \n\t\t ds_6_0, ds_6_1, ds_6_2, ds_6_3, \n\t\t hs_6_0, hs_6_1, hs_6_2, hs_6_3, \n\t\t lib_6_3">;
 def entrypoint :  JoinedOrSeparate<["-", "/"], "E">, Flags<[CoreOption]>, Group<hlslcomp_Group>,
   HelpText<"Entry point name">;
 // /I <include> - already defined above

+ 39 - 13
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,9 +278,14 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
       // Set entry point to impossible name.
       opts.EntryPoint = "lib.no::entry";
     }
-  } else if (Args.getLastArg(OPT_exports)) {
-    errors << "library profile required when using -exports option";
-    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, OPT_INVALID, false)) {
+      errors << "library profile required when using -export-shaders-only option";
+      return 1;
+    }
   }
 
   llvm::StringRef ver = Args.getLastArgValue(OPT_hlsl_version);
@@ -360,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)) {
@@ -423,6 +443,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   opts.DisassembleByteOffset = Args.hasFlag(OPT_No, OPT_INVALID, false);
   opts.DisaseembleHex = Args.hasFlag(OPT_Lx, OPT_INVALID, false);
   opts.LegacyMacroExpansion = Args.hasFlag(OPT_flegacy_macro_expansion, OPT_INVALID, false);
+  opts.ExportShadersOnly = Args.hasFlag(OPT_export_shaders_only, OPT_INVALID, false);
 
   if (opts.DefaultColMajor && opts.DefaultRowMajor) {
     errors << "Cannot specify /Zpr and /Zpc together, use /? to get usage information";
@@ -495,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];

+ 1 - 1
lib/HLSL/DxilPreparePasses.cpp

@@ -525,7 +525,7 @@ void DxilEmitMetadata::patchIsFrontfaceTy(Module &M) {
     return;
   unsigned ValMajor, ValMinor;
   DM.GetValidatorVersion(ValMajor, ValMinor);
-  bool bForceUint = ValMajor >= 1 && ValMinor >= 2;
+  bool bForceUint = ValMajor == 0 || (ValMajor >= 1 && ValMinor >= 2);
   if (pSM->IsPS()) {
     patchIsFrontface(DM.GetInputSignature(), bForceUint);
   } else if (pSM->IsGS()) {

+ 1 - 1
lib/HLSL/DxilShaderFlags.cpp

@@ -224,7 +224,7 @@ ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F,
   // Try to maintain compatibility with a v1.0 validator if that's what we have.
   uint32_t valMajor, valMinor;
   M->GetValidatorVersion(valMajor, valMinor);
-  bool hasMulticomponentUAVLoadsBackCompat = valMajor <= 1 && valMinor == 0;
+  bool hasMulticomponentUAVLoadsBackCompat = valMajor == 1 && valMinor == 0;
 
   Type *int16Ty = Type::getInt16Ty(F->getContext());
   Type *int64Ty = Type::getInt64Ty(F->getContext());

+ 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

@@ -585,7 +585,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 - 0
tools/clang/include/clang/Frontend/CodeGenOptions.h

@@ -204,6 +204,8 @@ public:
   unsigned HLSLDefaultSpace = UINT_MAX;
   /// HLSLLibraryExports specifies desired exports, with optional renaming
   std::vector<std::string> HLSLLibraryExports;
+  /// ExportShadersOnly limits library export functions to shaders
+  bool ExportShadersOnly = false;
   // HLSL Change Ends
   /// Regular expression to select optimizations for which we should enable
   /// optimization remarks. Transformation passes whose name matches this

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

@@ -4600,8 +4600,23 @@ void CGMSHLSLRuntime::FinishCodeGen() {
     }
   }
 
+  if (CGM.getCodeGenOpts().ExportShadersOnly) {
+    for (Function &f : m_pHLModule->GetModule()->functions()) {
+      // Skip declarations, intrinsics, shaders, and non-external linkage
+      if (f.isDeclaration() || f.isIntrinsic() ||
+          GetHLOpcodeGroup(&f) != HLOpcodeGroup::NotHL ||
+          m_pHLModule->HasDxilFunctionProps(&f) ||
+          m_pHLModule->IsPatchConstantShader(&f) ||
+          f.getLinkage() != GlobalValue::LinkageTypes::ExternalLinkage)
+        continue;
+      // Mark non-shader user functions as InternalLinkage
+      f.setLinkage(GlobalValue::LinkageTypes::InternalLinkage);
+    }
+  }
+
   // 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() &&

+ 110 - 0
tools/clang/test/CodeGenHLSL/quick-test/lib_hs_shaders_only.hlsl

@@ -0,0 +1,110 @@
+// RUN: %dxc -auto-binding-space 13 -T lib_6_3 -export-shaders-only %s | FileCheck %s
+
+// CHECK: class.Buffer
+// CHECK-NOT: unused
+// CHECK-NOT: @"\01?HSPerPatchFunc1@@YA?AUHSPerPatchData@@V?$InputPatch@UPSSceneIn@@$0BA@@@@Z"
+// CHECK: define void @"\01?HSPerPatchFunc2
+// CHECK: define void @HSMain1()
+// CHECK: define void @HSMain2()
+// CHECK: define void @HSMain3()
+// CHECK: define void @"\01?HSPerPatchFunc1@@YA?AUHSPerPatchData@@XZ"
+
+Buffer<float> T_unused;
+
+Buffer<float> GetBuffer_unused() { return T_unused; }
+
+struct PSSceneIn
+{
+  float4 pos  : SV_Position;
+  float2 tex  : TEXCOORD0;
+  float3 norm : NORMAL;
+};
+
+struct HSPerPatchData
+{
+  float edges[3] : SV_TessFactor;
+  float inside   : SV_InsideTessFactor;
+};
+
+struct HSPerPatchDataQuad
+{
+  float edges[4] : SV_TessFactor;
+  float inside[2]   : SV_InsideTessFactor;
+};
+
+// Should not be selected, since later candidate function with same name exists.
+// If selected, it should fail, since patch size mismatches HS function.
+HSPerPatchData HSPerPatchFunc1(
+  const InputPatch< PSSceneIn, 16 > points)
+{
+  HSPerPatchData d;
+
+  d.edges[0] = -5;
+  d.edges[1] = -6;
+  d.edges[2] = -7;
+  d.inside = T_unused.Load(1).x;
+
+  return d;
+}
+
+HSPerPatchDataQuad HSPerPatchFunc2(
+  const InputPatch< PSSceneIn, 4 > points)
+{
+  HSPerPatchDataQuad d;
+
+  d.edges[0] = -5;
+  d.edges[1] = -6;
+  d.edges[2] = -7;
+  d.edges[3] = -7;
+  d.inside[0] = -8;
+  d.inside[1] = -8;
+
+  return d;
+}
+
+
+[shader("hull")]
+[domain("tri")]
+[partitioning("fractional_odd")]
+[outputtopology("triangle_cw")]
+[patchconstantfunc("HSPerPatchFunc1")]
+[outputcontrolpoints(3)]
+void HSMain1( const uint id : SV_OutputControlPointID,
+              const InputPatch< PSSceneIn, 3 > points )
+{
+}
+
+[shader("hull")]
+[domain("quad")]
+[partitioning("fractional_odd")]
+[outputtopology("triangle_cw")]
+[patchconstantfunc("HSPerPatchFunc2")]
+[outputcontrolpoints(4)]
+void HSMain2( const uint id : SV_OutputControlPointID,
+              const InputPatch< PSSceneIn, 4 > points )
+{
+}
+
+[shader("hull")]
+[domain("tri")]
+[partitioning("fractional_odd")]
+[outputtopology("triangle_ccw")]
+[patchconstantfunc("HSPerPatchFunc1")]
+[outputcontrolpoints(3)]
+void HSMain3( const uint id : SV_OutputControlPointID,
+              const InputPatch< PSSceneIn, 3 > points )
+{
+}
+
+// actual selected HSPerPatchFunc1 for HSMain1 and HSMain3
+HSPerPatchData HSPerPatchFunc1()
+{
+  HSPerPatchData d;
+
+  d.edges[0] = -5;
+  d.edges[1] = -6;
+  d.edges[2] = -7;
+  d.inside = -8;
+
+  return d;
+}

+ 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);
+}

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

@@ -0,0 +1,38 @@
+// RUN: %dxc -auto-binding-space 13 -T lib_6_3 -export-shaders-only %s | FileCheck %s
+
+// CHECK: %struct.Payload
+// CHECK: class.Buffer
+// CHECK-NOT: unused
+// CHECK: define void @"\01?AnyHit
+// CHECK: define void @"\01?Callable
+// CHECK: define void @PSMain()
+
+Buffer<float> T_unused;
+
+Buffer<float> GetBuffer_unused() { return T_unused; }
+float unused_nonshader_export() { return 1.0; }
+float unused_nonshader_export2() { return unused_nonshader_export(); }
+
+
+struct Payload {
+  float f;
+};
+
+[shader("anyhit")]
+void AnyHit(inout Payload p, BuiltInTriangleIntersectionAttributes a) {
+  p.f += a.barycentrics.x;
+  if (p.f > 1.0)
+    AcceptHitAndEndSearch();
+  p.f += a.barycentrics.y;
+}
+
+[shader("callable")]
+void Callable(inout Payload p) {
+  p.f += 0.2;
+}
+
+[shader("pixel")]
+float4 PSMain(float2 coord : TEXCOORD) : SV_Target {
+  return coord.xyxy;
+}
+

+ 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;
+}

+ 3 - 0
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -900,6 +900,9 @@ public:
 
     // processed export names from -exports option:
     compiler.getCodeGenOpts().HLSLLibraryExports = Opts.Exports;
+
+    // only export shader functions for library
+    compiler.getCodeGenOpts().ExportShadersOnly = Opts.ExportShadersOnly;
   }
 
   // IDxcVersionInfo

+ 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" };