From c19e28d854e22b336d7aad78b88946864cd6eb13 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Tue, 31 Mar 2026 15:51:19 -0700 Subject: [PATCH] [NFC][LLVM] Simplify `TypeInfoGen` in Intrinsics.td (#189278) Eliminate `MappingRIdx` by making it an identity function. Currently, `MappingRIdx` is used to map the index of an `llvm_any*` type in an intrinsic type signature to its overload index. Eliminating this mapping means that dependent types in LLVM intrinsic definitions (like `LLVMMatchType` and its subclasses) should use the overload index to reference the overload type that it depends on (and not the index within the llvm_any* subset of overloaded types). See https://discourse.llvm.org/t/rfc-simplifying-intrinsics-type-signature-iit-info-generation-encoding-in-intrinsicemitter-cpp/90383 --- llvm/include/llvm/IR/Intrinsics.td | 70 +++++++++++------- llvm/test/CMakeLists.txt | 2 +- llvm/test/TableGen/intrinsic-arginfo-error.td | 5 +- ...nsic-overload-dependent-type-validation.td | 74 +++++++++++++++++++ 4 files changed, 121 insertions(+), 30 deletions(-) create mode 100644 llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index f0e6fa692bb6..e48c82ce89b5 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -252,13 +252,13 @@ class EncAnyType { int ret = !or(ID, ArgCode); } -// (Mapping[Num] << 3) | AK.MatchType +// (Num << 3) | AK.MatchType class EncMatchType { int ID = 0x200; int ret = !or(ID, Num); } -// (Mapping[Num] << 3) | ArgCodes[Mapping[Num]] +// (Num << 3) | ArgCodes[Num] class EncSameWidth { int ID = 0x300; int ret = !or(ID, Num); @@ -270,26 +270,24 @@ class EncNextArgA { int ret = !or(ID, dummy); } -// Mapping[Num] +// Num class EncNextArgN { int ID = 0x500; int ret = !or(ID, Num); } class ResolveArgCode< - list Mapping, list ArgCodes, int ACIdx, int ax> { int ah = !and(ax, 0xFF00); int al = !and(ax, 0x00FF); - int num = Mapping[al]; int ret = !cond( !eq(ah, EncAnyType<>.ID) : !or(!shl(ACIdx, 3), al), - !eq(ah, EncMatchType<>.ID) : !or(!shl(num, 3), ArgKind.MatchType), - !eq(ah, EncSameWidth<>.ID) : !or(!shl(num, 3), ArgCodes[num]), + !eq(ah, EncMatchType<>.ID) : !or(!shl(al, 3), ArgKind.MatchType), + !eq(ah, EncSameWidth<>.ID) : !or(!shl(al, 3), ArgCodes[al]), !eq(ah, EncNextArgA<>.ID) : ACIdx, - !eq(ah, EncNextArgN<>.ID) : num, + !eq(ah, EncNextArgN<>.ID) : al, true : al); } @@ -448,12 +446,28 @@ class LLVMAnyPointerType : LLVMAnyType { assert isAny, "pAny should have isOverloaded"; } -// Match the type of another intrinsic parameter. Number is an index into the -// list of overloaded types for the intrinsic, excluding all the fixed types. -// The Number value must refer to a previously listed type. For example: +// Match the type of another intrinsic parameter. Number is an index into the +// list of overloaded types for the intrinsic (i.e, the overload index), +// excluding all the fixed types and all fully dependent types (i.e., all +// sub-classes of LLVMMatchType, except LLVMMatchTypeNextArg). The Number +// value must refer to a previously listed type. For example: +// // Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_anyfloat_ty, LLVMMatchType<0>]> -// has two overloaded types, the 2nd and 3rd arguments. LLVMMatchType<0> -// refers to the first overloaded type, which is the 2nd argument. +// +// has one overloaded type, the 2nd argument. LLVMMatchType<0> refers to this +// first overloaded type, which is the 2nd argument. As another example, +// +// Intrinsic<[llvm_anyint_ty], +// [llvm_anyfloat_ty, LLVMMatchType<0>, llvm_anyfloat_ty, LLVMMatchType<2>]> +// +// has 3 overloaded types: +// overload index 0 = return type +// overload index 1 = first argument +// overload index 2 = third argument +// +// LLVMMatchType<0> therefore will match the return type, and +// LLVMMatchType<2> will match the 3rd argument. + class LLVMMatchType : LLVMType{ let Number = num; @@ -649,12 +663,7 @@ class MakeIdx Set> { !foldl(0, !range(0, i), m, j, !add(m, Set[j])), -1)); - list RIdxsR = !foreach(i, !range(Set), - !foldl(-1, !range(Set), m, j, - !if(!and(Set[j], !eq(IdxsR[j], i)), j, m))); - list Idxs = !foreach(a, IdxsR, !if(!ge(a, 0), a, ?)); - list RIdxs = !foreach(a, RIdxsR, !if(!ge(a, 0), a, ?)); } class TypeInfoGen< @@ -673,16 +682,26 @@ class TypeInfoGen< list ArgCodes = !foreach(ty, ACTys, ty.ArgCode); - // Mappings MatchTypeIdx to ACTys - list MappingRIdxs = MakeIdx< - !foreach(ty, ACTys, ty.isAny)>.RIdxs; + bit isOverloaded = !not(!empty(ACTys)); - // D63507: Exclude LLVMPointerType - bit isOverloaded = !not(!empty(!filter(ty, AllTypes, - !isa(ty)))); + // Validate that the overload index referenced by dependent types always + // references an "isAny" type. + list InvalidOverload = !foreach(ty, AllTypes, + // an entry in the list will be 1 if its a dependent type and it + // references another overload type that is not `Any`. + !and( + !or(!isa(ty), !isa(ty)), + !if(!ge(ty.Number, !size(ACTys)), + 1, + !not(ACTys[ty.Number].isAny) + ) + ) + ); + assert !eq(!foldl(0, InvalidOverload, a, x, !add(a, x)), 0), + "dependent types must reference an overload index of an \'llvm_any\' type"; list Types = !foreach(ty, AllTypes, - !if(!isa(ty), ACTys[MappingRIdxs[ty.Number]], ty)); + !if(!isa(ty), ACTys[ty.Number], ty)); list TypeSig = !listflatten(!listconcat( [!cond( @@ -692,7 +711,6 @@ class TypeInfoGen< !foreach(i, !range(AllTypes), !foreach(a, AllTypes[i].Sig, ResolveArgCode< - MappingRIdxs, ArgCodes, ACIdxs[i], a>.ret)))); diff --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt index 34213cd18e38..a027cd754135 100644 --- a/llvm/test/CMakeLists.txt +++ b/llvm/test/CMakeLists.txt @@ -66,6 +66,7 @@ set(LLVM_TEST_DEPENDS_COMMON count llvm-config not + split-file ) set(LLVM_TEST_DEPENDS @@ -154,7 +155,6 @@ set(LLVM_TEST_DEPENDS opt sancov sanstats - split-file verify-uselistorder yaml-bench yaml2obj diff --git a/llvm/test/TableGen/intrinsic-arginfo-error.td b/llvm/test/TableGen/intrinsic-arginfo-error.td index a9d30b6bec05..0a49e73bf552 100644 --- a/llvm/test/TableGen/intrinsic-arginfo-error.td +++ b/llvm/test/TableGen/intrinsic-arginfo-error.td @@ -2,9 +2,8 @@ include "llvm/IR/Intrinsics.td" -// CHECK: error: expected record type for the element with index 2 in list {{.*}} +// CHECK: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type def int_test : DefaultAttrsIntrinsic< [llvm_anyint_ty], - [llvm_anyint_ty, - LLVMMatchType<2>], + [llvm_anyint_ty, LLVMMatchType<2>], [IntrNoMem]>; diff --git a/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td b/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td new file mode 100644 index 000000000000..b7da7f6c0bf8 --- /dev/null +++ b/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td @@ -0,0 +1,74 @@ +// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST0 2>&1 | FileCheck %s --check-prefix=CHECK-TEST0 +// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST1 2>&1 | FileCheck %s --check-prefix=CHECK-TEST1 +// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST2 2>&1 | FileCheck %s --check-prefix=CHECK-TEST2 +// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST3 2>&1 | FileCheck %s --check-prefix=CHECK-TEST3 + +// This unit test tests various overloaded intrinsics that use dependent +// types to validate that if they reference an overload type is not one of the +// llvm_any*, it results in an error. + +#define TEST_INTRINSICS_SUPPRESS_DEFS +include "llvm/IR/Intrinsics.td" + +#ifdef TEST0 + +// CHECK-TEST0: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type +def int_test: DefaultAttrsIntrinsic< + [ llvm_anyvector_ty], // overload index 0. + [ LLVMVectorOfAnyPointersToElt<0>, // overload index 1. + llvm_anyvector_ty, // overload index 2. + LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>, + // Error: Fully dependent type references overload index 1, + // which is not one of the llvm_any-types. + LLVMMatchType<1>, + LLVMScalarOrSameVectorWidth<1, llvm_i1_ty>, + LLVMVectorOfAnyPointersToElt<1>, // overload index 3. + llvm_i32_ty]>; +#endif // TEST0 + +#ifdef TEST1 + +// CHECK-TEST1: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type +def int_test: DefaultAttrsIntrinsic< + [ llvm_anyvector_ty], // overload index 0. + [ LLVMVectorOfAnyPointersToElt<0>, // overload index 1. + llvm_anyvector_ty, // overload index 2. + LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>, + LLVMMatchType<0>, + // Error: Fully dependent type references overload index 1, + // which is not one of the llvm_any-types. + LLVMScalarOrSameVectorWidth<1, llvm_i1_ty>, + LLVMVectorOfAnyPointersToElt<1>, // overload index 3. + llvm_i32_ty]>; +#endif // TEST1 + +#ifdef TEST2 + +// CHECK-TEST2: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type +def int_test: DefaultAttrsIntrinsic< + [ llvm_anyvector_ty], // overload index 0. + [ LLVMVectorOfAnyPointersToElt<0>, // overload index 1. + llvm_anyvector_ty, // overload index 2. + LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>, + LLVMMatchType<0>, + LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>, + // Error: Partially dependent type references overload index 1, + // which is not one of the llvm_any-types. + LLVMVectorOfAnyPointersToElt<1>, // overload index 3. + llvm_i32_ty]>; +#endif // TEST2 + +#ifdef TEST3 + +// CHECK-TEST3: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type +def int_test: DefaultAttrsIntrinsic< + [ llvm_anyvector_ty], // overload index 0. + [ LLVMVectorOfAnyPointersToElt<0>, // overload index 1. + llvm_anyvector_ty, // overload index 2. + LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>, + LLVMMatchType<0>, + LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>, + // Error: Partially dependent type references overload index 3 (itself). + LLVMVectorOfAnyPointersToElt<3>, // overload index 3. + llvm_i32_ty]>; +#endif // TEST3