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 = ResourceInfo::RawBuffer(Symbol, "Buffer0"); 117 Resource.bind(0, 0, 0, 1); 118 std::pair<uint32_t, uint32_t> Props = Resource.getAnnotateProps(); 119 EXPECT_EQ(Props.first, 0x0000000bU); 120 EXPECT_EQ(Props.second, 0U); 121 MDTuple *MD = Resource.getAsMetadata(Context); 122 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "Buffer0", 0, 0, 1, 11, 0, nullptr)); 123 124 // RWByteAddressBuffer BufferOut : register(u3, space2); 125 Symbol = UndefValue::get( 126 StructType::create(Context, {Int32Ty}, "struct.RWByteAddressBuffer")); 127 Resource = 128 ResourceInfo::RWRawBuffer(Symbol, "BufferOut", 129 /*GloballyCoherent=*/false, /*IsROV=*/false); 130 Resource.bind(1, 2, 3, 1); 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(Symbol, "Buffer0", 145 /*Stride=*/16, Align(8)); 146 Resource.bind(0, 0, 0, 1); 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 // StructuredBuffer<float3> Buffer1 : register(t1); 155 Symbol = UndefValue::get(StructType::create( 156 Context, {Floatx3Ty}, "class.StructuredBuffer<vector<float, 3> >")); 157 Resource = ResourceInfo::StructuredBuffer(Symbol, "Buffer1", 158 /*Stride=*/12, {}); 159 Resource.bind(1, 0, 1, 1); 160 Props = Resource.getAnnotateProps(); 161 EXPECT_EQ(Props.first, 0x0000000cU); 162 EXPECT_EQ(Props.second, 0x0000000cU); 163 MD = Resource.getAsMetadata(Context); 164 EXPECT_MDEQ( 165 MD, TestMD.get(1, Symbol, "Buffer1", 0, 1, 1, 12, 0, TestMD.get(1, 12))); 166 167 // Texture2D<float4> ColorMapTexture : register(t2); 168 Symbol = UndefValue::get(StructType::create( 169 Context, {Floatx4Ty}, "class.Texture2D<vector<float, 4> >")); 170 Resource = 171 ResourceInfo::SRV(Symbol, "ColorMapTexture", dxil::ElementType::F32, 172 /*ElementCount=*/4, dxil::ResourceKind::Texture2D); 173 Resource.bind(2, 0, 2, 1); 174 Props = Resource.getAnnotateProps(); 175 EXPECT_EQ(Props.first, 0x00000002U); 176 EXPECT_EQ(Props.second, 0x00000409U); 177 MD = Resource.getAsMetadata(Context); 178 EXPECT_MDEQ(MD, TestMD.get(2, Symbol, "ColorMapTexture", 0, 2, 1, 2, 0, 179 TestMD.get(0, 9))); 180 181 // Texture2DMS<float, 8> DepthBuffer : register(t0); 182 Symbol = UndefValue::get( 183 StructType::create(Context, {FloatTy}, "class.Texture2DMS<float, 8>")); 184 Resource = 185 ResourceInfo::Texture2DMS(Symbol, "DepthBuffer", dxil::ElementType::F32, 186 /*ElementCount=*/1, /*SampleCount=*/8); 187 Resource.bind(0, 0, 0, 1); 188 Props = Resource.getAnnotateProps(); 189 EXPECT_EQ(Props.first, 0x00000003U); 190 EXPECT_EQ(Props.second, 0x00080109U); 191 MD = Resource.getAsMetadata(Context); 192 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "DepthBuffer", 0, 0, 1, 3, 8, 193 TestMD.get(0, 9))); 194 195 // FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> feedbackMinMip; 196 Symbol = UndefValue::get( 197 StructType::create(Context, {Int32Ty}, "class.FeedbackTexture2D<0>")); 198 Resource = ResourceInfo::FeedbackTexture2D(Symbol, "feedbackMinMip", 199 SamplerFeedbackType::MinMip); 200 Resource.bind(0, 0, 0, 1); 201 Props = Resource.getAnnotateProps(); 202 EXPECT_EQ(Props.first, 0x00001011U); 203 EXPECT_EQ(Props.second, 0U); 204 MD = Resource.getAsMetadata(Context); 205 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "feedbackMinMip", 0, 0, 1, 17, false, 206 false, false, TestMD.get(2, 0))); 207 208 // FeedbackTexture2DArray<SAMPLER_FEEDBACK_MIP_REGION_USED> feedbackMipRegion; 209 Symbol = UndefValue::get(StructType::create( 210 Context, {Int32Ty}, "class.FeedbackTexture2DArray<1>")); 211 Resource = ResourceInfo::FeedbackTexture2DArray( 212 Symbol, "feedbackMipRegion", SamplerFeedbackType::MipRegionUsed); 213 Resource.bind(0, 0, 0, 1); 214 Props = Resource.getAnnotateProps(); 215 EXPECT_EQ(Props.first, 0x00001012U); 216 EXPECT_EQ(Props.second, 0x00000001U); 217 MD = Resource.getAsMetadata(Context); 218 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "feedbackMipRegion", 0, 0, 1, 18, false, 219 false, false, TestMD.get(2, 1))); 220 221 // globallycoherent RWTexture2D<int2> OutputTexture : register(u0, space2); 222 Symbol = UndefValue::get(StructType::create( 223 Context, {Int32x2Ty}, "class.RWTexture2D<vector<int, 2> >")); 224 Resource = ResourceInfo::UAV(Symbol, "OutputTexture", dxil::ElementType::I32, 225 /*ElementCount=*/2, /*GloballyCoherent=*/1, 226 /*IsROV=*/0, dxil::ResourceKind::Texture2D); 227 Resource.bind(0, 2, 0, 1); 228 Props = Resource.getAnnotateProps(); 229 EXPECT_EQ(Props.first, 0x00005002U); 230 EXPECT_EQ(Props.second, 0x00000204U); 231 MD = Resource.getAsMetadata(Context); 232 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "OutputTexture", 2, 0, 1, 2, true, 233 false, false, TestMD.get(0, 4))); 234 235 // RasterizerOrderedBuffer<float4> ROB; 236 Symbol = UndefValue::get( 237 StructType::create(Context, {Floatx4Ty}, 238 "class.RasterizerOrderedBuffer<vector<float, 4> >")); 239 Resource = ResourceInfo::UAV(Symbol, "ROB", dxil::ElementType::F32, 240 /*ElementCount=*/4, /*GloballyCoherent=*/0, 241 /*IsROV=*/1, dxil::ResourceKind::TypedBuffer); 242 Resource.bind(0, 0, 0, 1); 243 Props = Resource.getAnnotateProps(); 244 EXPECT_EQ(Props.first, 0x0000300aU); 245 EXPECT_EQ(Props.second, 0x00000409U); 246 MD = Resource.getAsMetadata(Context); 247 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "ROB", 0, 0, 1, 10, false, false, true, 248 TestMD.get(0, 9))); 249 250 // RWStructuredBuffer<ParticleMotion> g_OutputBuffer : register(u2); 251 StructType *BufType1 = StructType::create( 252 Context, {Floatx3Ty, FloatTy, Int32Ty}, "ParticleMotion"); 253 Symbol = UndefValue::get(StructType::create( 254 Context, {BufType1}, "class.StructuredBuffer<ParticleMotion>")); 255 Resource = 256 ResourceInfo::RWStructuredBuffer(Symbol, "g_OutputBuffer", /*Stride=*/20, 257 Align(4), /*GloballyCoherent=*/false, 258 /*IsROV=*/false, /*HasCounter=*/true); 259 Resource.bind(0, 0, 2, 1); 260 Props = Resource.getAnnotateProps(); 261 EXPECT_EQ(Props.first, 0x0000920cU); 262 EXPECT_EQ(Props.second, 0x00000014U); 263 MD = Resource.getAsMetadata(Context); 264 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "g_OutputBuffer", 0, 2, 1, 12, false, 265 true, false, TestMD.get(1, 20))); 266 267 // RWTexture2DMSArray<uint,8> g_rw_t2dmsa; 268 Symbol = UndefValue::get(StructType::create( 269 Context, {Int32Ty}, "class.RWTexture2DMSArray<unsigned int, 8>")); 270 Resource = ResourceInfo::RWTexture2DMSArray( 271 Symbol, "g_rw_t2dmsa", dxil::ElementType::U32, /*ElementCount=*/1, 272 /*SampleCount=*/8, /*GloballyCoherent=*/false); 273 Resource.bind(0, 0, 0, 1); 274 Props = Resource.getAnnotateProps(); 275 EXPECT_EQ(Props.first, 0x00001008U); 276 EXPECT_EQ(Props.second, 0x00080105U); 277 MD = Resource.getAsMetadata(Context); 278 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "g_rw_t2dmsa", 0, 0, 1, 8, false, false, 279 false, TestMD.get(0, 5))); 280 281 // cbuffer cb0 { float4 g_X; float4 g_Y; } 282 Symbol = UndefValue::get( 283 StructType::create(Context, {Floatx4Ty, Floatx4Ty}, "cb0")); 284 Resource = ResourceInfo::CBuffer(Symbol, "cb0", /*Size=*/32); 285 Resource.bind(0, 0, 0, 1); 286 Props = Resource.getAnnotateProps(); 287 EXPECT_EQ(Props.first, 0x0000000dU); 288 EXPECT_EQ(Props.second, 0x00000020U); 289 MD = Resource.getAsMetadata(Context); 290 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "cb0", 0, 0, 1, 32, nullptr)); 291 292 // SamplerState ColorMapSampler : register(s0); 293 Symbol = UndefValue::get( 294 StructType::create(Context, {Int32Ty}, "struct.SamplerState")); 295 Resource = ResourceInfo::Sampler(Symbol, "ColorMapSampler", 296 dxil::SamplerType::Default); 297 Resource.bind(0, 0, 0, 1); 298 Props = Resource.getAnnotateProps(); 299 EXPECT_EQ(Props.first, 0x0000000eU); 300 EXPECT_EQ(Props.second, 0U); 301 MD = Resource.getAsMetadata(Context); 302 EXPECT_MDEQ(MD, 303 TestMD.get(0, Symbol, "ColorMapSampler", 0, 0, 1, 0, nullptr)); 304 305 // SamplerComparisonState ShadowSampler {...}; 306 Resource = ResourceInfo::Sampler(Symbol, "CmpSampler", 307 dxil::SamplerType::Comparison); 308 Resource.bind(0, 0, 0, 1); 309 Props = Resource.getAnnotateProps(); 310 EXPECT_EQ(Props.first, 0x0000800eU); 311 EXPECT_EQ(Props.second, 0U); 312 MD = Resource.getAsMetadata(Context); 313 EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "CmpSampler", 0, 0, 1, 1, nullptr)); 314 } 315