[llvm] [DirectX] Generalize DXIL integer legalization (PR #225233)

Farzon Lotfi via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 6 19:06:23 PDT 2026


================
@@ -25,6 +27,335 @@
 
 using namespace llvm;
 
+// Map an unsupported integer type to the smallest legal DXIL carrier type.
+static IntegerType *getLegalIntegerType(Type *Ty) {
+  auto *IntTy = dyn_cast<IntegerType>(Ty);
+  if (!IntTy)
+    return nullptr;
+
+  unsigned Width = IntTy->getBitWidth();
+  // DXIL uses i1 for SSA predicates even though booleans occupy i32 in memory.
+  if (Width == 1 || Width == 16 || Width == 32 || Width == 64)
+    return nullptr;
+  if (Width < 32)
+    return Type::getInt32Ty(Ty->getContext());
+  if (Width < 64)
+    return Type::getInt64Ty(Ty->getContext());
+  return nullptr;
+}
+
+enum class IntegerExtension { None, Zero, Sign };
+
+// Zero-extend the low Width bits of a legal-width carrier.
+static Value *maskToIntegerWidth(Value *V, unsigned Width,
+                                 IRBuilder<> &Builder) {
+  auto *LegalTy = cast<IntegerType>(V->getType());
+  APInt Mask = APInt::getLowBitsSet(LegalTy->getBitWidth(), Width);
+  return Builder.CreateAnd(V, ConstantInt::get(LegalTy, Mask));
+}
+
+// Return true when V is already a zero-extended Width-bit value.
+static bool isKnownZeroExtendedFromWidth(Value *V, unsigned Width,
+                                         const DataLayout &DL) {
+  unsigned LegalWidth = V->getType()->getIntegerBitWidth();
+  ConstantRange Range = computeConstantRangeIncludingKnownBits(
+      V, /*ForSigned=*/false, SimplifyQuery(DL, dyn_cast<Instruction>(V)));
+  return Range.getUnsignedMax().ult(APInt::getOneBitSet(LegalWidth, Width));
+}
+
+// Return true when V is already a sign-extended Width-bit value.
+static bool isKnownSignExtendedFromWidth(Value *V, unsigned Width,
+                                         const DataLayout &DL) {
+  unsigned LegalWidth = V->getType()->getIntegerBitWidth();
+  ConstantRange Range = computeConstantRangeIncludingKnownBits(
+      V, /*ForSigned=*/true, SimplifyQuery(DL, dyn_cast<Instruction>(V)));
+  APInt SignedMin = APInt::getSignedMinValue(Width).sext(LegalWidth);
+  APInt SignedMax = APInt::getSignedMaxValue(Width).sext(LegalWidth);
+  return Range.getSignedMin().sge(SignedMin) &&
+         Range.getSignedMax().sle(SignedMax);
+}
+
+// Get an operand's legal carrier, normalizing it only when a consumer requires
+// signed or unsigned narrow-integer semantics.
+static Value *
+getLegalizedIntegerOperand(Value *Operand, IntegerType *LegalTy,
+                           IntegerExtension Extension, IRBuilder<> &Builder,
+                           DenseMap<Value *, Value *> &ReplacedValues,
+                           const DataLayout &DL) {
+  if (Value *Replacement = ReplacedValues.lookup(Operand)) {
+    Replacement = Builder.CreateZExtOrTrunc(Replacement, LegalTy);
+    if (Extension == IntegerExtension::None)
+      return Replacement;
+    unsigned Width = cast<IntegerType>(Operand->getType())->getBitWidth();
+    if (Extension == IntegerExtension::Zero) {
+      if (auto *OverflowingOp = dyn_cast<OverflowingBinaryOperator>(Operand);
+          OverflowingOp && OverflowingOp->hasNoUnsignedWrap())
+        return Replacement;
+      return isKnownZeroExtendedFromWidth(Replacement, Width, DL)
+                 ? Replacement
+                 : maskToIntegerWidth(Replacement, Width, Builder);
+    }
+    if (isKnownSignExtendedFromWidth(Replacement, Width, DL))
+      return Replacement;
+    if (auto *OverflowingOp = dyn_cast<OverflowingBinaryOperator>(Operand);
+        OverflowingOp && OverflowingOp->hasNoSignedWrap())
+      return Replacement;
+    unsigned Shift = LegalTy->getBitWidth() - Width;
+    return Builder.CreateAShr(Builder.CreateShl(Replacement, Shift), Shift);
+  }
+  if (auto *C = dyn_cast<ConstantInt>(Operand))
+    return ConstantInt::get(
+        LegalTy, Extension == IntegerExtension::Sign
+                     ? C->getValue().sextOrTrunc(LegalTy->getBitWidth())
+                     : C->getValue().zextOrTrunc(LegalTy->getBitWidth()));
+  return Operand->getType() == LegalTy ? Operand : nullptr;
+}
+
+// bitcast <N x iM> to illegal iK -> extract and pack into an i32/i64 carrier.
+static bool
+legalizeNonStandardIntegerBitCast(BitCastInst &BitCast,
+                                  SmallVectorImpl<Instruction *> &ToRemove,
+                                  DenseMap<Value *, Value *> &ReplacedValues) {
+  auto *LegalTy = getLegalIntegerType(BitCast.getDestTy());
+  auto *SourceTy = dyn_cast<FixedVectorType>(BitCast.getSrcTy());
+  if (!LegalTy || !SourceTy || !SourceTy->getElementType()->isIntegerTy() ||
+      SourceTy->getPrimitiveSizeInBits() !=
----------------
farzonl wrote:

another case where  I will instead now do `report_fatal_error` instead of ignoring the issue.

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


More information about the llvm-commits mailing list