diff --git a/include/dxc/dxcapi.internal.h b/include/dxc/dxcapi.internal.h index b0f9a467a4..5f5f6e7296 100644 --- a/include/dxc/dxcapi.internal.h +++ b/include/dxc/dxcapi.internal.h @@ -46,8 +46,11 @@ enum LEGAL_INTRINSIC_TEMPLATES { 4, // Any one of scalar, vector or matrix types (but not object). LITEMPLATE_OBJECT = 5, // Object types. LITEMPLATE_ARRAY = 6, // Scalar array. + LITEMPLATE_SCALAR_ONLY = 7, // Uncastable scalar types. + LITEMPLATE_VECTOR_ONLY = 8, // Uncastable vector types (eg. float3). + LITEMPLATE_MATRIX_ONLY = 9, // Uncastable matrix types (eg. float3x3). - LITEMPLATE_COUNT = 7 + LITEMPLATE_COUNT = 10 }; // INTRIN_COMPTYPE_FROM_TYPE_ELT0 is for object method intrinsics to indicate diff --git a/lib/HLSL/HLOperationLower.cpp b/lib/HLSL/HLOperationLower.cpp index 6377bba8c5..86ea3582f7 100644 --- a/lib/HLSL/HLOperationLower.cpp +++ b/lib/HLSL/HLOperationLower.cpp @@ -4196,12 +4196,10 @@ void TranslateLoad(ResLoadHelper &helper, HLResource::Kind RK, loadArgs.emplace_back(opArg); // opcode loadArgs.emplace_back(helper.handle); // resource handle + // offsets if (opcode == OP::OpCode::TextureLoad) { // set mip level loadArgs.emplace_back(helper.mipLevel); - } - - if (opcode == OP::OpCode::TextureLoad) { // texture coord unsigned coordSize = DxilResource::GetNumCoords(RK); bool isVectorAddr = helper.addr->getType()->isVectorTy(); @@ -4213,22 +4211,6 @@ void TranslateLoad(ResLoadHelper &helper, HLResource::Kind RK, } else loadArgs.emplace_back(undefI); } - } else { - if (helper.addr->getType()->isVectorTy()) { - Value *scalarOffset = - Builder.CreateExtractElement(helper.addr, (uint64_t)0); - - // TODO: calculate the real address based on opcode - - loadArgs.emplace_back(scalarOffset); // offset - } else { - // TODO: calculate the real address based on opcode - - loadArgs.emplace_back(helper.addr); // offset - } - } - // offset 0 - if (opcode == OP::OpCode::TextureLoad) { if (helper.offset && !isa(helper.offset)) { unsigned offsetSize = DxilResource::GetNumOffsets(RK); for (unsigned i = 0; i < 3; i++) { @@ -4242,11 +4224,9 @@ void TranslateLoad(ResLoadHelper &helper, HLResource::Kind RK, loadArgs.emplace_back(undefI); loadArgs.emplace_back(undefI); } - } - - // Offset 1 - if (RK == DxilResource::Kind::TypedBuffer) { - loadArgs.emplace_back(undefI); + } else { + loadArgs.emplace_back(helper.addr); // c0 + loadArgs.emplace_back(undefI); // c1 } Value *ResRet = Builder.CreateCall(F, loadArgs, OP->GetOpCodeName(opcode)); @@ -4420,12 +4400,7 @@ void TranslateStore(DxilResource::Kind RK, Value *handle, Value *val, if (RK == DxilResource::Kind::RawBuffer || RK == DxilResource::Kind::TypedBuffer) { // Offset 0 - if (offset->getType()->isVectorTy()) { - Value *scalarOffset = Builder.CreateExtractElement(offset, (uint64_t)0); - storeArgs.emplace_back(scalarOffset); // offset - } else { - storeArgs.emplace_back(offset); // offset - } + storeArgs.emplace_back(offset); // offset // Store offset0 for later use offset0Idx = storeArgs.size() - 1; diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index ba0801dd52..cb696a1e8e 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -662,6 +662,7 @@ enum ArTypeObjectKind { // indexer object used to implement .mips[1]. AR_TOBJ_STRING, // Represents a string AR_TOBJ_DEPENDENT, // Dependent type for template. + AR_TOBJ_NOCAST, // Parameter should not have layout casts (splat,trunc) }; enum TYPE_CONVERSION_FLAGS { @@ -989,9 +990,15 @@ static const ArTypeObjectKind g_NullTT[] = {AR_TOBJ_VOID, AR_TOBJ_UNKNOWN}; static const ArTypeObjectKind g_ArrayTT[] = {AR_TOBJ_ARRAY, AR_TOBJ_UNKNOWN}; +static const ArTypeObjectKind g_ScalarOnlyTT[] = {AR_TOBJ_SCALAR, AR_TOBJ_NOCAST, AR_TOBJ_UNKNOWN}; + +static const ArTypeObjectKind g_VectorOnlyTT[] = {AR_TOBJ_VECTOR, AR_TOBJ_NOCAST, AR_TOBJ_UNKNOWN}; + +static const ArTypeObjectKind g_MatrixOnlyTT[] = {AR_TOBJ_MATRIX, AR_TOBJ_NOCAST, AR_TOBJ_UNKNOWN}; + const ArTypeObjectKind *g_LegalIntrinsicTemplates[] = { g_NullTT, g_ScalarTT, g_VectorTT, g_MatrixTT, - g_AnyTT, g_ObjectTT, g_ArrayTT, + g_AnyTT, g_ObjectTT, g_ArrayTT, g_ScalarOnlyTT, g_VectorOnlyTT, g_MatrixOnlyTT, }; C_ASSERT(ARRAYSIZE(g_LegalIntrinsicTemplates) == LITEMPLATE_COUNT); @@ -6113,7 +6120,7 @@ bool HLSLExternalSource::MatchArguments( ArBasicKind ComponentType[MaxIntrinsicArgs]; // Component type for each argument, // AR_BASIC_UNKNOWN if unspecified. - UINT uSpecialSize[IA_SPECIAL_SLOTS]; // row/col matching types, UNUSED_INDEX32 + UINT uSpecialSize[IA_SPECIAL_SLOTS]; // row/col matching types, UnusedSize // if unspecified. badArgIdx = MaxIntrinsicArgs; @@ -6249,12 +6256,14 @@ bool HLSLExternalSource::MatchArguments( "otherwise intrinsic table was modified and g_MaxIntrinsicParamCount " "was not updated (or uTemplateId is out of bounds)"); - // Compare template + // Compare template to any type matching params requirements. if ((AR_TOBJ_UNKNOWN == Template[pIntrinsicArg->uTemplateId]) || ((AR_TOBJ_SCALAR == Template[pIntrinsicArg->uTemplateId]) && (AR_TOBJ_VECTOR == TypeInfoShapeKind || AR_TOBJ_MATRIX == TypeInfoShapeKind))) { - // Unrestricted or truncation of tuples to scalars are allowed + // Previous params gave no type restrictions + // or truncation of tuples to scalars are allowed + // Later steps harmonize common typed params and will always convert the earlier arg into a splat instead. Template[pIntrinsicArg->uTemplateId] = TypeInfoShapeKind; } else if (AR_TOBJ_SCALAR == TypeInfoShapeKind) { if (AR_TOBJ_SCALAR != Template[pIntrinsicArg->uTemplateId] && @@ -6292,6 +6301,11 @@ bool HLSLExternalSource::MatchArguments( } } + // If the intrinsic parameter has variable rows or columns but must match + // other argument dimensions, it will be specified in pIntrinsicArg with + // a special value indicating that the dimension depends on the passed values. + // uSpecialSize stores the dimensions of the actual passed type. + // Rows if (AR_TOBJ_SCALAR != TypeInfoShapeKind) { if (pIntrinsicArg->uRows >= IA_SPECIAL_BASE) { @@ -6398,18 +6412,37 @@ bool HLSLExternalSource::MatchArguments( const ArTypeObjectKind *pTT = g_LegalIntrinsicTemplates[pArgument->uLegalTemplates]; if (AR_TOBJ_UNKNOWN != Template[i]) { - if ((AR_TOBJ_SCALAR == Template[i]) && - (AR_TOBJ_VECTOR == *pTT || AR_TOBJ_MATRIX == *pTT)) { - Template[i] = *pTT; - } else { + // See if a perfect match overload is available + while (AR_TOBJ_UNKNOWN != *pTT && AR_TOBJ_NOCAST != *pTT) { + if (Template[i] == *pTT) + break; + pTT++; + } + + if (AR_TOBJ_UNKNOWN == *pTT) { + // Perfect match failed and casts are allowed. + // Try splats and truncations to get a match. + pTT = g_LegalIntrinsicTemplates[pArgument->uLegalTemplates]; while (AR_TOBJ_UNKNOWN != *pTT) { - if (Template[i] == *pTT) + if (AR_TOBJ_SCALAR == Template[i] && + (AR_TOBJ_VECTOR == *pTT || AR_TOBJ_MATRIX == *pTT)) { + // If a scalar was passed in and the expected value was matrix/vector + // convert to the template type for a splat. + // Only applicable to VectorTT and MatrixTT, since the vec/mtx has to be first in the list. + Template[i] = *pTT; break; + } else if (AR_TOBJ_VECTOR == Template[i] && AR_TOBJ_SCALAR == *pTT) { + // If a vector was passed in and the expected value was scalar + // convert to the template type for a truncation. + // Only applicable to ScalarTT, since the scalar has to be first in the list. + Template[i] = AR_TOBJ_SCALAR; + break; + } pTT++; } } - if (AR_TOBJ_UNKNOWN == *pTT) { + if (AR_TOBJ_UNKNOWN == *pTT || AR_TOBJ_NOCAST == *pTT) { Template[i] = g_LegalIntrinsicTemplates[pArgument->uLegalTemplates][0]; badArgIdx = std::min(badArgIdx, i); } diff --git a/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/compound/refract.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/compound/refract.hlsl index 7dfd24aa95..e72e6ceaa5 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/compound/refract.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/compound/refract.hlsl @@ -13,9 +13,10 @@ // RUN: %dxc -E main -T vs_6_2 -DTY1=float3 -DTY2=bool -enable-16bit-types %s | FileCheck %s // RUN: %dxc -E main -T vs_6_2 -DTY1=float4 -DTY2=uint16_t -enable-16bit-types %s | FileCheck %s +// RUN: %dxc -E main -T vs_6_2 -DTY1=float4 -DTY2=uint16_t4 -enable-16bit-types %s | FileCheck %s -check-prefix=CHECK +// RUN: %dxc -E main -T vs_6_2 -DTY1=float4 -DTY2=float16_t2 -enable-16bit-types %s | FileCheck %s -check-prefix=CHECK + // RUN: %dxc -E main -T vs_6_2 -DTY1=float4 -DTY2=uint16_t4x4 -enable-16bit-types %s | FileCheck %s -check-prefix=CHECK_ERROR -// RUN: %dxc -E main -T vs_6_2 -DTY1=float4 -DTY2=uint16_t4 -enable-16bit-types %s | FileCheck %s -check-prefix=CHECK_ERROR -// RUN: %dxc -E main -T vs_6_2 -DTY1=float4 -DTY2=float16_t2 -enable-16bit-types %s | FileCheck %s -check-prefix=CHECK_ERROR // RUN: %dxc -E main -T vs_6_2 -DTY1=uint16_t4x4 -DTY2=float16_t -enable-16bit-types %s | FileCheck %s -check-prefix=CHECK_ERROR // CHECK: define void @main() @@ -23,4 +24,4 @@ TY1 main (TY1 a: IN0, TY1 b : IN1, TY2 c : IN2) : OUT { return refract(a, b, c); -} \ No newline at end of file +} diff --git a/tools/clang/test/SemaHLSL/intrinsic-examples.hlsl b/tools/clang/test/SemaHLSL/intrinsic-examples.hlsl index 5feb31e5a1..555d032159 100644 --- a/tools/clang/test/SemaHLSL/intrinsic-examples.hlsl +++ b/tools/clang/test/SemaHLSL/intrinsic-examples.hlsl @@ -18,10 +18,10 @@ float4 RWByteAddressBufferMain(uint2 a : A, uint2 b : B) : SV_Target uint status; // TODO - fix the following error - the subscript exist, but the indexer type is incorrect - message is misleading r += uav1[b]; // expected-error {{type 'RWByteAddressBuffer' does not provide a subscript operator}} fxc-error {{X3121: array, matrix, vector, or indexable object type expected in index expression}} - r += uav1.Load(a); // expected-error {{no matching member function for call to 'Load'}} expected-note {{candidate function template not viable: requires 2 arguments, but 1 was provided}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint)}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint, out uint status)}} fxc-error {{X3013: 'Load': no matching 1 parameter intrinsic method}} fxc-error {{X3013: Possible intrinsic methods are:}} - uav1.Load(a, status); // expected-error {{no matching member function for call to 'Load'}} expected-note {{candidate function template not viable: requires single argument 'byteOffset', but 2 arguments were provided}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint)}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint, out uint status)}} fxc-error {{X3013: 'Load': no matching 2 parameter intrinsic method}} fxc-error {{X3013: Possible intrinsic methods are:}} + r += uav1.Load(a); // expected-warning {{implicit truncation of vector type}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint)}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint, out uint status)}} fxc-error {{X3013: 'Load': no matching 1 parameter intrinsic method}} fxc-error {{X3013: Possible intrinsic methods are:}} + uav1.Load(a, status); // expected-warning {{implicit truncation of vector type}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint)}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint, out uint status)}} fxc-error {{X3013: 'Load': no matching 2 parameter intrinsic method}} fxc-error {{X3013: Possible intrinsic methods are:}} r += status; - uav1.Load(a, status); // expected-error {{no matching member function for call to 'Load'}} expected-note {{requires single argument 'byteOffset', but 2 arguments were provided}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint)}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint, out uint status)}} fxc-error {{X3013: 'Load': no matching 2 parameter intrinsic method}} fxc-error {{X3013: Possible intrinsic methods are:}} + uav1.Load(a, status); // expected-warning {{implicit truncation of vector type}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint)}} fxc-error {{X3013: RWByteAddressBuffer.Load(uint, out uint status)}} fxc-error {{X3013: 'Load': no matching 2 parameter intrinsic method}} fxc-error {{X3013: Possible intrinsic methods are:}} r += status; uav1[b] = r; // expected-error {{type 'RWByteAddressBuffer' does not provide a subscript operator}} fxc-error {{X3121: array, matrix, vector, or indexable object type expected in index expression}} uav1.Load(a.x, status); diff --git a/utils/hct/gen_intrin_main.txt b/utils/hct/gen_intrin_main.txt index 7f7637b230..64ff61ad14 100644 --- a/utils/hct/gen_intrin_main.txt +++ b/utils/hct/gen_intrin_main.txt @@ -198,15 +198,15 @@ $type1 [[rn,unsigned_op=umax]] max(in numeric<> a, in $type1 b); $type1 [[rn,unsigned_op=umin]] min(in numeric<> a, in $type1 b); $type1 [[]] modf(in float_like<> x, out $type1 ip); uint<4> [[rn]] msad4(in uint reference, in uint<2> source, in uint<4> accum); -numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric a, in $match<2, 0> numeric b) : mul_ss; -numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric a, in $match<2, 0> numeric b) : mul_sv; -numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric a, in $match<2, 0> numeric b) : mul_sm; -numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric a, in $match<2, 0> numeric b) : mul_vs; -numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric a, in $match<2, 0> numeric b) : mul_vv; -numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric a, in col_major $match<2, 0> numeric b) : mul_vm; -numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric a, in $match<2, 0> numeric b) : mul_ms; -numeric [[rn,unsigned_op=umul]] mul(in row_major $match<1, 0> numeric a, in $match<2, 0> numeric b) : mul_mv; -numeric [[rn,unsigned_op=umul]] mul(in row_major $match<1, 0> numeric a, in col_major $match<2, 0> numeric b) : mul_mm; +numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric! a, in $match<2, 0> numeric! b) : mul_ss; +numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric! a, in $match<2, 0> numeric! b) : mul_sv; +numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric! a, in $match<2, 0> numeric! b) : mul_sm; +numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric! a, in $match<2, 0> numeric! b) : mul_vs; +numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric! a, in $match<2, 0> numeric! b) : mul_vv; +numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric! a, in col_major $match<2, 0> numeric! b) : mul_vm; +numeric [[rn,unsigned_op=umul]] mul(in $match<1, 0> numeric! a, in $match<2, 0> numeric! b) : mul_ms; +numeric [[rn,unsigned_op=umul]] mul(in row_major $match<1, 0> numeric! a, in $match<2, 0> numeric! b) : mul_mv; +numeric [[rn,unsigned_op=umul]] mul(in row_major $match<1, 0> numeric! a, in col_major $match<2, 0> numeric! b) : mul_mm; $type1 [[rn]] normalize(in float_like x); $type1 [[rn]] pow(in float_like<> x, in $type1 y); void [[]] printf(in string Format, ...); @@ -849,8 +849,8 @@ $match<0, -1> void<4> [[]] GatherCmpAlpha(in sampler_cmp s, in float<4> x, in fl namespace BufferMethods { void [[]] GetDimensions(out uint_only width) : bufinfo; -$classT [[ro]] Load(in int<1> x) : buffer_load; -$classT [[]] Load(in int<1> x, out uint_only status) : buffer_load_s; +$classT [[ro]] Load(in int x) : buffer_load; +$classT [[]] Load(in int x, out uint_only status) : buffer_load_s; } namespace diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 2f632aceee..d569b7e7f5 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -8330,13 +8330,13 @@ def load_intrinsics(self, intrinsic_defs): params_split_re = re.compile(r"\s*,\s*") ws_split_re = re.compile(r"\s+") typeref_re = re.compile(r"\$type(\d+)$") - type_matrix_re = re.compile(r"(\S+)<(\S+)@(\S+)>$") - type_vector_re = re.compile(r"(\S+)<(\S+)>$") + type_matrix_re = re.compile(r"(\S+)<(\S+)@(\S+)>(\!?)$") + type_vector_re = re.compile(r"(\S+)<(\S+)>(\!?)$") type_any_re = re.compile(r"(\S+)<>$") type_array_re = re.compile(r"(\S+)\[\]$") type_object_re = re.compile( r"""( - sampler\w* | string | + sampler\w* | any_sampler\w* | string | (?:RW)?(?:Texture\w*|ByteAddressBuffer) | acceleration_struct | ray_desc | Node\w* | RWNode\w* | EmptyNode\w* | @@ -8381,6 +8381,7 @@ def process_arg(desc, idx, done_args, intrinsic_name): component_list = "LICOMPTYPE_ANY" rows = "1" cols = "1" + only = "" if type_name == "$classT": assert idx == 0, "'$classT' can only be used as the return type" # template_id may be -1 in other places other than return type, for example in Stream.Append(). @@ -8415,13 +8416,19 @@ def process_arg(desc, idx, done_args, intrinsic_name): base_type = type_name def do_matrix(m): - base_type, rows, cols = m.groups() - template_list = "LITEMPLATE_MATRIX" + base_type, rows, cols, only = m.groups() + if only == "!": + template_list = "LITEMPLATE_MATRIX_ONLY" + else: + template_list = "LITEMPLATE_MATRIX" return base_type, rows, cols, template_list def do_vector(m): - base_type, cols = m.groups() - template_list = "LITEMPLATE_VECTOR" + base_type, cols, only = m.groups() + if only == "!": + template_list = "LITEMPLATE_VECTOR_ONLY" + else: + template_list = "LITEMPLATE_VECTOR" return base_type, rows, cols, template_list def do_any(m): @@ -8454,32 +8461,11 @@ def do_object(m): base_type, rows, cols, template_list = do(m) break else: - type_vector_match = type_vector_re.match(type_name) - if type_vector_match: - base_type = type_vector_match.group(1) - cols = type_vector_match.group(2) - template_list = "LITEMPLATE_VECTOR" + if type_name[-1] == "!": + template_list = "LITEMPLATE_SCALAR_ONLY" + base_type = type_name[:-1] else: - type_any_match = type_any_re.match(type_name) - if type_any_match: - base_type = type_any_match.group(1) - rows = "r" - cols = "c" - template_list = "LITEMPLATE_ANY" - else: - base_type = type_name - if ( - base_type.startswith("sampler") - or base_type.startswith("string") - or base_type.startswith("Texture") - or base_type.startswith("wave") - or base_type.startswith("acceleration_struct") - or base_type.startswith("ray_desc") - or base_type.startswith("any_sampler") - ): - template_list = "LITEMPLATE_OBJECT" - else: - template_list = "LITEMPLATE_SCALAR" + template_list = "LITEMPLATE_SCALAR" assert base_type in self.base_types, "Unknown base type '%s' in '%s'" % ( base_type, desc,