[llvm] [llubi] Implement intrinsics for integer arithmetic/bit manipulation (PR #193702)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 23 02:58:47 PDT 2026


================
@@ -381,6 +472,171 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
       }
       return AnyValue();
     }
+    case Intrinsic::ssa_copy:
+    case Intrinsic::expect:
+    case Intrinsic::expect_with_probability:
+      return getValue(CB.getArgOperand(0));
+    case Intrinsic::donothing:
+      return AnyValue();
+    case Intrinsic::vscale:
+      return APInt(RetTy->getScalarSizeInBits(), Ctx.getVScale());
+    case Intrinsic::abs: {
+      const bool IsIntMinPoison =
+          getBooleanNonPoison(getValue(CB.getArgOperand(1)).asBoolean());
+      return visitIntUnOpWithResult(CB, [&](const APInt &Operand) -> AnyValue {
+        if (IsIntMinPoison && Operand.isMinSignedValue())
+          return AnyValue::poison();
+        return Operand.abs();
+      });
+    }
+    case Intrinsic::smax: {
+      return visitIntBinOpWithResult(
+          CB, [](const APInt &LHS, const APInt &RHS) -> AnyValue {
+            return APIntOps::smax(LHS, RHS);
+          });
+    }
+    case Intrinsic::smin: {
+      return visitIntBinOpWithResult(
+          CB, [](const APInt &LHS, const APInt &RHS) -> AnyValue {
+            return APIntOps::smin(LHS, RHS);
+          });
+    }
+    case Intrinsic::umax: {
+      return visitIntBinOpWithResult(
+          CB, [](const APInt &LHS, const APInt &RHS) -> AnyValue {
+            return APIntOps::umax(LHS, RHS);
+          });
+    }
+    case Intrinsic::umin: {
+      return visitIntBinOpWithResult(
+          CB, [](const APInt &LHS, const APInt &RHS) -> AnyValue {
+            return APIntOps::umin(LHS, RHS);
+          });
+    }
+    case Intrinsic::scmp:
+    case Intrinsic::ucmp: {
+      std::uint32_t BitWidth = RetTy->getScalarSizeInBits();
+      return visitIntBinOpWithResult(
+          CB, [&](const APInt &LHS, const APInt &RHS) -> AnyValue {
+            if (LHS == RHS)
+              return APInt::getZero(BitWidth);
+            if (IID == Intrinsic::scmp)
+              return LHS.slt(RHS) ? APInt::getAllOnes(BitWidth)
+                                  : APInt(BitWidth, 1);
+            return LHS.ult(RHS) ? APInt::getAllOnes(BitWidth)
+                                : APInt(BitWidth, 1);
+          });
+    }
+    case Intrinsic::bitreverse: {
+      return visitIntUnOpWithResult(CB, [](const APInt &Operand) -> AnyValue {
+        return Operand.reverseBits();
+      });
+    }
+    case Intrinsic::bswap: {
+      return visitIntUnOpWithResult(CB, [](const APInt &Operand) -> AnyValue {
+        return Operand.byteSwap();
+      });
+    }
+    case Intrinsic::ctpop: {
+      return visitIntUnOpWithResult(CB, [](const APInt &Operand) -> AnyValue {
+        return APInt(Operand.getBitWidth(), Operand.popcount());
+      });
+    }
+    case Intrinsic::ctlz:
+    case Intrinsic::cttz: {
+      const bool IsZeroPoison =
+          getBooleanNonPoison(getValue(CB.getArgOperand(1)).asBoolean());
+      return visitIntUnOpWithResult(CB, [&](const APInt &Operand) -> AnyValue {
+        if (IsZeroPoison && Operand.isZero())
+          return AnyValue::poison();
+        if (IID == Intrinsic::ctlz)
+          return APInt(Operand.getBitWidth(), Operand.countl_zero());
+        return APInt(Operand.getBitWidth(), Operand.countr_zero());
+      });
+    }
+    case Intrinsic::fshl:
+    case Intrinsic::fshr: {
+      return visitIntTriOpWithResult(
+          CB,
+          [IID](const APInt &Op1, const APInt &Op2,
+                const APInt &Op3) -> AnyValue {
+            const std::uint32_t BitWidth = Op1.getBitWidth();
+            const std::uint32_t ShiftAmount = Op3.urem(BitWidth);
+            const bool IsFShr = IID == Intrinsic::fshr;
+            const std::uint32_t LShrAmount =
+                IsFShr ? ShiftAmount : BitWidth - ShiftAmount;
+            const std::uint32_t ShlAmount =
+                !IsFShr ? ShiftAmount : BitWidth - ShiftAmount;
+            return Op1.shl(ShlAmount) | Op2.lshr(LShrAmount);
+          });
+    }
+    case Intrinsic::clmul: {
+      return visitIntBinOpWithResult(
+          CB, [](const APInt &LHS, const APInt &RHS) -> AnyValue {
+            return APIntOps::clmul(LHS, RHS);
+          });
+    }
+    case Intrinsic::sadd_with_overflow:
+    case Intrinsic::uadd_with_overflow:
+    case Intrinsic::ssub_with_overflow:
+    case Intrinsic::usub_with_overflow:
+    case Intrinsic::smul_with_overflow:
+    case Intrinsic::umul_with_overflow: {
+      return visitIntBinOpWithResult(
+          CB, [IID](const APInt &LHS, const APInt &RHS) -> AnyValue {
+            APInt Res;
+            bool Overflow = false;
+            switch (IID) {
+            case Intrinsic::sadd_with_overflow:
+              Res = LHS.sadd_ov(RHS, Overflow);
+              break;
+            case Intrinsic::uadd_with_overflow:
+              Res = LHS.uadd_ov(RHS, Overflow);
+              break;
+            case Intrinsic::ssub_with_overflow:
+              Res = LHS.ssub_ov(RHS, Overflow);
+              break;
+            case Intrinsic::usub_with_overflow:
+              Res = LHS.usub_ov(RHS, Overflow);
+              break;
+            case Intrinsic::smul_with_overflow:
+              Res = LHS.smul_ov(RHS, Overflow);
+              break;
+            case Intrinsic::umul_with_overflow:
+              Res = LHS.umul_ov(RHS, Overflow);
+              break;
+            default:
+              llvm_unreachable("Unexpected intrinsic ID");
+            }
+            return std::vector{AnyValue(Res), AnyValue::boolean(Overflow)};
+          });
+    }
+    case Intrinsic::sadd_sat:
+    case Intrinsic::uadd_sat:
+    case Intrinsic::ssub_sat:
+    case Intrinsic::usub_sat:
+    case Intrinsic::sshl_sat:
+    case Intrinsic::ushl_sat: {
+      return visitIntBinOpWithResult(
+          CB, [IID](const APInt &LHS, const APInt &RHS) -> AnyValue {
+            switch (IID) {
+            case Intrinsic::sadd_sat:
+              return LHS.sadd_sat(RHS);
+            case Intrinsic::uadd_sat:
+              return LHS.uadd_sat(RHS);
+            case Intrinsic::ssub_sat:
+              return LHS.ssub_sat(RHS);
+            case Intrinsic::usub_sat:
+              return LHS.usub_sat(RHS);
+            case Intrinsic::sshl_sat:
+              return LHS.sshl_sat(RHS);
+            case Intrinsic::ushl_sat:
+              return LHS.ushl_sat(RHS);
----------------
nikic wrote:

> The arguments (%a and %b) and the result may be of integer types of any bit width, but they must have the same bit width. %a is the value to be shifted, and %b is the amount to shift by. If b is (statically or dynamically) equal to or larger than the integer bit width of the arguments, the result is a [poison value](https://llvm.org/docs/LangRef.html#poisonvalues). If the arguments are vectors, each vector element of a is shifted by the corresponding shift amount in b.

Missing poison handling.

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


More information about the llvm-commits mailing list