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

Write and test example library for accessing TempRegLoad/TempRegStore (#2951)

Tex Riddell 5 жил өмнө
parent
commit
760e1cf8f1

+ 18 - 0
tools/clang/test/HLSLFileCheck/dxil/linker/TempReg.hlslh

@@ -0,0 +1,18 @@
+// Prototypes for wrappers to TempRegLoad/TempRegStore,
+// overloaded for uint, int, and float
+// link to TempReg.dxl (assembled from TempReg.ll)
+
+#ifndef TEMPREG_H
+#define TEMPREG_H
+
+// Store values
+void sreg(uint n, uint val);
+void sreg(uint n, int val);
+void sreg(uint n, float val);
+
+// Load values
+uint ureg(uint n);
+int ireg(uint n);
+float freg(uint n);
+
+#endif // TEMPREG_H

+ 126 - 0
tools/clang/test/HLSLFileCheck/dxil/linker/TempReg.ll

@@ -0,0 +1,126 @@
+; RUN: %opt %s -dce -S | FileCheck %s
+; Just run a pass that shouldn't do anything in order to pass through assembler
+
+; dxa TempReg.ll -o TempReg.dxl
+
+; CHECK: define void
+; CHECK-SAME: sreg
+; CHECK-SAME: i32 %n
+; CHECK-SAME: i32 %val
+; CHECK: call void @dx.op.tempRegStore.i32
+
+; CHECK: define void
+; CHECK-SAME: sreg
+; CHECK-SAME: i32 %n
+; CHECK-SAME: i32 %val
+; CHECK: call void @dx.op.tempRegStore.i32
+
+; CHECK: define void
+; CHECK-SAME: sreg
+; CHECK-SAME: i32 %n
+; CHECK-SAME: float %val
+; CHECK: call void @dx.op.tempRegStore.f32
+
+; CHECK: define i32
+; CHECK-SAME: ureg
+; CHECK-SAME: i32 %n
+; CHECK: call i32 @dx.op.tempRegLoad.i32
+
+; CHECK: define i32
+; CHECK-SAME: ireg
+; CHECK-SAME: i32 %n
+; CHECK: call i32 @dx.op.tempRegLoad.i32
+
+; CHECK: define float
+; CHECK-SAME: freg
+; CHECK-SAME: i32 %n
+; CHECK: call float @dx.op.tempRegLoad.f32
+
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
+target triple = "dxil-ms-dx"
+
+; Function Attrs: alwaysinline nounwind
+define void @"\01?sreg@@YAXII@Z"(i32 %n, i32 %val) #0 {
+  call void @dx.op.tempRegStore.i32(i32 1, i32 %n, i32 %val)  ; TempRegStore(index,value)
+  ret void
+}
+
+; Function Attrs: alwaysinline nounwind
+define void @"\01?sreg@@YAXIH@Z"(i32 %n, i32 %val) #0 {
+  call void @dx.op.tempRegStore.i32(i32 1, i32 %n, i32 %val)  ; TempRegStore(index,value)
+  ret void
+}
+
+; Function Attrs: alwaysinline nounwind
+define void @"\01?sreg@@YAXIM@Z"(i32 %n, float %val) #0 {
+  call void @dx.op.tempRegStore.f32(i32 1, i32 %n, float %val)  ; TempRegStore(index,value)
+  ret void
+}
+
+; Function Attrs: alwaysinline nounwind readonly
+define i32 @"\01?ureg@@YAII@Z"(i32 %n) #1 {
+  %r = call i32 @dx.op.tempRegLoad.i32(i32 0, i32 %n)  ; TempRegLoad(index)
+  ret i32 %r
+}
+
+; Function Attrs: alwaysinline nounwind readonly
+define i32 @"\01?ireg@@YAHI@Z"(i32 %n) #1 {
+  %r = call i32 @dx.op.tempRegLoad.i32(i32 0, i32 %n)  ; TempRegLoad(index)
+  ret i32 %r
+}
+
+; Function Attrs: alwaysinline nounwind readonly
+define float @"\01?freg@@YAMI@Z"(i32 %n) #1 {
+  %r = call float @dx.op.tempRegLoad.f32(i32 0, i32 %n)  ; TempRegLoad(index)
+  ret float %r
+}
+
+; Function Attrs: nounwind
+declare void @dx.op.tempRegStore.i32(i32, i32, i32) #2
+
+; Function Attrs: nounwind
+declare void @dx.op.tempRegStore.f32(i32, i32, float) #2
+
+; Function Attrs: nounwind readonly
+declare i32 @dx.op.tempRegLoad.i32(i32, i32) #3
+
+; Function Attrs: nounwind readonly
+declare float @dx.op.tempRegLoad.f32(i32, i32) #3
+
+attributes #0 = { alwaysinline nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="0" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { alwaysinline nounwind readonly "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="0" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind }
+attributes #3 = { nounwind readonly }
+
+!llvm.ident = !{!0}
+!dx.version = !{!1}
+!dx.valver = !{!2}
+!dx.shaderModel = !{!3}
+!dx.resources = !{!4}
+!dx.typeAnnotations = !{!5}
+!dx.entryPoints = !{!23}
+
+!0 = !{!"clang version 3.7 (tags/RELEASE_370/final)"}
+!1 = !{i32 1, i32 6}
+!2 = !{i32 0, i32 0}
+!3 = !{!"lib", i32 6, i32 3}
+!4 = !{null, null, null, null}
+!5 = !{i32 1, void (i32, i32)* @"\01?sreg@@YAXII@Z", !6, void (i32, i32)* @"\01?sreg@@YAXIH@Z", !11, void (i32, float)* @"\01?sreg@@YAXIM@Z", !14, i32 (i32)* @"\01?ureg@@YAII@Z", !17, i32 (i32)* @"\01?ireg@@YAHI@Z", !19, float (i32)* @"\01?freg@@YAMI@Z", !21}
+!6 = !{!7, !9, !9}
+!7 = !{i32 1, !8, !8}
+!8 = !{}
+!9 = !{i32 0, !10, !8}
+!10 = !{i32 7, i32 5}
+!11 = !{!7, !9, !12}
+!12 = !{i32 0, !13, !8}
+!13 = !{i32 7, i32 4}
+!14 = !{!7, !9, !15}
+!15 = !{i32 0, !16, !8}
+!16 = !{i32 7, i32 9}
+!17 = !{!18, !9}
+!18 = !{i32 1, !10, !8}
+!19 = !{!20, !9}
+!20 = !{i32 1, !13, !8}
+!21 = !{!22, !9}
+!22 = !{i32 1, !16, !8}
+!23 = !{null, !"", null, !4, null}

