[llvm] [LLVM][Intrinsics] Change overly defensive code in `DecodeIITType` (PR #190260)

via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 11 16:03:28 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Rahul Joshi (jurahul)

<details>
<summary>Changes</summary>

`DecodeIITType` does a range check each time the next entry from the IIT encoding table is read. This is required to handle IIT encodings that are in-lined into the table `IIT_Table` entries, since the `IITEntries` array in `getIntrinsicInfoTableEntries` is terminated after the last non-zero nibble is seen in the inlined encoding (but that may not be the actual end). Change this code to instead have the `IITEntries` array for the inlined case point to the full payload + a IIT_Done terminator, so that such entries look exactly like they would if they were encoded in the long encoding table and then remove the range check in `DecodeIITType` to streamline that code a bit.

Additionally, change some use if 0s (in loop conditions and default constructed terminator in the IIT long encoding table) to explicitly use IIT_Done to clarify the code better.

Also use `consume_front()` in a few places instead of `front()` followed by `slice(1)`.

---
Full diff: https://github.com/llvm/llvm-project/pull/190260.diff


2 Files Affected:

- (modified) llvm/lib/IR/Intrinsics.cpp (+27-26) 
- (modified) llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp (+7-1) 


``````````diff
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index 0e01529bda711..0220d74ca9f12 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -202,6 +202,8 @@ enum IIT_Info {
 #include "llvm/IR/IntrinsicImpl.inc"
 };
 
+static_assert(IIT_Done == 0, "IIT_Done expected to be 0");
+
 static void
 DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
               IIT_Info LastInfo,
@@ -354,42 +356,39 @@ DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
         IITDescriptor::get(IITDescriptor::Pointer, Infos[NextElt++]));
     return;
   case IIT_ANY: {
-    unsigned OverloadInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
+    unsigned OverloadInfo = Infos[NextElt++];
     OutputTable.push_back(
         IITDescriptor::get(IITDescriptor::Overloaded, OverloadInfo));
     return;
   }
   case IIT_EXTEND_ARG: {
-    unsigned OverloadIndex = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
+    unsigned OverloadIndex = Infos[NextElt++];
     OutputTable.push_back(
         IITDescriptor::get(IITDescriptor::Extend, OverloadIndex));
     return;
   }
   case IIT_TRUNC_ARG: {
-    unsigned OverloadIndex = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
+    unsigned OverloadIndex = Infos[NextElt++];
     OutputTable.push_back(
         IITDescriptor::get(IITDescriptor::Trunc, OverloadIndex));
     return;
   }
   case IIT_ONE_NTH_ELTS_VEC_ARG: {
-    unsigned short OverloadIndex =
-        (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
-    unsigned short N = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
+    unsigned short OverloadIndex = Infos[NextElt++];
+    unsigned short N = Infos[NextElt++];
     OutputTable.push_back(IITDescriptor::get(IITDescriptor::OneNthEltsVec,
                                              /*Hi=*/N, /*Lo=*/OverloadIndex));
     return;
   }
   case IIT_SAME_VEC_WIDTH_ARG: {
-    unsigned OverloadIndex = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
+    unsigned OverloadIndex = Infos[NextElt++];
     OutputTable.push_back(
         IITDescriptor::get(IITDescriptor::SameVecWidth, OverloadIndex));
     return;
   }
   case IIT_VEC_OF_ANYPTRS_TO_ELT: {
-    unsigned short OverloadIndex =
-        (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
-    unsigned short RefOverloadIndex =
-        (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
+    unsigned short OverloadIndex = Infos[NextElt++];
+    unsigned short RefOverloadIndex = Infos[NextElt++];
     OutputTable.push_back(IITDescriptor::get(IITDescriptor::VecOfAnyPtrsToElt,
                                              /*Hi=*/RefOverloadIndex,
                                              /*Lo=*/OverloadIndex));
@@ -409,19 +408,19 @@ DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
     return;
   }
   case IIT_SUBDIVIDE2_ARG: {
-    unsigned OverloadIndex = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
+    unsigned OverloadIndex = Infos[NextElt++];
     OutputTable.push_back(
         IITDescriptor::get(IITDescriptor::Subdivide2, OverloadIndex));
     return;
   }
   case IIT_SUBDIVIDE4_ARG: {
-    unsigned OverloadIndex = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
+    unsigned OverloadIndex = Infos[NextElt++];
     OutputTable.push_back(
         IITDescriptor::get(IITDescriptor::Subdivide4, OverloadIndex));
     return;
   }
   case IIT_VEC_ELEMENT: {
-    unsigned OverloadIndex = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
+    unsigned OverloadIndex = Infos[NextElt++];
     OutputTable.push_back(
         IITDescriptor::get(IITDescriptor::VecElement, OverloadIndex));
     return;
@@ -431,7 +430,7 @@ DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
     return;
   }
   case IIT_VEC_OF_BITCASTS_TO_INT: {
-    unsigned OverloadIndex = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
+    unsigned OverloadIndex = Infos[NextElt++];
     OutputTable.push_back(
         IITDescriptor::get(IITDescriptor::VecOfBitcastsToInt, OverloadIndex));
     return;
@@ -457,8 +456,13 @@ void Intrinsic::getIntrinsicInfoTableEntries(
 
   // Array to hold the inlined fixed encoding values expanded from nibbles to
   // bytes. Its size can be be atmost FixedEncodingBits / 4 i.e., number
-  // of nibbles that can fit in `FixedEncodingTy`.
-  unsigned char IITValues[FixedEncodingBits / 4];
+  // of nibbles that can fit in `FixedEncodingTy` + 1 (the IIT_Done terminator
+  // that is not explicitly encoded). Note that if there are trailing 0 bytes
+  // in the encoding (for example, payload following one of the IIT tokens),
+  // the inlined encoding does not encode the actual size of the encoding, so
+  // we always assume its size of this maximum length possible, followed by the
+  // IIT_Done terminator token (whose value is 0).
+  unsigned char IITValues[FixedEncodingBits / 4 + 1] = {0};
 
   ArrayRef<unsigned char> IITEntries;
   unsigned NextElt = 0;
@@ -478,13 +482,13 @@ void Intrinsic::getIntrinsicInfoTableEntries(
       TableVal >>= 4;
     } while (TableVal);
 
-    IITEntries = ArrayRef(IITValues).take_front(NextElt);
+    IITEntries = IITValues;
     NextElt = 0;
   }
 
   // Okay, decode the table into the output vector of IITDescriptors.
   DecodeIITType(NextElt, IITEntries, IIT_Done, T);
-  while (NextElt != IITEntries.size() && IITEntries[NextElt] != 0)
+  while (IITEntries[NextElt] != IIT_Done)
     DecodeIITType(NextElt, IITEntries, IIT_Done, T);
 }
 
@@ -493,8 +497,7 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
                              LLVMContext &Context) {
   using namespace Intrinsic;
 
-  IITDescriptor D = Infos.front();
-  Infos = Infos.slice(1);
+  IITDescriptor D = Infos.consume_front();
 
   switch (D.Kind) {
   case IITDescriptor::Void:
@@ -862,8 +865,7 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
     return false;
   };
 
-  IITDescriptor D = Infos.front();
-  Infos = Infos.slice(1);
+  IITDescriptor D = Infos.consume_front();
 
   switch (D.Kind) {
   case IITDescriptor::Void:
@@ -997,7 +999,7 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
   case IITDescriptor::SameVecWidth: {
     if (D.getOverloadIndex() >= OverloadTys.size()) {
       // Defer check and subsequent check for the vector element type.
-      Infos = Infos.slice(1);
+      Infos.consume_front();
       return IsDeferredCheck || DeferCheck(Ty);
     }
     auto *ReferenceType =
@@ -1114,8 +1116,7 @@ bool Intrinsic::matchIntrinsicVarArg(
     return true;
 
   // Check and verify the descriptor.
-  IITDescriptor D = Infos.front();
-  Infos = Infos.slice(1);
+  IITDescriptor D = Infos.consume_front();
   if (D.Kind == IITDescriptor::VarArg)
     return !isVarArg;
 
diff --git a/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp b/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp
index bda911b50d813..85524981a2a57 100644
--- a/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp
@@ -224,6 +224,8 @@ void IntrinsicEmitter::EmitIITInfo(raw_ostream &OS) {
     RecsByNumber[Number] = Rec->getName();
   }
   if (IIT_Base.size() > 0) {
+    if (RecsByNumber[0] != "IIT_Done")
+      PrintFatalError("IIT_Done expected to have value 0");
     for (unsigned I = 0, E = RecsByNumber.size(); I < E; ++I)
       if (!RecsByNumber[I].empty())
         OS << "  " << RecsByNumber[I] << " = " << I << ",\n";
@@ -351,7 +353,11 @@ void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,
   // If we can compute a 16/32-bit fixed encoding for this intrinsic, do so and
   // capture it in this vector, otherwise store a ~0U.
   std::vector<FixedEncodingTy> FixedEncodings;
-  SequenceToOffsetTable<TypeSigTy> LongEncodingTable;
+
+  // Each IIT encoding sequence in the long encoding table is terminated by
+  // IIT_Done(=0) token.
+  constexpr unsigned char IIT_Done = 0;
+  SequenceToOffsetTable<TypeSigTy> LongEncodingTable(IIT_Done);
 
   FixedEncodings.reserve(Ints.size());
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/190260


More information about the llvm-commits mailing list