[llvm] [TableGen][DecoderEmitter] Add option to emit type-specialized `decodeToMCInst` (PR #146593)
Sergei Barannikov via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 12 03:44:45 PDT 2025
================
@@ -2176,45 +2252,99 @@ populateInstruction(const CodeGenTarget &Target, const Record &EncodingDef,
// emitFieldFromInstruction - Emit the templated helper function
// fieldFromInstruction().
-// On Windows we make sure that this function is not inlined when
-// using the VS compiler. It has a bug which causes the function
-// to be optimized out in some circumstances. See llvm.org/pr38292
-static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
- OS << R"(
-// Helper functions for extracting fields from encoded instructions.
-// InsnType must either be integral or an APInt-like object that must:
-// * be default-constructible and copy-constructible
-// * Support extractBitsAsZExtValue(numBits, startBit)
-// * Support the ~, &, ==, and != operators with other objects of the same type
-// * Support the != and bitwise & with uint64_t
-template <typename InsnType>
+//
+// On Windows we make sure that this function is not inlined when using the VS
+// compiler. It has a bug which causes the function to be optimized out in some
+// circumstances. See llvm.org/pr38292
+//
+// There are 4 variants of this function that can be generated under different
+// conditions:
+//
+// 1. Integer types (for non-templated code when using integer types and when
+// generating templated code).
+// 2. bitset types (for non-templated code with bitset type).
+// 3. APInt type (for variable length instructions).
+// 4. Non-Integer `InsnType` (when generating templated code)
+
+static void emitFieldFromInstruction(formatted_raw_ostream &OS,
+ bool GenerateIntType,
+ bool GenerateBitsetType,
+ bool GenerateAPIntType,
+ bool GenerateTemplateType) {
+ if (GenerateIntType) {
+ OS << R"(
+// Helper macro to disable inlining of `fieldFromInstruction` for integer types.
#if defined(_MSC_VER) && !defined(__clang__)
-__declspec(noinline)
+#define DEC_EMIT_NO_INLINE __declspec(noinline)
+#else
+#define DEC_EMIT_NO_INLINE
#endif
-static std::enable_if_t<std::is_integral<InsnType>::value, InsnType>
-fieldFromInstruction(const InsnType &insn, unsigned startBit,
- unsigned numBits) {
- assert(startBit + numBits <= 64 && "Cannot support >64-bit extractions!");
- assert(startBit + numBits <= (sizeof(InsnType) * 8) &&
+
+template <typename IntType>
+DEC_EMIT_NO_INLINE static
+std::enable_if_t<std::is_integral_v<IntType>, IntType>
+fieldFromInstruction(const IntType &Insn, unsigned StartBit, unsigned Size) {
+ assert(StartBit + Size <= 64 && "Cannot support >64-bit extractions!");
+ assert(StartBit + Size <= (sizeof(IntType) * 8) &&
"Instruction field out of bounds!");
- InsnType fieldMask;
- if (numBits == sizeof(InsnType) * 8)
- fieldMask = (InsnType)(-1LL);
+ IntType fieldMask;
+ if (Size == sizeof(IntType) * 8)
+ fieldMask = (IntType)(-1LL);
else
- fieldMask = (((InsnType)1 << numBits) - 1) << startBit;
- return (insn & fieldMask) >> startBit;
+ fieldMask = (((IntType)1 << Size) - 1) << StartBit;
+ return (Insn & fieldMask) >> StartBit;
+}
+#undef DEC_EMIT_NO_INLINE
+
+)";
+ }
+
+ if (GenerateBitsetType) {
+ // Emit a version that will work with a std::bitset.
+ OS << R"(
+template <size_t N>
+uint64_t fieldFromInstruction(const std::bitset<N>& Insn, unsigned StartBit,
+ unsigned Size) {
+ assert(StartBit + Size <= N && "Instruction field out of bounds!");
+ assert(Size <= 64 && "Cannot support >64-bit extractions!");
+ if (Size == N)
+ return Insn.to_ullong();
+ const std::bitset<N> Mask((1ULL << Size) - 1);
+ return ((Insn >> StartBit) & Mask).to_ullong();
}
+)";
+ }
+
+ if (GenerateAPIntType) {
+ // The templated version also works with APInt.
----------------
s-barannikov wrote:
Does it? I see `GenerateAPIntType == false` in the templated case.
https://github.com/llvm/llvm-project/pull/146593
More information about the llvm-commits
mailing list