1 //===- DXILResourceTest.cpp - Unit tests for DXILResource -----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Analysis/DXILResource.h" 10 #include "llvm/IR/Constants.h" 11 #include "gtest/gtest.h" 12 13 using namespace llvm; 14 using namespace dxil; 15 16 namespace { 17 // Helper to succinctly build resource shaped metadata for tests. 18 struct MDBuilder { 19 LLVMContext &Context; 20 Type *Int32Ty; 21 Type *Int1Ty; 22 23 MDBuilder(LLVMContext &Context, Type *Int32Ty, Type *Int1Ty) 24 : Context(Context), Int32Ty(Int32Ty), Int1Ty(Int1Ty) {} 25 26 template <typename... Ts> 27 void appendMDs(SmallVectorImpl<Metadata *> &MDs, int V, Ts... More) { 28 MDs.push_back(ConstantAsMetadata::get( 29 Constant::getIntegerValue(Int32Ty, APInt(32, V)))); 30 appendMDs(MDs, More...); 31 } 32 template <typename... Ts> 33 void appendMDs(SmallVectorImpl<Metadata *> &MDs, unsigned int V, Ts... More) { 34 MDs.push_back(ConstantAsMetadata::get( 35 Constant::getIntegerValue(Int32Ty, APInt(32, V)))); 36 appendMDs(MDs, More...); 37 } 38 template <typename... Ts> 39 void appendMDs(SmallVectorImpl<Metadata *> &MDs, bool V, Ts... More) { 40 MDs.push_back(ConstantAsMetadata::get( 41 Constant::getIntegerValue(Int1Ty, APInt(1, V)))); 42 appendMDs(MDs, More...); 43 } 44 template <typename... Ts> 45 void appendMDs(SmallVectorImpl<Metadata *> &MDs, Value *V, Ts... More) { 46 MDs.push_back(ValueAsMetadata::get(V)); 47 appendMDs(MDs, More...); 48 } 49 template <typename... Ts> 50 void appendMDs(SmallVectorImpl<Metadata *> &MDs, const char *V, Ts... More) { 51 MDs.push_back(MDString::get(Context, V)); 52 appendMDs(MDs, More...); 53 } 54 template <typename... Ts> 55 void appendMDs(SmallVectorImpl<Metadata *> &MDs, StringRef V, Ts... More) { 56 MDs.push_back(MDString::get(Context, V)); 57 appendMDs(MDs, More...); 58 } 59 template <typename... Ts> 60 void appendMDs(SmallVectorImpl<Metadata *> &MDs, std::nullptr_t V, 61 Ts... More) { 62 MDs.push_back(nullptr); 63 appendMDs(MDs, More...); 64 } 65 template <typename... Ts> 66 void appendMDs(SmallVectorImpl<Metadata *> &MDs, MDTuple *V, Ts... More) { 67 MDs.push_back(V); 68 appendMDs(MDs, More...); 69 } 70 void appendMDs(SmallVectorImpl<Metadata *> &MDs) { 71 // Base case, nothing to do. 72 } 73 74 template <typename... Ts> MDTuple *get(Ts... Data) { 75 SmallVector<Metadata *> MDs; 76 appendMDs(MDs, Data...); 77 return MDNode::get(Context, MDs); 78 } 79 }; 80 81 testing::AssertionResult MDTupleEq(const char *LHSExpr, const char *RHSExpr, 82 MDTuple *LHS, MDTuple *RHS) { 83 if (LHS == RHS) 84 return testing::AssertionSuccess(); 85 std::string LHSRepr, RHSRepr; 86 raw_string_ostream LHSS(LHSRepr), RHSS(RHSRepr); 87 LHS->printTree(LHSS); 88 RHS->printTree(RHSS); 89 90 return testing::AssertionFailure() << "Expected equality:\n" 91 << " " << LHSExpr << "\n" 92 << "Which is:\n" 93 << " " << LHSS.str() << "\n\n" 94 << " " << RHSExpr << "\n" 95 << "Which is:\n" 96 << " " << RHSS.str(); 97 } 98 #define EXPECT_MDEQ(X, Y) EXPECT_PRED_FORMAT2(MDTupleEq, X, Y) 99 } // namespace 100 101 TEST(DXILResource, AnnotationsAndMetadata) { 102 LLVMContext Context; 103 Type *Int1Ty = Type::getInt1Ty(Context); 104 Type *Int32Ty = Type::getInt32Ty(Context); 105 Type *FloatTy = Type::getFloatTy(Context); 106 Type *DoubleTy = Type::getDoubleTy(Context); 107 Type *Floatx4Ty = FixedVectorType::get(FloatTy, 4); 108 Type *Floatx3Ty = FixedVectorType::get(FloatTy, 3); 109 Type *Int32x2Ty = FixedVectorType::get(Int32Ty, 2); 110 111 MDBuilder TestMD(Context, Int32Ty, Int1Ty); 112 113 // ByteAddressBuffer Buffer0; 114 Value *Symbol = UndefValue::get( 115 StructType::create(Context, {Int32Ty}, "struct.ByteAddressBuffer")); 116 ResourceInfo Resource = 117 ResourceInfo::RawBuffer(Symbol, "Buffer0", ResourceBinding{0, 0, 1}, 118 /*UniqueID=*/0); 119 std::pair<uint32_t, uint32_t> Props = Resource.getAnnotateProps(); 120 EXPECT_EQ(Props.first, 0x0000000bU); 121 EXPECT_EQ(Props.second, 0U); 122 MDTuple *MD = Resource.getAsMetadata(Context); 123 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "Buffer0", 0, 0, 1, 11, 0, nullptr)); 124 125 // RWByteAddressBuffer BufferOut : register(u3, space2); 126 Symbol = UndefValue::get( 127 StructType::create(Context, {Int32Ty}, "struct.RWByteAddressBuffer")); 128 Resource = ResourceInfo::RWRawBuffer( 129 Symbol, "BufferOut", ResourceBinding{2, 3, 1}, /*UniqueID=*/1, 130 /*GloballyCoherent=*/false, /*IsROV=*/false); 131 Props = Resource.getAnnotateProps(); 132 EXPECT_EQ(Props.first, 0x0000100bU); 133 EXPECT_EQ(Props.second, 0U); 134 MD = Resource.getAsMetadata(Context); 135 EXPECT_MDEQ(MD, TestMD.get(1, Symbol, "BufferOut", 2, 3, 1, 11, false, false, 136 false, nullptr)); 137 138 // struct BufType0 { int i; float f; double d; }; 139 // StructuredBuffer<BufType0> Buffer0 : register(t0); 140 StructType *BufType0 = 141 StructType::create(Context, {Int32Ty, FloatTy, DoubleTy}, "BufType0"); 142 Symbol = UndefValue::get(StructType::create( 143 Context, {BufType0}, "class.StructuredBuffer<BufType>")); 144 Resource = ResourceInfo::StructuredBuffer( 145 Symbol, "Buffer0", ResourceBinding{0, 0, 1}, /*UniqueID=*/0, 146 /*Stride=*/16, Align(8)); 147 Props = Resource.getAnnotateProps(); 148 EXPECT_EQ(Props.first, 0x0000030cU); 149 EXPECT_EQ(Props.second, 0x00000010U); 150 MD = Resource.getAsMetadata(Context); 151 EXPECT_MDEQ( 152 MD, TestMD.get(0, Symbol, "Buffer0", 0, 0, 1, 12, 0, TestMD.get(1, 16))); 153 154 // Texture2D<float4> ColorMapTexture : register(t2); 155 Symbol = UndefValue::get(StructType::create( 156 Context, {Floatx4Ty}, "class.Texture2D<vector<float, 4> >")); 157 Resource = 158 ResourceInfo::SRV(Symbol, "ColorMapTexture", ResourceBinding{0, 2, 1}, 159 /*UniqueID=*/2, dxil::ElementType::F32, 160 /*ElementCount=*/4, dxil::ResourceKind::Texture2D); 161 Props = Resource.getAnnotateProps(); 162 EXPECT_EQ(Props.first, 0x00000002U); 163 EXPECT_EQ(Props.second, 0x00000409U); 164 MD = Resource.getAsMetadata(Context); 165 EXPECT_MDEQ(MD, TestMD.get(2, Symbol, "ColorMapTexture", 0, 2, 1, 2, 0, 166 TestMD.get(0, 9))); 167 168 // Texture2DMS<float, 8> DepthBuffer : register(t0); 169 Symbol = UndefValue::get( 170 StructType::create(Context, {FloatTy}, "class.Texture2DMS<float, 8>")); 171 Resource = 172 ResourceInfo::Texture2DMS(Symbol, "DepthBuffer", ResourceBinding{0, 0, 1}, 173 /*UniqueID=*/0, dxil::ElementType::F32, 174 /*ElementCount=*/1, /*SampleCount=*/8); 175 Props = Resource.getAnnotateProps(); 176 EXPECT_EQ(Props.first, 0x00000003U); 177 EXPECT_EQ(Props.second, 0x00080109U); 178 MD = Resource.getAsMetadata(Context); 179 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "DepthBuffer", 0, 0, 1, 3, 8, 180 TestMD.get(0, 9))); 181 182 // FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> feedbackMinMip; 183 Symbol = UndefValue::get( 184 StructType::create(Context, {Int32Ty}, "class.FeedbackTexture2D<0>")); 185 Resource = ResourceInfo::FeedbackTexture2D( 186 Symbol, "feedbackMinMip", ResourceBinding{0, 0, 1}, 187 /*UniqueID=*/0, SamplerFeedbackType::MinMip); 188 Props = Resource.getAnnotateProps(); 189 EXPECT_EQ(Props.first, 0x00001011U); 190 EXPECT_EQ(Props.second, 0U); 191 MD = Resource.getAsMetadata(Context); 192 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "feedbackMinMip", 0, 0, 1, 17, false, 193 false, false, TestMD.get(2, 0))); 194 195 // FeedbackTexture2DArray<SAMPLER_FEEDBACK_MIP_REGION_USED> feedbackMipRegion; 196 Symbol = UndefValue::get(StructType::create( 197 Context, {Int32Ty}, "class.FeedbackTexture2DArray<1>")); 198 Resource = ResourceInfo::FeedbackTexture2DArray( 199 Symbol, "feedbackMipRegion", ResourceBinding{0, 0, 1}, 200 /*UniqueID=*/0, SamplerFeedbackType::MipRegionUsed); 201 Props = Resource.getAnnotateProps(); 202 EXPECT_EQ(Props.first, 0x00001012U); 203 EXPECT_EQ(Props.second, 0x00000001U); 204 MD = Resource.getAsMetadata(Context); 205 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "feedbackMipRegion", 0, 0, 1, 18, false, 206 false, false, TestMD.get(2, 1))); 207 208 // globallycoherent RWTexture2D<int2> OutputTexture : register(u0, space2); 209 Symbol = UndefValue::get(StructType::create( 210 Context, {Int32x2Ty}, "class.RWTexture2D<vector<int, 2> >")); 211 Resource = 212 ResourceInfo::UAV(Symbol, "OutputTexture", ResourceBinding{2, 0, 1}, 213 /*UniqueID=*/0, dxil::ElementType::I32, 214 /*ElementCount=*/2, /*GloballyCoherent=*/1, /*IsROV=*/0, 215 dxil::ResourceKind::Texture2D); 216 Props = Resource.getAnnotateProps(); 217 EXPECT_EQ(Props.first, 0x00005002U); 218 EXPECT_EQ(Props.second, 0x00000204U); 219 MD = Resource.getAsMetadata(Context); 220 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "OutputTexture", 2, 0, 1, 2, true, 221 false, false, TestMD.get(0, 4))); 222 223 // RasterizerOrderedBuffer<float4> ROB; 224 Symbol = UndefValue::get( 225 StructType::create(Context, {Floatx4Ty}, 226 "class.RasterizerOrderedBuffer<vector<float, 4> >")); 227 Resource = ResourceInfo::UAV(Symbol, "ROB", ResourceBinding{0, 0, 1}, 228 /*UniqueID=*/0, dxil::ElementType::F32, 229 /*ElementCount=*/4, /*GloballyCoherent=*/0, 230 /*IsROV=*/1, dxil::ResourceKind::TypedBuffer); 231 Props = Resource.getAnnotateProps(); 232 EXPECT_EQ(Props.first, 0x0000300aU); 233 EXPECT_EQ(Props.second, 0x00000409U); 234 MD = Resource.getAsMetadata(Context); 235 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "ROB", 0, 0, 1, 10, false, false, true, 236 TestMD.get(0, 9))); 237 238 // RWStructuredBuffer<ParticleMotion> g_OutputBuffer : register(u2); 239 StructType *BufType1 = StructType::create( 240 Context, {Floatx3Ty, FloatTy, Int32Ty}, "ParticleMotion"); 241 Symbol = UndefValue::get(StructType::create( 242 Context, {BufType1}, "class.StructuredBuffer<ParticleMotion>")); 243 Resource = ResourceInfo::RWStructuredBuffer( 244 Symbol, "g_OutputBuffer", ResourceBinding{0, 2, 1}, 245 /*UniqueID=*/0, /*Stride=*/20, Align(4), /*GloballyCoherent=*/false, 246 /*IsROV=*/false, /*HasCounter=*/true); 247 Props = Resource.getAnnotateProps(); 248 EXPECT_EQ(Props.first, 0x0000920cU); 249 EXPECT_EQ(Props.second, 0x00000014U); 250 MD = Resource.getAsMetadata(Context); 251 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "g_OutputBuffer", 0, 2, 1, 12, false, 252 true, false, TestMD.get(1, 20))); 253 254 // RWTexture2DMSArray<uint,8> g_rw_t2dmsa; 255 Symbol = UndefValue::get(StructType::create( 256 Context, {Int32Ty}, "class.RWTexture2DMSArray<unsigned int, 8>")); 257 Resource = ResourceInfo::RWTexture2DMSArray( 258 Symbol, "g_rw_t2dmsa", ResourceBinding{0, 0, 1}, 259 /*UniqueID=*/0, dxil::ElementType::U32, /*ElementCount=*/1, 260 /*SampleCount=*/8, /*GloballyCoherent=*/false); 261 Props = Resource.getAnnotateProps(); 262 EXPECT_EQ(Props.first, 0x00001008U); 263 EXPECT_EQ(Props.second, 0x00080105U); 264 MD = Resource.getAsMetadata(Context); 265 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "g_rw_t2dmsa", 0, 0, 1, 8, false, false, 266 false, TestMD.get(0, 5))); 267 268 // cbuffer cb0 { float4 g_X; float4 g_Y; } 269 Symbol = UndefValue::get( 270 StructType::create(Context, {Floatx4Ty, Floatx4Ty}, "cb0")); 271 Resource = ResourceInfo::CBuffer(Symbol, "cb0", ResourceBinding{0, 0, 1}, 272 /*UniqueID=*/0, /*Size=*/32); 273 Props = Resource.getAnnotateProps(); 274 EXPECT_EQ(Props.first, 0x0000000dU); 275 EXPECT_EQ(Props.second, 0x00000020U); 276 MD = Resource.getAsMetadata(Context); 277 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "cb0", 0, 0, 1, 32, nullptr)); 278 279 // SamplerState ColorMapSampler : register(s0); 280 Symbol = UndefValue::get( 281 StructType::create(Context, {Int32Ty}, "struct.SamplerState")); 282 Resource = 283 ResourceInfo::Sampler(Symbol, "ColorMapSampler", ResourceBinding{0, 0, 1}, 284 /*UniqueID=*/0, dxil::SamplerType::Default); 285 Props = Resource.getAnnotateProps(); 286 EXPECT_EQ(Props.first, 0x0000000eU); 287 EXPECT_EQ(Props.second, 0U); 288 MD = Resource.getAsMetadata(Context); 289 EXPECT_MDEQ(MD, 290 TestMD.get(0, Symbol, "ColorMapSampler", 0, 0, 1, 0, nullptr)); 291 292 // SamplerComparisonState ShadowSampler {...}; 293 Resource = 294 ResourceInfo::Sampler(Symbol, "CmpSampler", ResourceBinding{0, 0, 1}, 295 /*UniqueID=*/0, dxil::SamplerType::Comparison); 296 Props = Resource.getAnnotateProps(); 297 EXPECT_EQ(Props.first, 0x0000800eU); 298 EXPECT_EQ(Props.second, 0U); 299 MD = Resource.getAsMetadata(Context); 300 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "CmpSampler", 0, 0, 1, 1, nullptr)); 301 } 302