diff --git a/lib/HLSL/HLOperationLower.cpp b/lib/HLSL/HLOperationLower.cpp index 69ce941178..ac3994c2ac 100644 --- a/lib/HLSL/HLOperationLower.cpp +++ b/lib/HLSL/HLOperationLower.cpp @@ -4308,6 +4308,23 @@ static SmallVector GetBufLoadArgs(ResLoadHelper helper, return Args; } +static bool isMinPrecisionType(Type *EltTy, const DataLayout &DL) { + return !EltTy->isIntegerTy(1) && + DL.getTypeAllocSizeInBits(EltTy) > EltTy->getPrimitiveSizeInBits(); +} + +static Type *widenMinPrecisionType(Type *Ty, LLVMContext &Ctx, + const DataLayout &DL) { + Type *EltTy = Ty->getScalarType(); + if (!isMinPrecisionType(EltTy, DL)) + return Ty; + Type *WideTy = EltTy->isFloatingPointTy() ? Type::getFloatTy(Ctx) + : Type::getInt32Ty(Ctx); + if (Ty->isVectorTy()) + return VectorType::get(WideTy, Ty->getVectorNumElements()); + return WideTy; +} + // Emits as many calls as needed to load the full vector // Performs any needed extractions and conversions of the results. Value *TranslateBufLoad(ResLoadHelper &helper, HLResource::Kind RK, @@ -4321,10 +4338,13 @@ Value *TranslateBufLoad(ResLoadHelper &helper, HLResource::Kind RK, NumComponents = Ty->getVectorNumElements(); const bool isTyped = DXIL::IsTyped(RK); - Type *EltTy = Ty->getScalarType(); + Type *OrigEltTy = Ty->getScalarType(); + Type *WidenedTy = widenMinPrecisionType(Ty, Builder.getContext(), DL); + Type *EltTy = WidenedTy->getScalarType(); + const bool isMinPrec = (WidenedTy != Ty); const bool is64 = (EltTy->isIntegerTy(64) || EltTy->isDoubleTy()); const bool isBool = EltTy->isIntegerTy(1); - // Values will be loaded in memory representations. + // DXIL buffer loads require i32; narrow types are reconverted after load. if (isBool || (is64 && isTyped)) EltTy = Builder.getInt32Ty(); @@ -4440,6 +4460,14 @@ Value *TranslateBufLoad(ResLoadHelper &helper, HLResource::Kind RK, retValNew = Builder.CreateICmpNE( retValNew, Constant::getNullValue(retValNew->getType())); + // DXIL loads min precision as 32-bit; narrow back to original IR type. + if (isMinPrec) { + if (OrigEltTy->isIntegerTy()) + retValNew = Builder.CreateTrunc(retValNew, Ty); + else + retValNew = Builder.CreateFPTrunc(retValNew, Ty); + } + helper.retVal->replaceAllUsesWith(retValNew); helper.retVal = retValNew; @@ -4560,6 +4588,25 @@ void TranslateStore(DxilResource::Kind RK, Value *handle, Value *val, val = Builder.CreateZExt(val, Ty); } + // Min precision alloc size is 32-bit; widen to match store intrinsic. + // Scalar RawBufferStore widening is handled by TranslateMinPrecisionRawBuffer + // in DxilGenerationPass, which has signedness info from struct annotations. + if (opcode == OP::OpCode::RawBufferVectorStore) { + const DataLayout &DL = + OP->GetModule()->GetHLModule().GetModule()->getDataLayout(); + Type *WideTy = widenMinPrecisionType(Ty, Builder.getContext(), DL); + if (WideTy != Ty) { + if (EltTy->isFloatingPointTy()) + val = Builder.CreateFPExt(val, WideTy); + else + // TODO(#8314): Signedness info is lost by this point; SExt is wrong + // for min16uint. Front-end should widen during Clang CodeGen instead. + val = Builder.CreateSExt(val, WideTy); + EltTy = WideTy->getScalarType(); + Ty = WideTy; + } + } + // If RawBuffer store of 64-bit value, don't set alignment to 8, // since buffer alignment isn't known to be anything over 4. unsigned alignValue = OP->GetAllocSizeForType(EltTy); diff --git a/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16float_vec.hlsl b/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16float_vec.hlsl index 60fff4a6df..5dae57d261 100644 --- a/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16float_vec.hlsl +++ b/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16float_vec.hlsl @@ -16,20 +16,20 @@ void main() { Foo foo = buf[0]; // foo.m_B.x - // CHECK-DAG: call void @llvm.dbg.value(metadata half %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 96, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata half %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 48, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata half %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 96, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata half %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 48, 16) // foo.m_B.y - // CHECK-DAG: call void @llvm.dbg.value(metadata half %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 128, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata half %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 64, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata half %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 128, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata half %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 64, 16) // foo.m_B.z - // CHECK-DAG: call void @llvm.dbg.value(metadata half %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 160, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata half %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 80, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata half %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 160, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata half %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 80, 16) // foo.m_A.x - // CHECK-DAG: call void @llvm.dbg.value(metadata half %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata half %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata half %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata half %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) min16float value1 = foo.m_B.x; min16float value2 = foo.m_B.y; diff --git a/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16int_vec.hlsl b/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16int_vec.hlsl index a16a006b76..b7af2cf87d 100644 --- a/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16int_vec.hlsl +++ b/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16int_vec.hlsl @@ -16,20 +16,20 @@ void main() { Foo foo = buf[0]; // foo.m_B.x - // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 96, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 48, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 96, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 48, 16) // foo.m_B.y - // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 128, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 64, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 128, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 64, 16) // foo.m_B.z - // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 160, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 80, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 160, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 80, 16) // foo.m_A.x - // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) min16int value1 = foo.m_B.x; min16int value2 = foo.m_B.y; diff --git a/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16uint_vec.hlsl b/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16uint_vec.hlsl index e09a944a44..488c0385f9 100644 --- a/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16uint_vec.hlsl +++ b/tools/clang/test/HLSLFileCheck/dxil/debug/min16/min16uint_vec.hlsl @@ -16,20 +16,20 @@ void main() { Foo foo = buf[0]; // foo.m_B.x - // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 96, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 48, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 96, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 48, 16) // foo.m_B.y - // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 128, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 64, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 128, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 64, 16) // foo.m_B.z - // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 160, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 80, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 160, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 80, 16) // foo.m_A.x - // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) - // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[0-9]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) + // CHECK-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) + // CHECK16-DAG: call void @llvm.dbg.value(metadata i16 %{{[^ ,]+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"foo" !DIExpression(DW_OP_bit_piece, 0, 16) min16int value1 = foo.m_B.x; min16int value2 = foo.m_B.y; diff --git a/tools/clang/test/HLSLFileCheck/hlsl/objects/ByteAddressBuffer/min_precision_raw_load_store.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/objects/ByteAddressBuffer/min_precision_raw_load_store.hlsl new file mode 100644 index 0000000000..1b5ba27baf --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/hlsl/objects/ByteAddressBuffer/min_precision_raw_load_store.hlsl @@ -0,0 +1,38 @@ +// RUN: %dxc -E main -T cs_6_9 %s | FileCheck %s + +// Regression test for min precision rawBufferLoad/Store. +// Min precision types should use i32/f32 operations (not i16/f16) +// to match how pre-SM6.9 RawBufferLoad handles min precision. + +RWByteAddressBuffer g_buf : register(u0); + +[numthreads(1,1,1)] +void main() { + // === Vector loads/stores (RawBufferVectorLoad/Store) === + + // min16int: should load as v3i32, not v3i16 + // CHECK: call %dx.types.ResRet.v3i32 @dx.op.rawBufferVectorLoad.v3i32 + min16int3 vi = g_buf.Load< min16int3 >(0); + // CHECK: call void @dx.op.rawBufferVectorStore.v3i32 + g_buf.Store< min16int3 >(12, vi); + + // min16uint: should load as v3i32, not v3i16 + // CHECK: call %dx.types.ResRet.v3i32 @dx.op.rawBufferVectorLoad.v3i32 + min16uint3 vu = g_buf.Load< min16uint3 >(24); + // CHECK: call void @dx.op.rawBufferVectorStore.v3i32 + g_buf.Store< min16uint3 >(36, vu); + + // min16float: should load as v3f32, not v3f16 + // CHECK: call %dx.types.ResRet.v3f32 @dx.op.rawBufferVectorLoad.v3f32 + // CHECK: fptrunc <3 x float> {{.*}} to <3 x half> + min16float3 vf = g_buf.Load< min16float3 >(48); + // CHECK: fpext <3 x half> {{.*}} to <3 x float> + // CHECK: call void @dx.op.rawBufferVectorStore.v3f32 + g_buf.Store< min16float3 >(60, vf); + + // Verify i16/f16 ops are NOT used for vector loads/stores. + // CHECK-NOT: rawBufferVectorLoad.v{{[0-9]+}}i16 + // CHECK-NOT: rawBufferVectorStore.v{{[0-9]+}}i16 + // CHECK-NOT: rawBufferVectorLoad.v{{[0-9]+}}f16 + // CHECK-NOT: rawBufferVectorStore.v{{[0-9]+}}f16 +}