+ 21 - 0
tools/clang/test/HLSLFileCheck/dxil/linker/use-TempReg.hlsl

@@ -0,0 +1,21 @@
+// RUN: %dxc -T lib_6_3 %s | FileCheck %s
+
+// CHECK: define void @main()
+// CHECK: call i32 @dx.op.loadInput.i32
+// CHECK: call void
+// CHECK-SAME: sreg
+// CHECK: call i32
+// CHECK-SAME: ureg
+// CHECK: call void @dx.op.storeOutput.i32
+
+// dxc -T lib_6_3 -Fo use-TempReg.dxl
+// dxl -E=main -T vs_6_0 -Fo shader.dxo TempReg.dxl;use-TempReg.dxl
+
+#include "TempReg.hlslh"
+
+[shader("vertex")]
+uint main(uint In : IN) : OUT {
+  sreg(0, In);
+  return ureg(0);
+}
+

+ 50 - 3
tools/clang/unittests/HLSL/LinkerTest.cpp

@@ -62,6 +62,7 @@ public:
   TEST_METHOD(RunLinkToLibWithNoExports);
   TEST_METHOD(RunLinkWithPotentialIntrinsicNameCollisions);
   TEST_METHOD(RunLinkWithValidatorVersion);
+  TEST_METHOD(RunLinkWithTempReg);
 
 
   dxc::DxcDllSupport m_dllSupport;
@@ -83,17 +84,33 @@ public:
     VERIFY_SUCCEEDED(
         pLibrary->CreateBlobFromFile(fullPath.c_str(), nullptr, &pSource));
 
+    CComPtr<IDxcIncludeHandler> pIncludeHandler;
+    VERIFY_SUCCEEDED(pLibrary->CreateIncludeHandler(&pIncludeHandler));
+
     CComPtr<IDxcCompiler> pCompiler;
     CComPtr<IDxcOperationResult> pResult;
     CComPtr<IDxcBlob> pProgram;
 
     VERIFY_SUCCEEDED(
         m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
-    VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"", pShaderTarget,
+    VERIFY_SUCCEEDED(pCompiler->Compile(pSource, fullPath.c_str(), L"", pShaderTarget,
                                         const_cast<LPCWSTR*>(pArguments.data()), pArguments.size(),
                                         nullptr, 0,
-                                        nullptr, &pResult));
-    VERIFY_SUCCEEDED(pResult->GetResult(pResultBlob));
+                                        pIncludeHandler, &pResult));
+    CheckOperationSucceeded(pResult, pResultBlob);
+  }
+
+  void AssembleLib(LPCWSTR filename, IDxcBlob **pResultBlob) {
+    std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(filename);
+    CComPtr<IDxcLibrary> pLibrary;
+    VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
+    CComPtr<IDxcBlobEncoding> pSource;
+    VERIFY_SUCCEEDED(pLibrary->CreateBlobFromFile(fullPath.c_str(), nullptr, &pSource));
+    CComPtr<IDxcAssembler> pAssembler;
+    VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
+    CComPtr<IDxcOperationResult> pResult;
+    VERIFY_SUCCEEDED(pAssembler->AssembleToContainer(pSource, &pResult));
+    CheckOperationSucceeded(pResult, pResultBlob);
   }
 
   void RegisterDxcModule(LPCWSTR pLibName, IDxcBlob *pBlob,
@@ -662,3 +679,33 @@ TEST_F(LinkerTest, RunLinkWithValidatorVersion) {
        {"!dx.valver = !{(![0-9]+)}.*\n\\1 = !{i32 1, i32 3}"},
        {}, {L"-validator-version", L"1.3"}, /*regex*/ true);
 }
+
+TEST_F(LinkerTest, RunLinkWithTempReg) {
+  // TempRegLoad/TempRegStore not normally usable from HLSL.
+  // This assembly library exposes these through overloaded wrapper functions
+  // void sreg(uint index, <type> value) to store register, overloaded for uint, int, and float
+  // uint ureg(uint index) to load register as uint
+  // int ireg(int index) to load register as int
+  // float freg(uint index) to load register as float
+
+  // This test verifies this scenario works, by assembling this library,
+  // compiling a library with an entry point that uses sreg/ureg,
+  // then linking these to a final standard vs_6_0 DXIL shader.
+
+  CComPtr<IDxcBlob> pTempRegLib;
+  AssembleLib(L"..\\HLSLFileCheck\\dxil\\linker\\TempReg.ll", &pTempRegLib);
+  CComPtr<IDxcBlob> pEntryLib;
+  CompileLib(L"..\\HLSLFileCheck\\dxil\\linker\\use-TempReg.hlsl", &pEntryLib, {}, L"lib_6_3");
+  CComPtr<IDxcLinker> pLinker;
+  CreateLinker(&pLinker);
+  LPCWSTR libName = L"entry";
+  RegisterDxcModule(libName, pEntryLib, pLinker);
+
+  LPCWSTR libResName = L"TempReg";
+  RegisterDxcModule(libResName, pTempRegLib, pLinker);
+
+  Link(L"main", L"vs_6_0", pLinker, {libResName, libName}, {
+    "call void @dx.op.tempRegStore.i32",
+    "call i32 @dx.op.tempRegLoad.i32"
+    } ,{});
+}