[llvm] [IR] Reject unhandled assume bundles and seperate them from normal attributes (PR #197007)
Nikolas Klauser via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 8 00:51:37 PDT 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/197007
>From 8638a3094025b99918fd28e7062ca254151b6d05 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 11 May 2026 19:09:30 +0200
Subject: [PATCH 01/12] [IR] Reject unhandled assume bundles and seperate them
from normal attributes
---
llvm/include/llvm/IR/BundleAttributes.def | 18 ++
llvm/include/llvm/IR/BundleAttributes.h | 62 +++++
llvm/include/llvm/IR/InstrTypes.h | 6 +
.../llvm/Transforms/Utils/PredicateInfo.h | 5 +-
llvm/lib/Analysis/LazyValueInfo.cpp | 36 ++-
llvm/lib/Analysis/ValueTracking.cpp | 61 ++---
llvm/lib/IR/BundleAttributes.cpp | 58 +++++
llvm/lib/IR/CMakeLists.txt | 1 +
llvm/lib/IR/Verifier.cpp | 91 ++++----
.../InstCombine/InstCombineCalls.cpp | 94 ++++----
.../Transforms/Utils/AssumeBundleBuilder.cpp | 9 +-
llvm/lib/Transforms/Utils/PredicateInfo.cpp | 17 +-
llvm/test/Transforms/Attributor/nofpclass.ll | 28 ---
llvm/test/Transforms/Attributor/nofree.ll | 81 -------
...-split-musttail-chain-pgo-counter-promo.ll | 6 +-
llvm/test/Transforms/InstCombine/test.ll | 38 +++
llvm/test/Transforms/Util/assume-builder.ll | 217 ------------------
llvm/test/Verifier/assume-bundles.ll | 77 ++++++-
.../Analysis/AssumeBundleQueriesTest.cpp | 27 ---
19 files changed, 415 insertions(+), 517 deletions(-)
create mode 100644 llvm/include/llvm/IR/BundleAttributes.def
create mode 100644 llvm/include/llvm/IR/BundleAttributes.h
create mode 100644 llvm/lib/IR/BundleAttributes.cpp
create mode 100644 llvm/test/Transforms/InstCombine/test.ll
diff --git a/llvm/include/llvm/IR/BundleAttributes.def b/llvm/include/llvm/IR/BundleAttributes.def
new file mode 100644
index 0000000000000..2d57a0b697edc
--- /dev/null
+++ b/llvm/include/llvm/IR/BundleAttributes.def
@@ -0,0 +1,18 @@
+//===- llvm/BundleAttributes.def - LLVM Bundle Attributes -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+ATTR(Align, align)
+ATTR(Cold, cold)
+ATTR(Dereferenceable, dereferenceable)
+ATTR(DereferenceableOrNull, dereferenceable_or_null)
+ATTR(Ignore, ignore)
+ATTR(NonNull, nonnull)
+ATTR(NoUndef, noundef) // FIXME: Is this actually useful? It's currently exclusively emitted through tests.
+ATTR(SeparateStorage, separate_storage)
+
+#undef ATTR
diff --git a/llvm/include/llvm/IR/BundleAttributes.h b/llvm/include/llvm/IR/BundleAttributes.h
new file mode 100644
index 0000000000000..789e5b95fc1e4
--- /dev/null
+++ b/llvm/include/llvm/IR/BundleAttributes.h
@@ -0,0 +1,62 @@
+//===- llvm/BundleAttributes.h - LLVM Bundle Attributes ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_IR_BUNDLE_ATTRIBUTES_H
+#define LLVM_IR_BUNDLE_ATTRIBUTES_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/InstrTypes.h"
+
+enum class BundleAttr {
+ None,
+#define ATTR(Name, String) Name,
+#include "BundleAttributes.def"
+};
+
+namespace llvm {
+
+LLVM_ABI StringRef getNameFromBundleAttr(BundleAttr);
+LLVM_ABI BundleAttr getBundleAttrFromString(StringRef);
+
+inline BundleAttr getBundleAttrFromOBU(OperandBundleUse OBU) {
+ return getBundleAttrFromString(OBU.getTagName());
+}
+
+struct AssumeAlignInfo {
+ Value *Ptr;
+ Value *Alignment;
+ Value *Offset;
+};
+
+LLVM_ABI AssumeAlignInfo getAssumeAlignInfo(OperandBundleUse);
+
+struct AssumeSeparateStorageInfo {
+ const Use *Ptr1;
+ const Use *Ptr2;
+};
+
+LLVM_ABI
+AssumeSeparateStorageInfo getAssumeSeparateStorageInfo(OperandBundleUse);
+
+struct AssumeNonNullInfo {
+ Value *Ptr;
+};
+
+LLVM_ABI AssumeNonNullInfo getAssumeNonNullInfo(OperandBundleUse);
+
+struct AssumeDereferenceableInfo {
+ Value *Ptr;
+ Value *Count;
+};
+
+LLVM_ABI
+AssumeDereferenceableInfo getAssumeDereferenceableInfo(OperandBundleUse);
+
+} // namespace llvm
+
+#endif // LLVM_IR_BUNDLE_ATTRIBUTES_H
diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index 61dc5ebef1b1d..123a42d09ce7c 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -2286,6 +2286,12 @@ class CallBase : public Instruction {
return make_range(bundle_op_info_begin(), bundle_op_info_end());
}
+ auto operand_bundles() const {
+ return map_range(bundle_op_infos(), [this](BundleOpInfo BOI) {
+ return operandBundleFromBundleOpInfo(BOI);
+ });
+ }
+
/// Populate the BundleOpInfo instances and the Use& vector from \p
/// Bundles. Return the op_iterator pointing to the Use& one past the last
/// last bundle operand use.
diff --git a/llvm/include/llvm/Transforms/Utils/PredicateInfo.h b/llvm/include/llvm/Transforms/Utils/PredicateInfo.h
index e472656d7b9fb..06ce720bda6a9 100644
--- a/llvm/include/llvm/Transforms/Utils/PredicateInfo.h
+++ b/llvm/include/llvm/Transforms/Utils/PredicateInfo.h
@@ -52,6 +52,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/IR/BundleAttributes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/ValueHandle.h"
@@ -132,9 +133,9 @@ class PredicateAssume : public PredicateBase {
class PredicateBundleAssume : public PredicateAssume {
public:
- Attribute::AttrKind AttrKind;
+ BundleAttr AttrKind;
PredicateBundleAssume(Value *Op, IntrinsicInst *AssumeInst,
- Attribute::AttrKind AttrKind)
+ BundleAttr AttrKind)
: PredicateAssume(PT_BundleAssume, Op, AssumeInst, nullptr),
AttrKind(AttrKind) {}
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index b70c380dd5466..37771985bd455 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -14,7 +14,6 @@
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Analysis/AssumeBundleQueries.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/InstructionSimplify.h"
@@ -23,6 +22,7 @@
#include "llvm/Analysis/ValueLattice.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/AssemblyAnnotationWriter.h"
+#include "llvm/IR/BundleAttributes.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
@@ -856,26 +856,24 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
continue;
if (AssumeVH.Index != AssumptionCache::ExprResultIdx) {
- if (RetainedKnowledge RK = getKnowledgeFromBundle(
- *I, I->bundle_op_info_begin()[AssumeVH.Index])) {
- if (RK.WasOn != Val)
- continue;
- switch (RK.AttrKind) {
- case Attribute::NonNull:
- BBLV = BBLV.intersect(ValueLatticeElement::getNot(
- Constant::getNullValue(RK.WasOn->getType())));
- break;
+ auto OBU = I->operand_bundles().begin()[AssumeVH.Index];
+ switch (getBundleAttrFromOBU(OBU)) {
+ case BundleAttr::NonNull:
+ assert(getAssumeNonNullInfo(OBU).Ptr == Val);
+ BBLV = BBLV.intersect(ValueLatticeElement::getNot(
+ Constant::getNullValue(Val->getType())));
+ break;
- case Attribute::Dereferenceable:
- if (auto *CI = dyn_cast<ConstantInt>(RK.IRArgValue);
- CI && !CI->isZero())
- BBLV = BBLV.intersect(ValueLatticeElement::getNot(
- Constant::getNullValue(RK.WasOn->getType())));
- break;
+ case BundleAttr::Dereferenceable: {
+ auto [Ptr, Count] = getAssumeDereferenceableInfo(OBU);
+ assert(Ptr == Val);
+ if (auto *CI = dyn_cast<ConstantInt>(Count); CI && !CI->isZero())
+ BBLV = BBLV.intersect(ValueLatticeElement::getNot(
+ Constant::getNullValue(Val->getType())));
+ } break;
- default:
- break;
- }
+ default:
+ break;
}
} else {
BBLV = BBLV.intersect(*getValueFromCondition(Val, I->getArgOperand(0),
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 91ad517f194a6..7a391182594ee 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -38,6 +38,7 @@
#include "llvm/IR/Argument.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/BundleAttributes.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/ConstantFPRange.h"
#include "llvm/IR/ConstantRange.h"
@@ -829,32 +830,28 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
"Got assumption for the wrong function!");
if (Elem.Index != AssumptionCache::ExprResultIdx) {
- if (!V->getType()->isPointerTy())
- continue;
- if (RetainedKnowledge RK = getKnowledgeFromBundle(
- *I, I->bundle_op_info_begin()[Elem.Index])) {
- if (RK.WasOn != V)
- continue;
- bool AssumeImpliesNonNull = [&]() {
- if (RK.AttrKind == Attribute::NonNull)
- return true;
+ auto OBU = I->operand_bundles().begin()[Elem.Index];
+ bool AssumeImpliesNonNull = [&]() {
+ switch (getBundleAttrFromOBU(OBU)) {
+ case BundleAttr::Dereferenceable: {
+ auto [Ptr, Count] = getAssumeDereferenceableInfo(OBU);
+ if (NullPointerIsDefined(Q.CxtI->getFunction(),
+ V->getType()->getPointerAddressSpace()))
+ return false;
- if (RK.AttrKind == Attribute::Dereferenceable) {
- if (NullPointerIsDefined(Q.CxtI->getFunction(),
- V->getType()->getPointerAddressSpace()))
- return false;
- assert(RK.IRArgValue &&
- "Dereferenceable attribute without IR argument?");
+ auto *CI = dyn_cast<ConstantInt>(Count);
+ return CI && !CI->isZero();
+ }
- auto *CI = dyn_cast<ConstantInt>(RK.IRArgValue);
- return CI && !CI->isZero();
- }
+ case BundleAttr::NonNull:
+ return true;
+ default:
return false;
- }();
- if (AssumeImpliesNonNull && isValidAssumeForContext(I, Q))
- return true;
- }
+ }
+ }();
+ if (AssumeImpliesNonNull && isValidAssumeForContext(I, Q))
+ return true;
continue;
}
@@ -1090,13 +1087,19 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
"Got assumption for the wrong function!");
if (Elem.Index != AssumptionCache::ExprResultIdx) {
- if (!V->getType()->isPointerTy())
- continue;
- if (RetainedKnowledge RK = getKnowledgeFromBundle(
- *I, I->bundle_op_info_begin()[Elem.Index])) {
- if (RK.WasOn == V && RK.AttrKind == Attribute::Alignment &&
- isPowerOf2_64(RK.ArgValue) && isValidAssumeForContext(I, Q))
- Known.Zero.setLowBits(Log2_64(RK.ArgValue));
+ auto OBU = I->operand_bundles().begin()[Elem.Index];
+ if (getBundleAttrFromOBU(OBU) == BundleAttr::Align) {
+ auto [Ptr, Alignment, Offset] = getAssumeAlignInfo(OBU);
+ assert(Ptr == V);
+ if ((Offset && !isa<ConstantInt>(Offset)) ||
+ !isa<ConstantInt>(Alignment))
+ continue;
+ auto AlignVal =
+ MinAlign(Offset ? cast<ConstantInt>(Offset)->getZExtValue() : 0,
+ cast<ConstantInt>(Alignment)->getZExtValue());
+ if (!isPowerOf2_64(AlignVal) || !isValidAssumeForContext(I, Q))
+ continue;
+ Known.Zero.setLowBits(Log2_64(AlignVal));
}
continue;
}
diff --git a/llvm/lib/IR/BundleAttributes.cpp b/llvm/lib/IR/BundleAttributes.cpp
new file mode 100644
index 0000000000000..19ff05a96ee27
--- /dev/null
+++ b/llvm/lib/IR/BundleAttributes.cpp
@@ -0,0 +1,58 @@
+//===- llvm/BundleAttributes.cpp - LLVM Bundle Attributes -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/BundleAttributes.h"
+
+using namespace llvm;
+
+StringRef llvm::getNameFromBundleAttr(BundleAttr BA) {
+ switch (BA) {
+#define ATTR(Name, Str) \
+ case BundleAttr::Name: \
+ return #Str;
+#include "llvm/IR/BundleAttributes.def"
+ case BundleAttr::None:
+ return "none";
+ }
+}
+
+BundleAttr llvm::getBundleAttrFromString(StringRef Str) {
+ return StringSwitch<BundleAttr>(Str)
+#define ATTR(Name, Str) .Case(#Str, BundleAttr::Name)
+#include "llvm/IR/BundleAttributes.def"
+ .Default(BundleAttr::None);
+}
+
+AssumeAlignInfo llvm::getAssumeAlignInfo(OperandBundleUse OBU) {
+ assert(OBU.getTagName() == "align" && OBU.Inputs.size() >= 2 &&
+ OBU.Inputs.size() <= 3);
+ AssumeAlignInfo Ret{};
+ Ret.Ptr = OBU.Inputs[0];
+ Ret.Alignment = OBU.Inputs[1];
+ if (OBU.Inputs.size() == 3)
+ Ret.Offset = OBU.Inputs[2];
+ return Ret;
+}
+
+AssumeSeparateStorageInfo
+llvm::getAssumeSeparateStorageInfo(OperandBundleUse OBU) {
+ assert(OBU.getTagName() == "separate_storage" && OBU.Inputs.size() == 2);
+ return {&OBU.Inputs[0], &OBU.Inputs[1]};
+}
+
+AssumeNonNullInfo llvm::getAssumeNonNullInfo(OperandBundleUse OBU) {
+ assert(OBU.getTagName() == "nonnull" && OBU.Inputs.size() == 1);
+ return {OBU.Inputs[0]};
+}
+
+AssumeDereferenceableInfo
+llvm::getAssumeDereferenceableInfo(OperandBundleUse OBU) {
+ assert(OBU.getTagName() == "dereferenceable" && OBU.Inputs.size() == 2);
+ return {OBU.Inputs[0], OBU.Inputs[1]};
+}
diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt
index 5511c3b33b0d7..9cc45ef0e1773 100644
--- a/llvm/lib/IR/CMakeLists.txt
+++ b/llvm/lib/IR/CMakeLists.txt
@@ -6,6 +6,7 @@ add_llvm_component_library(LLVMCore
AutoUpgrade.cpp
BasicBlock.cpp
BuiltinGCs.cpp
+ BundleAttributes.cpp
Comdat.cpp
ConstantFold.cpp
ConstantFPRange.cpp
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index e75ba813e4559..8b5748bbf6f4e 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -64,6 +64,7 @@
#include "llvm/IR/AttributeMask.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/BundleAttributes.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Comdat.h"
@@ -5995,56 +5996,60 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
Check(Cond && Cond->isOne(),
"assume with operand bundles must have i1 true condition", Call);
}
- for (auto &Elem : Call.bundle_op_infos()) {
- unsigned ArgCount = Elem.End - Elem.Begin;
+ for (auto OBU : Call.operand_bundles()) {
// Separate storage assumptions are special insofar as they're the only
// operand bundles allowed on assumes that aren't parameter attributes.
- if (Elem.Tag->getKey() == "separate_storage") {
- Check(ArgCount == 2,
- "separate_storage assumptions should have 2 arguments", Call);
- Check(Call.getOperand(Elem.Begin)->getType()->isPointerTy() &&
- Call.getOperand(Elem.Begin + 1)->getType()->isPointerTy(),
- "arguments to separate_storage assumptions should be pointers",
- Call);
- continue;
- }
- Check(Elem.Tag->getKey() == "ignore" ||
- Attribute::isExistingAttribute(Elem.Tag->getKey()),
- "tags must be valid attribute names", Call);
- Attribute::AttrKind Kind =
- Attribute::getAttrKindFromName(Elem.Tag->getKey());
- if (Kind == Attribute::Alignment) {
- Check(ArgCount <= 3 && ArgCount >= 2,
+
+ auto GetTypeAt = [&](unsigned Index) {
+ return OBU.Inputs[Index]->getType();
+ };
+
+ switch (getBundleAttrFromOBU(OBU)) {
+ case BundleAttr::None:
+ CheckFailed("tags must be valid attribute names", Call);
+ break;
+ case BundleAttr::Align:
+ Check(OBU.Inputs.size() >= 2 && OBU.Inputs.size() <= 3,
"alignment assumptions should have 2 or 3 arguments", Call);
- Check(Call.getOperand(Elem.Begin)->getType()->isPointerTy(),
- "first argument should be a pointer", Call);
- Check(Call.getOperand(Elem.Begin + 1)->getType()->isIntegerTy(),
+ Check(GetTypeAt(0)->isPointerTy(), "first argument should be a pointer",
+ Call);
+ Check(GetTypeAt(1)->isIntegerTy(),
"second argument should be an integer", Call);
- if (ArgCount == 3)
- Check(Call.getOperand(Elem.Begin + 2)->getType()->isIntegerTy(),
- "third argument should be an integer if present", Call);
- continue;
- }
- if (Kind == Attribute::Dereferenceable) {
- Check(ArgCount == 2,
+ Check(OBU.Inputs.size() < 3 || GetTypeAt(2)->isIntegerTy(),
+ "third argument should be an integer if present", Call);
+ break;
+ case BundleAttr::Cold:
+ Check(OBU.Inputs.size() == 0,
+ "cold assumptions should have no arguments", Call);
+ break;
+ case BundleAttr::Dereferenceable:
+ case BundleAttr::DereferenceableOrNull:
+ Check(OBU.Inputs.size() == 2,
"dereferenceable assumptions should have 2 arguments", Call);
- Check(Call.getOperand(Elem.Begin)->getType()->isPointerTy(),
- "first argument should be a pointer", Call);
- Check(Call.getOperand(Elem.Begin + 1)->getType()->isIntegerTy(),
+ Check(GetTypeAt(0)->isPointerTy(), "first argument should be a pointer",
+ Call);
+ Check(GetTypeAt(1)->isIntegerTy(),
"second argument should be an integer", Call);
- continue;
- }
- Check(ArgCount <= 2, "too many arguments", Call);
- if (Kind == Attribute::None)
break;
- if (Attribute::isIntAttrKind(Kind)) {
- Check(ArgCount == 2, "this attribute should have 2 arguments", Call);
- Check(isa<ConstantInt>(Call.getOperand(Elem.Begin + 1)),
- "the second argument should be a constant integral value", Call);
- } else if (Attribute::canUseAsParamAttr(Kind)) {
- Check((ArgCount) == 1, "this attribute should have one argument", Call);
- } else if (Attribute::canUseAsFnAttr(Kind)) {
- Check((ArgCount) == 0, "this attribute has no argument", Call);
+ case BundleAttr::Ignore:
+ break;
+ case BundleAttr::NonNull:
+ Check(OBU.Inputs.size() == 1,
+ "nonnull assumptions should have 1 argument", Call);
+ Check(GetTypeAt(0)->isPointerTy(), "first argument should be a pointer",
+ Call);
+ break;
+ case BundleAttr::NoUndef:
+ Check(OBU.Inputs.size() == 1,
+ "noundef assumptions should have 1 argument", Call);
+ break;
+ case BundleAttr::SeparateStorage:
+ Check(OBU.Inputs.size() == 2,
+ "separate_storage assumptions should have 2 arguments", Call);
+ Check(GetTypeAt(0)->isPointerTy() && GetTypeAt(1)->isPointerTy(),
+ "arguments to separate_storage assumptions should be pointers",
+ Call);
+ break;
}
}
break;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 2a8bf3ffecd6f..3ee5d65f7f8b7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -31,6 +31,7 @@
#include "llvm/IR/AttributeMask.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/BundleAttributes.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
@@ -3621,66 +3622,48 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
return eraseInstFromFunction(*II);
}
- for (unsigned Idx = 0; Idx < II->getNumOperandBundles(); Idx++) {
- OperandBundleUse OBU = II->getOperandBundleAt(Idx);
+ for (auto OBU : II->operand_bundles()) {
+ switch (getBundleAttrFromOBU(OBU)) {
+ case BundleAttr::None:
+ llvm_unreachable("Unexpected Attribute");
+ case BundleAttr::Align: {
+ // Try to remove redundant alignment assumptions.
+ auto [Ptr, Alignment, Offset] = getAssumeAlignInfo(OBU);
- // Separate storage assumptions apply to the underlying allocations, not
- // any particular pointer within them. When evaluating the hints for AA
- // purposes we getUnderlyingObject them; by precomputing the answers here
- // we can avoid having to do so repeatedly there.
- if (OBU.getTagName() == "separate_storage") {
- assert(OBU.Inputs.size() == 2);
- auto MaybeSimplifyHint = [&](const Use &U) {
- Value *Hint = U.get();
- // Not having a limit is safe because InstCombine removes unreachable
- // code.
- Value *UnderlyingObject = getUnderlyingObject(Hint, /*MaxLookup*/ 0);
- if (Hint != UnderlyingObject)
- replaceUse(const_cast<Use &>(U), UnderlyingObject);
- };
- MaybeSimplifyHint(OBU.Inputs[0]);
- MaybeSimplifyHint(OBU.Inputs[1]);
- }
-
- // Try to remove redundant alignment assumptions.
- if (OBU.getTagName() == "align" && OBU.Inputs.size() == 2) {
- RetainedKnowledge RK = getKnowledgeFromOperandInAssume(
- *cast<AssumeInst>(II), II->arg_size() + Idx);
- if (!RK || RK.AttrKind != Attribute::Alignment ||
- !isPowerOf2_64(RK.ArgValue) || !isa<ConstantInt>(RK.IRArgValue))
- continue;
+ if (Offset || !isa<ConstantInt>(Alignment))
+ break;
+ auto AlignVal = cast<ConstantInt>(Alignment)->getZExtValue();
+ if (!isPowerOf2_64(AlignVal))
+ break;
// Remove align 1 bundles; they don't add any useful information.
- if (RK.ArgValue == 1)
+ if (AlignVal == 1)
return CallBase::removeOperandBundle(II, OBU.getTagID());
// Don't try to remove align assumptions for pointers derived from
// arguments. We might lose information if the function gets inline and
// the align argument attribute disappears.
- Value *UO = getUnderlyingObject(RK.WasOn);
+ Value *UO = getUnderlyingObject(Ptr);
if (!UO || isa<Argument>(UO))
- continue;
+ break;
// Compute known bits for the pointer and drop the assume if the
// known alignment isn't increased by it.
- if ((1ULL << computeKnownBits(RK.WasOn, II).countMinTrailingZeros()) <
- RK.ArgValue)
- continue;
+ if ((1ULL << computeKnownBits(Ptr, II).countMinTrailingZeros()) <
+ AlignVal)
+ break;
return CallBase::removeOperandBundle(II, OBU.getTagID());
}
- if (OBU.getTagName() == "nonnull" && OBU.Inputs.size() == 1) {
- RetainedKnowledge RK = getKnowledgeFromOperandInAssume(
- *cast<AssumeInst>(II), II->arg_size() + Idx);
- if (!RK || RK.AttrKind != Attribute::NonNull)
- continue;
+ case BundleAttr::NonNull: {
+ auto [Ptr] = llvm::getAssumeNonNullInfo(OBU);
// Drop assume if we can prove nonnull without it
- if (isKnownNonZero(RK.WasOn, getSimplifyQuery().getWithInstruction(II)))
+ if (isKnownNonZero(Ptr, getSimplifyQuery().getWithInstruction(II)))
return CallBase::removeOperandBundle(II, OBU.getTagID());
// Fold the assume into metadata if it's valid at the load
- if (auto *LI = dyn_cast<LoadInst>(RK.WasOn);
+ if (auto *LI = dyn_cast<LoadInst>(Ptr);
LI &&
isValidAssumeForContext(II, LI, &DT, /*AllowEphemerals=*/true)) {
MDNode *MD = MDNode::get(II->getContext(), {});
@@ -3690,6 +3673,37 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
}
// TODO: apply nonnull return attributes to calls and invokes
+ break;
+ }
+
+ case BundleAttr::SeparateStorage: {
+ auto [Ptr1, Ptr2] = getAssumeSeparateStorageInfo(OBU);
+ // Separate storage assumptions apply to the underlying allocations, not
+ // any particular pointer within them. When evaluating the hints for AA
+ // purposes we getUnderlyingObject them; by precomputing the answers
+ // here we can avoid having to do so repeatedly there.
+ auto MaybeSimplifyHint = [&](const Use &U) {
+ Value *Hint = U.get();
+ // Not having a limit is safe because InstCombine removes unreachable
+ // code.
+ Value *UnderlyingObject = getUnderlyingObject(Hint, /*MaxLookup*/ 0);
+ if (Hint != UnderlyingObject)
+ replaceUse(const_cast<Use &>(U), UnderlyingObject);
+ };
+ MaybeSimplifyHint(*Ptr1);
+ MaybeSimplifyHint(*Ptr2);
+ } break;
+
+ // TODO: Drop these assumes when they are redundant
+ case BundleAttr::Dereferenceable:
+ case BundleAttr::DereferenceableOrNull:
+ case BundleAttr::Ignore:
+ case BundleAttr::NoUndef:
+ break;
+
+ // This cannot be simplified
+ case BundleAttr::Cold:
+ break;
}
}
diff --git a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
index 26bca70e1056f..722d04c9ae957 100644
--- a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
+++ b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
@@ -20,18 +20,12 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/DebugCounter.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace llvm;
namespace llvm {
-LLVM_ABI cl::opt<bool> ShouldPreserveAllAttributes(
- "assume-preserve-all", cl::init(false), cl::Hidden,
- cl::desc("enable preservation of all attributes. even those that are "
- "unlikely to be useful"));
-
cl::opt<bool> EnableKnowledgeRetention(
"enable-knowledge-retention", cl::init(false), cl::Hidden,
cl::desc(
@@ -193,8 +187,7 @@ struct AssumeBuilderState {
void addAttribute(Attribute Attr, Value *WasOn) {
if (Attr.isTypeAttribute() || Attr.isStringAttribute() ||
- (!ShouldPreserveAllAttributes &&
- !isUsefullToPreserve(Attr.getKindAsEnum())))
+ !isUsefullToPreserve(Attr.getKindAsEnum()))
return;
uint64_t AttrArg = 0;
if (Attr.isIntAttribute())
diff --git a/llvm/lib/Transforms/Utils/PredicateInfo.cpp b/llvm/lib/Transforms/Utils/PredicateInfo.cpp
index 3d3c70522fb55..7a86d310f0f93 100644
--- a/llvm/lib/Transforms/Utils/PredicateInfo.cpp
+++ b/llvm/lib/Transforms/Utils/PredicateInfo.cpp
@@ -17,6 +17,7 @@
#include "llvm/Analysis/AssumeBundleQueries.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/IR/AssemblyAnnotationWriter.h"
+#include "llvm/IR/BundleAttributes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
@@ -363,12 +364,12 @@ void PredicateInfoBuilder::processAssume(
AssumeInst *II, BasicBlock *AssumeBB,
SmallVectorImpl<Value *> &OpsToRename) {
if (II->hasOperandBundles()) {
- for (auto BOI : II->bundle_op_infos()) {
- if (RetainedKnowledge RK = getKnowledgeFromBundle(*II, BOI)) {
- if (RK.AttrKind == Attribute::NonNull && shouldRename(RK.WasOn))
- addInfoFor(OpsToRename, RK.WasOn,
- new (Allocator) PredicateBundleAssume(RK.WasOn, II,
- Attribute::NonNull));
+ for (auto OBU : II->operand_bundles()) {
+ if (getBundleAttrFromOBU(OBU) == BundleAttr::NonNull) {
+ if (auto [Ptr] = getAssumeNonNullInfo(OBU); shouldRename(Ptr))
+ addInfoFor(OpsToRename, Ptr,
+ new (Allocator)
+ PredicateBundleAssume(Ptr, II, BundleAttr::NonNull));
}
}
return;
@@ -724,7 +725,7 @@ PredicateInfo::PredicateInfo(Function &F, DominatorTree &DT,
std::optional<PredicateConstraint> PredicateBase::getConstraint() const {
switch (Type) {
case PT_BundleAssume: {
- assert(cast<PredicateBundleAssume>(this)->AttrKind == Attribute::NonNull &&
+ assert(cast<PredicateBundleAssume>(this)->AttrKind == BundleAttr::NonNull &&
"Cannot handle anything other than NonNull");
return {{CmpInst::ICMP_NE, ConstantPointerNull::get(
cast<PointerType>(OriginalOp->getType()))}};
@@ -844,7 +845,7 @@ class PredicateInfoAnnotatedWriter : public AssemblyAnnotationWriter {
} else if (const auto *PA = dyn_cast<PredicateAssume>(PI)) {
OS << "; assume predicate info {";
if (auto *PBA = dyn_cast<PredicateBundleAssume>(PA)) {
- OS << " Attribute: " << Attribute::getNameFromAttrKind(PBA->AttrKind);
+ OS << " Attribute: " << getNameFromBundleAttr(PBA->AttrKind);
} else {
assert(isa<PredicateConditionAssume>(PA));
OS << " Comparison:" << *PA->Condition;
diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll
index 788558638a5d2..7a6c9542fa055 100644
--- a/llvm/test/Transforms/Attributor/nofpclass.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass.ll
@@ -647,34 +647,6 @@ entry:
ret half %arg
}
-define float @assume_bundles(i1 %c, float %ret) {
-; CHECK-LABEL: define float @assume_bundles
-; CHECK-SAME: (i1 noundef [[C:%.*]], float returned [[RET:%.*]]) {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
-; CHECK: A:
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR22]] [ "nofpclass"(float [[RET]], i32 3) ]
-; CHECK-NEXT: call void @extern.use(float nofpclass(nan) [[RET]])
-; CHECK-NEXT: ret float [[RET]]
-; CHECK: B:
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "nofpclass"(float [[RET]], i32 12) ]
-; CHECK-NEXT: call void @extern.use(float nofpclass(ninf nnorm) [[RET]])
-; CHECK-NEXT: ret float [[RET]]
-;
-entry:
- br i1 %c, label %A, label %B
-
-A:
- call void @llvm.assume(i1 true) [ "nofpclass"(float %ret, i32 3) ]
- call void @extern.use(float %ret)
- ret float %ret
-
-B:
- call void @llvm.assume(i1 true) [ "nofpclass"(float %ret, i32 12) ]
- call void @extern.use(float %ret)
- ret float %ret
-}
-
define float @returned_load(ptr %ptr) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CHECK-LABEL: define float @returned_load
diff --git a/llvm/test/Transforms/Attributor/nofree.ll b/llvm/test/Transforms/Attributor/nofree.ll
index 94aa79aa327f4..6937238dc8c3c 100644
--- a/llvm/test/Transforms/Attributor/nofree.ll
+++ b/llvm/test/Transforms/Attributor/nofree.ll
@@ -343,85 +343,6 @@ define void @test14(ptr nocapture %0, ptr nocapture %1) {
; UTC_ARGS: --enable
-define void @nonnull_assume_pos(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {
-; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_pos
-; ATTRIBUTOR-SAME: (ptr nofree [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr nofree [[ARG3:%.*]], ptr [[ARG4:%.*]])
-; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) #11 [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; ATTRIBUTOR-NEXT: call void @unknown(ptr nofree [[ARG1]], ptr [[ARG2]], ptr nofree [[ARG3]], ptr [[ARG4]])
-; ATTRIBUTOR-NEXT: ret void
-;
-; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_pos
-; CHECK-SAME: (ptr nofree [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr nofree [[ARG3:%.*]], ptr [[ARG4:%.*]]) {
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR15:[0-9]+]] [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; CHECK-NEXT: call void @unknown(ptr nofree [[ARG1]], ptr [[ARG2]], ptr nofree [[ARG3]], ptr [[ARG4]])
-; CHECK-NEXT: ret void
-;
- call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)]
- call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4)
- ret void
-}
-define void @nonnull_assume_neg(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {
-; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_neg
-; ATTRIBUTOR-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]])
-; ATTRIBUTOR-NEXT: call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]])
-; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; ATTRIBUTOR-NEXT: ret void
-;
-; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg
-; CHECK-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]]) {
-; CHECK-NEXT: call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]])
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; CHECK-NEXT: ret void
-;
- call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4)
- call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)]
- ret void
-}
-define void @nonnull_assume_call(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {
-; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_call
-; ATTRIBUTOR-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]])
-; ATTRIBUTOR-NEXT: call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]])
-; ATTRIBUTOR-NEXT: call void @use_i8_ptr(ptr noalias readnone [[ARG1]])
-; ATTRIBUTOR-NEXT: call void @use_i8_ptr(ptr noalias readnone [[ARG2]])
-; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; ATTRIBUTOR-NEXT: call void @use_i8_ptr(ptr noalias nofree readnone [[ARG3]])
-; ATTRIBUTOR-NEXT: call void @use_i8_ptr(ptr noalias readnone [[ARG4]])
-; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG1]])
-; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(ptr noalias readnone [[ARG2]])
-; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG4]]) ]
-; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG3]])
-; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG4]])
-; ATTRIBUTOR-NEXT: ret void
-;
-; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_call
-; CHECK-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]]) {
-; CHECK-NEXT: call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]])
-; CHECK-NEXT: call void @use_i8_ptr(ptr noalias nofree readnone captures(none) [[ARG1]]) #[[ATTR0]]
-; CHECK-NEXT: call void @use_i8_ptr(ptr noalias nofree readnone captures(none) [[ARG2]]) #[[ATTR0]]
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; CHECK-NEXT: call void @use_i8_ptr(ptr noalias nofree readnone captures(none) [[ARG3]]) #[[ATTR0]]
-; CHECK-NEXT: call void @use_i8_ptr(ptr noalias nofree readnone captures(none) [[ARG4]]) #[[ATTR0]]
-; CHECK-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone captures(none) [[ARG1]]) #[[ATTR0]]
-; CHECK-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone captures(none) [[ARG2]]) #[[ATTR0]]
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG4]]) ]
-; CHECK-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone captures(none) [[ARG3]]) #[[ATTR0]]
-; CHECK-NEXT: call void @use_i8_ptr_ret(ptr noalias nofree readnone captures(none) [[ARG4]]) #[[ATTR0]]
-; CHECK-NEXT: ret void
-;
- call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4)
- call void @use_i8_ptr(ptr %arg1)
- call void @use_i8_ptr(ptr %arg2)
- call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)]
- call void @use_i8_ptr(ptr %arg3)
- call void @use_i8_ptr(ptr %arg4)
- call void @use_i8_ptr_ret(ptr %arg1)
- call void @use_i8_ptr_ret(ptr %arg2)
- call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg4)]
- call void @use_i8_ptr_ret(ptr %arg3)
- call void @use_i8_ptr_ret(ptr %arg4)
- ret void
-}
-
; FIXME: function is nofree
define weak void @implied_nofree1() readnone {
; CHECK: Function Attrs: nosync memory(none)
@@ -498,7 +419,6 @@ attributes #2 = { nobuiltin nounwind }
; TUNIT: attributes #[[ATTR12:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
; TUNIT: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn }
; TUNIT: attributes #[[ATTR14]] = { nofree nosync willreturn }
-; TUNIT: attributes #[[ATTR15]] = { nofree willreturn memory(write) }
;.
; CGSCC: attributes #[[ATTR0]] = { nounwind }
; CGSCC: attributes #[[ATTR1]] = { noinline nounwind uwtable }
@@ -515,5 +435,4 @@ attributes #2 = { nobuiltin nounwind }
; CGSCC: attributes #[[ATTR12:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
; CGSCC: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn }
; CGSCC: attributes #[[ATTR14]] = { nofree nosync willreturn }
-; CGSCC: attributes #[[ATTR15]] = { nofree willreturn memory(write) }
;.
diff --git a/llvm/test/Transforms/Coroutines/coro-split-musttail-chain-pgo-counter-promo.ll b/llvm/test/Transforms/Coroutines/coro-split-musttail-chain-pgo-counter-promo.ll
index 70f15f6129d8e..f176ef59d64b5 100644
--- a/llvm/test/Transforms/Coroutines/coro-split-musttail-chain-pgo-counter-promo.ll
+++ b/llvm/test/Transforms/Coroutines/coro-split-musttail-chain-pgo-counter-promo.ll
@@ -2,14 +2,14 @@
; RUN: opt -passes='pgo-instr-gen,instrprof,coro-split' -do-counter-promotion=true -S < %s | FileCheck %s
; CHECK-LABEL: define internal fastcc void @f.resume
-; CHECK: musttail call fastcc void
+; CHECK: musttail call fastcc void
; CHECK-NEXT: ret void
-; CHECK: musttail call fastcc void
+; CHECK: musttail call fastcc void
; CHECK-NEXT: ret void
; CHECK-LABEL: define internal fastcc void @f.destroy
target triple = "x86_64-grtev4-linux-gnu"
-%CoroutinePromise = type { ptr, i64, [8 x i8], ptr}
+%CoroutinePromise = type { ptr, i64, [8 x i8], ptr}
%Awaitable.1 = type { ptr }
%Awaitable.2 = type { ptr, ptr }
diff --git a/llvm/test/Transforms/InstCombine/test.ll b/llvm/test/Transforms/InstCombine/test.ll
new file mode 100644
index 0000000000000..c5b859e19f486
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/test.ll
@@ -0,0 +1,38 @@
+
+define void @f2(ptr %a) {
+; CHECK-LABEL: @f2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A:%.*]], i64 32, i32 24) ]
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 8
+; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[TMP0]] to i64
+; CHECK-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 8
+; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0
+; CHECK-NEXT: br i1 [[TMP3]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: store i64 16, ptr [[TMP0]], align 4
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: store i8 1, ptr [[TMP0]], align 1
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: ret void
+;
+entry:
+ call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 32, i32 24) ]
+ %0 = getelementptr inbounds i8, ptr %a, i64 8
+ %1 = ptrtoint ptr %0 to i64
+ %2 = and i64 %1, 15
+ %3 = icmp eq i64 %2, 0
+ br i1 %3, label %if.then, label %if.else
+
+if.then: ; preds = %entry
+ store i64 16, ptr %0, align 4
+ br label %if.end
+
+if.else: ; preds = %entry
+ store i8 1, ptr %0, align 1
+ br label %if.end
+
+if.end: ; preds = %if.else, %if.then
+ ret void
+}
diff --git a/llvm/test/Transforms/Util/assume-builder.ll b/llvm/test/Transforms/Util/assume-builder.ll
index 98ff2a4827d61..d5fc4ef57015d 100644
--- a/llvm/test/Transforms/Util/assume-builder.ll
+++ b/llvm/test/Transforms/Util/assume-builder.ll
@@ -1,6 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
; RUN: opt -passes='assume-builder,verify' --enable-knowledge-retention -S %s | FileCheck %s --check-prefixes=BASIC
-; RUN: opt -passes='assume-builder,verify' --enable-knowledge-retention --assume-preserve-all -S %s | FileCheck %s --check-prefixes=ALL
; RUN: opt -passes='require<assumptions>,assume-builder,verify' --enable-knowledge-retention -S %s | FileCheck %s --check-prefixes=WITH-AC
; RUN: opt -passes='require<domtree>,require<assumptions>,assume-builder,verify' --enable-knowledge-retention -S %s | FileCheck %s --check-prefixes=CROSS-BLOCK
; RUN: opt -passes='assume-builder,require<domtree>,require<assumptions>,assume-simplify,verify' --enable-knowledge-retention -S %s | FileCheck %s --check-prefixes=FULL-SIMPLIFY
@@ -47,34 +46,6 @@ define void @test(ptr %P, ptr %P1, ptr %P2, ptr %P3) {
; BASIC-NEXT: call void @func(ptr noundef nonnull [[P1]], ptr noundef nonnull [[P]])
; BASIC-NEXT: ret void
;
-; ALL-LABEL: define {{[^@]+}}@test
-; ALL-SAME: (ptr [[P:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]], ptr [[P3:%.*]]) {
-; ALL-NEXT: bb:
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[P]]), "dereferenceable"(ptr [[P]], i64 16) ]
-; ALL-NEXT: call void @func(ptr nonnull dereferenceable(16) [[P]], ptr null)
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P1]], i64 12) ]
-; ALL-NEXT: call void @func(ptr dereferenceable(12) [[P1]], ptr nonnull [[P]])
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "cold"(), "nounwind"(), "willreturn"() ]
-; ALL-NEXT: call void @func_cold(ptr dereferenceable(12) [[P1]]) #[[ATTR6:[0-9]+]]
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "cold"(), "nounwind"(), "willreturn"() ]
-; ALL-NEXT: call void @func_cold(ptr dereferenceable(12) [[P1]])
-; ALL-NEXT: call void @func(ptr [[P1]], ptr [[P]])
-; ALL-NEXT: call void @func_strbool(ptr [[P1]])
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 32) ]
-; ALL-NEXT: call void @func(ptr dereferenceable(32) [[P]], ptr dereferenceable(8) [[P]])
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "norecurse"(), "nounwind"(), "willreturn"() ]
-; ALL-NEXT: call void @func_many(ptr align 8 [[P1]])
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "noundef"(ptr [[P1]]), "align"(ptr [[P1]], i64 8), "norecurse"(), "nounwind"(), "willreturn"() ]
-; ALL-NEXT: call void @func_many(ptr noundef align 8 [[P1]])
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "nounwind"() ]
-; ALL-NEXT: call void @func_argattr(ptr [[P2]], ptr [[P3]])
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "noundef"(ptr [[P2]]), "align"(ptr [[P2]], i64 8), "noundef"(ptr [[P3]]), "nonnull"(ptr [[P3]]), "nounwind"() ]
-; ALL-NEXT: call void @func_argattr2(ptr [[P2]], ptr [[P3]])
-; ALL-NEXT: call void @func(ptr nonnull [[P1]], ptr nonnull [[P]])
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[P1]]), "noundef"(ptr [[P]]) ]
-; ALL-NEXT: call void @func(ptr noundef nonnull [[P1]], ptr noundef nonnull [[P]])
-; ALL-NEXT: ret void
-;
; WITH-AC-LABEL: define {{[^@]+}}@test
; WITH-AC-SAME: (ptr [[P:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]], ptr [[P3:%.*]]) {
; WITH-AC-NEXT: bb:
@@ -201,38 +172,6 @@ define i32 @test2(ptr %arg, ptr %arg1, ptr %arg2) {
; BASIC-NEXT: [[I26:%.*]] = add nsw i32 [[I21]], [[I25]]
; BASIC-NEXT: ret i32 [[I26]]
;
-; ALL-LABEL: define {{[^@]+}}@test2
-; ALL-SAME: (ptr [[ARG:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) {
-; ALL-NEXT: bb:
-; ALL-NEXT: [[I:%.*]] = alloca ptr, align 8
-; ALL-NEXT: [[I3:%.*]] = alloca ptr, align 8
-; ALL-NEXT: [[I4:%.*]] = alloca ptr, align 8
-; ALL-NEXT: [[I5:%.*]] = alloca [[STRUCT_S:%.*]], align 8
-; ALL-NEXT: store ptr [[ARG]], ptr [[I]], align 8
-; ALL-NEXT: store ptr [[ARG1]], ptr [[I3]], align 8
-; ALL-NEXT: store ptr [[ARG2]], ptr [[I4]], align 8
-; ALL-NEXT: [[I6:%.*]] = load ptr, ptr [[I3]], align 8
-; ALL-NEXT: [[I7:%.*]] = load i32, ptr [[I6]], align 4
-; ALL-NEXT: [[I8:%.*]] = trunc i32 [[I7]] to i8
-; ALL-NEXT: [[I9:%.*]] = load ptr, ptr [[I4]], align 8
-; ALL-NEXT: store i8 [[I8]], ptr [[I9]], align 1
-; ALL-NEXT: [[I11:%.*]] = load ptr, ptr [[I]], align 8
-; ALL-NEXT: [[I14:%.*]] = load ptr, ptr [[I]], align 8
-; ALL-NEXT: [[I16:%.*]] = load i32, ptr [[I14]], align 8
-; ALL-NEXT: [[I17:%.*]] = load ptr, ptr [[I]], align 8
-; ALL-NEXT: [[I18:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[I17]], i32 0, i32 1
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[I17]], i64 5), "nonnull"(ptr [[I17]]), "align"(ptr [[I17]], i64 4) ]
-; ALL-NEXT: [[I19:%.*]] = load i8, ptr [[I18]], align 4
-; ALL-NEXT: [[I20:%.*]] = sext i8 [[I19]] to i32
-; ALL-NEXT: [[I21:%.*]] = add nsw i32 [[I16]], [[I20]]
-; ALL-NEXT: [[I22:%.*]] = load ptr, ptr [[I]], align 8
-; ALL-NEXT: [[I23:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[I22]], i32 0, i32 2
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[I22]], i64 16), "nonnull"(ptr [[I22]]), "align"(ptr [[I22]], i64 8) ]
-; ALL-NEXT: [[I24:%.*]] = load ptr, ptr [[I23]], align 8
-; ALL-NEXT: [[I25:%.*]] = load i32, ptr [[I24]], align 4
-; ALL-NEXT: [[I26:%.*]] = add nsw i32 [[I21]], [[I25]]
-; ALL-NEXT: ret i32 [[I26]]
-;
; WITH-AC-LABEL: define {{[^@]+}}@test2
; WITH-AC-SAME: (ptr [[ARG:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) {
; WITH-AC-NEXT: bb:
@@ -391,39 +330,6 @@ define i32 @test3(ptr %arg, ptr %arg1, ptr %arg2) #4 {
; BASIC-NEXT: [[I26:%.*]] = add nsw i32 [[I21]], [[I25]]
; BASIC-NEXT: ret i32 [[I26]]
;
-; ALL-LABEL: define {{[^@]+}}@test3
-; ALL-SAME: (ptr [[ARG:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #[[ATTR4:[0-9]+]] {
-; ALL-NEXT: bb:
-; ALL-NEXT: [[I:%.*]] = alloca ptr, align 8
-; ALL-NEXT: [[I3:%.*]] = alloca ptr, align 8
-; ALL-NEXT: [[I4:%.*]] = alloca ptr, align 8
-; ALL-NEXT: [[I5:%.*]] = alloca [[STRUCT_S:%.*]], align 8
-; ALL-NEXT: store ptr [[ARG]], ptr [[I]], align 8
-; ALL-NEXT: store ptr [[ARG1]], ptr [[I3]], align 8
-; ALL-NEXT: store ptr [[ARG2]], ptr [[I4]], align 8
-; ALL-NEXT: [[I6:%.*]] = load ptr, ptr [[I3]], align 8
-; ALL-NEXT: [[I7:%.*]] = load i32, ptr [[I6]], align 4
-; ALL-NEXT: [[I8:%.*]] = trunc i32 [[I7]] to i8
-; ALL-NEXT: [[I9:%.*]] = load ptr, ptr [[I4]], align 8
-; ALL-NEXT: store i8 [[I8]], ptr [[I9]], align 1
-; ALL-NEXT: [[I11:%.*]] = load ptr, ptr [[I]], align 32
-; ALL-NEXT: call void @may_throw()
-; ALL-NEXT: [[I14:%.*]] = load ptr, ptr [[I]], align 8
-; ALL-NEXT: [[I16:%.*]] = load i32, ptr [[I14]], align 8
-; ALL-NEXT: [[I17:%.*]] = load ptr, ptr [[I]], align 8
-; ALL-NEXT: [[I18:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[I17]], i32 0, i32 1
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[I17]], i64 5), "align"(ptr [[I17]], i64 4) ]
-; ALL-NEXT: [[I19:%.*]] = load i8, ptr [[I18]], align 8
-; ALL-NEXT: [[I20:%.*]] = sext i8 [[I19]] to i32
-; ALL-NEXT: [[I21:%.*]] = add nsw i32 [[I16]], [[I20]]
-; ALL-NEXT: [[I22:%.*]] = load ptr, ptr [[I]], align 8
-; ALL-NEXT: [[I23:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[I22]], i32 0, i32 2
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[I22]], i64 16), "align"(ptr [[I22]], i64 8) ]
-; ALL-NEXT: [[I24:%.*]] = load ptr, ptr [[I23]], align 8
-; ALL-NEXT: [[I25:%.*]] = load i32, ptr [[I24]], align 4
-; ALL-NEXT: [[I26:%.*]] = add nsw i32 [[I21]], [[I25]]
-; ALL-NEXT: ret i32 [[I26]]
-;
; WITH-AC-LABEL: define {{[^@]+}}@test3
; WITH-AC-SAME: (ptr [[ARG:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #[[ATTR4:[0-9]+]] {
; WITH-AC-NEXT: bb:
@@ -577,30 +483,6 @@ define dso_local i32 @_Z6squarePi(ptr %P, ptr %P1, i1 %cond) {
; BASIC-NEXT: store i32 0, ptr [[P1]], align 4
; BASIC-NEXT: ret i32 0
;
-; ALL-LABEL: define {{[^@]+}}@_Z6squarePi
-; ALL-SAME: (ptr [[P:%.*]], ptr [[P1:%.*]], i1 [[COND:%.*]]) {
-; ALL-NEXT: bb:
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
-; ALL-NEXT: store i32 0, ptr [[P]], align 4
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P1]], i64 4), "nonnull"(ptr [[P1]]), "align"(ptr [[P1]], i64 8) ]
-; ALL-NEXT: store i32 0, ptr [[P1]], align 8
-; ALL-NEXT: br i1 [[COND]], label [[A:%.*]], label [[B:%.*]]
-; ALL: A:
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P]], i64 8) ]
-; ALL-NEXT: store i32 0, ptr [[P]], align 8
-; ALL-NEXT: store i32 0, ptr [[P1]], align 4
-; ALL-NEXT: br i1 [[COND]], label [[C:%.*]], label [[B]]
-; ALL: B:
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P]], i64 8) ]
-; ALL-NEXT: store i32 0, ptr [[P]], align 8
-; ALL-NEXT: store i32 0, ptr [[P1]], align 8
-; ALL-NEXT: br label [[C]]
-; ALL: C:
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P]], i64 32) ]
-; ALL-NEXT: store i32 0, ptr [[P]], align 32
-; ALL-NEXT: store i32 0, ptr [[P1]], align 4
-; ALL-NEXT: ret i32 0
-;
; WITH-AC-LABEL: define {{[^@]+}}@_Z6squarePi
; WITH-AC-SAME: (ptr [[P:%.*]], ptr [[P1:%.*]], i1 [[COND:%.*]]) {
; WITH-AC-NEXT: bb:
@@ -714,27 +596,6 @@ define dso_local i32 @test4A(ptr %arg, ptr %arg1, i32 %arg2, i32 %arg3) {
; BASIC: bb10:
; BASIC-NEXT: ret i32 0
;
-; ALL-LABEL: define {{[^@]+}}@test4A
-; ALL-SAME: (ptr [[ARG:%.*]], ptr [[ARG1:%.*]], i32 [[ARG2:%.*]], i32 [[ARG3:%.*]]) {
-; ALL-NEXT: bb:
-; ALL-NEXT: [[I:%.*]] = icmp ne ptr [[ARG1]], null
-; ALL-NEXT: br i1 [[I]], label [[BB4:%.*]], label [[BB10:%.*]]
-; ALL: bb4:
-; ALL-NEXT: [[I5:%.*]] = add nsw i32 [[ARG3]], [[ARG2]]
-; ALL-NEXT: call void @may_throw()
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[ARG]], i64 4), "nonnull"(ptr [[ARG]]), "align"(ptr [[ARG]], i64 4) ]
-; ALL-NEXT: [[I6:%.*]] = load i32, ptr [[ARG]], align 4
-; ALL-NEXT: [[I7:%.*]] = add nsw i32 [[I5]], [[I6]]
-; ALL-NEXT: store i32 0, ptr [[ARG]], align 4
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[ARG1]], i64 4), "nonnull"(ptr [[ARG1]]), "align"(ptr [[ARG1]], i64 4) ]
-; ALL-NEXT: [[I8:%.*]] = load i32, ptr [[ARG1]], align 4
-; ALL-NEXT: [[I9:%.*]] = add nsw i32 [[I7]], [[I8]]
-; ALL-NEXT: call void @may_throw()
-; ALL-NEXT: store i32 [[I9]], ptr [[ARG1]], align 4
-; ALL-NEXT: br label [[BB10]]
-; ALL: bb10:
-; ALL-NEXT: ret i32 0
-;
; WITH-AC-LABEL: define {{[^@]+}}@test4A
; WITH-AC-SAME: (ptr [[ARG:%.*]], ptr [[ARG1:%.*]], i32 [[ARG2:%.*]], i32 [[ARG3:%.*]]) {
; WITH-AC-NEXT: bb:
@@ -833,19 +694,6 @@ define dso_local i32 @terminator(ptr %P) personality ptr @__gxx_personality_v0 {
; BASIC-NEXT: [[DOT0:%.*]] = phi i32 [ 1, [[BB:%.*]] ], [ 0, [[CATCH]] ]
; BASIC-NEXT: ret i32 [[DOT0]]
;
-; ALL-LABEL: define {{[^@]+}}@terminator
-; ALL-SAME: (ptr [[P:%.*]]) personality ptr @__gxx_personality_v0 {
-; ALL-NEXT: bb:
-; ALL-NEXT: invoke void @may_throwv2(ptr nonnull [[P]])
-; ALL-NEXT: to label [[EXIT:%.*]] unwind label [[CATCH:%.*]]
-; ALL: Catch:
-; ALL-NEXT: [[V:%.*]] = landingpad { ptr, i32 }
-; ALL-NEXT: catch ptr null
-; ALL-NEXT: br label [[EXIT]]
-; ALL: Exit:
-; ALL-NEXT: [[DOT0:%.*]] = phi i32 [ 1, [[BB:%.*]] ], [ 0, [[CATCH]] ]
-; ALL-NEXT: ret i32 [[DOT0]]
-;
; WITH-AC-LABEL: define {{[^@]+}}@terminator
; WITH-AC-SAME: (ptr [[P:%.*]]) personality ptr @__gxx_personality_v0 {
; WITH-AC-NEXT: bb:
@@ -918,22 +766,6 @@ define dso_local i32 @test5(ptr %arg, i32 %arg1) {
; BASIC-NEXT: [[I9:%.*]] = trunc i64 [[I8]] to i32
; BASIC-NEXT: ret i32 [[I9]]
;
-; ALL-LABEL: define {{[^@]+}}@test5
-; ALL-SAME: (ptr [[ARG:%.*]], i32 [[ARG1:%.*]]) {
-; ALL-NEXT: bb:
-; ALL-NEXT: [[I3:%.*]] = sext i32 [[ARG1]] to i64
-; ALL-NEXT: [[I4:%.*]] = getelementptr inbounds i16, ptr [[ARG]], i64 [[I3]]
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[I4]], i64 2), "nonnull"(ptr [[ARG]]), "align"(ptr [[ARG]], i64 8) ]
-; ALL-NEXT: [[I5:%.*]] = load i16, ptr [[I4]], align 2
-; ALL-NEXT: [[A:%.*]] = load i16, ptr [[I4]], align 4
-; ALL-NEXT: [[I6:%.*]] = sext i16 [[I5]] to i64
-; ALL-NEXT: [[I7:%.*]] = getelementptr inbounds i64, ptr [[ARG]], i64 [[I6]]
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[I7]], i64 8) ]
-; ALL-NEXT: [[I8:%.*]] = load i64, ptr [[I7]], align 16
-; ALL-NEXT: [[B:%.*]] = load i64, ptr [[I7]], align 32
-; ALL-NEXT: [[I9:%.*]] = trunc i64 [[I8]] to i32
-; ALL-NEXT: ret i32 [[I9]]
-;
; WITH-AC-LABEL: define {{[^@]+}}@test5
; WITH-AC-SAME: (ptr [[ARG:%.*]], i32 [[ARG1:%.*]]) {
; WITH-AC-NEXT: bb:
@@ -1025,36 +857,6 @@ define i32 @test6(ptr %arg, i32 %arg1, ptr %arg2) {
; BASIC-NEXT: [[I18:%.*]] = load i32, ptr [[I17]], align 4
; BASIC-NEXT: ret i32 [[I18]]
;
-; ALL-LABEL: define {{[^@]+}}@test6
-; ALL-SAME: (ptr [[ARG:%.*]], i32 [[ARG1:%.*]], ptr [[ARG2:%.*]]) {
-; ALL-NEXT: bb:
-; ALL-NEXT: br label [[BB3:%.*]]
-; ALL: bb3:
-; ALL-NEXT: [[DOT0:%.*]] = phi i32 [ 0, [[BB:%.*]] ], [ [[I14:%.*]], [[BB4:%.*]] ]
-; ALL-NEXT: [[I:%.*]] = icmp slt i32 [[DOT0]], [[ARG1]]
-; ALL-NEXT: br i1 [[I]], label [[BB4]], label [[BB15:%.*]]
-; ALL: bb4:
-; ALL-NEXT: [[I5:%.*]] = add nsw i32 [[ARG1]], [[DOT0]]
-; ALL-NEXT: [[I6:%.*]] = sext i32 [[I5]] to i64
-; ALL-NEXT: [[I7:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[I6]]
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[ARG]]), "align"(ptr [[ARG]], i64 4) ]
-; ALL-NEXT: [[I8:%.*]] = load i32, ptr [[I7]], align 4
-; ALL-NEXT: [[I9:%.*]] = mul nsw i32 [[DOT0]], [[I8]]
-; ALL-NEXT: [[I10:%.*]] = sext i32 [[DOT0]] to i64
-; ALL-NEXT: [[I11:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[I10]]
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[I11]], i64 4) ]
-; ALL-NEXT: [[I12:%.*]] = load i32, ptr [[I11]], align 4
-; ALL-NEXT: [[I13:%.*]] = add nsw i32 [[I12]], [[I9]]
-; ALL-NEXT: store i32 [[I13]], ptr [[I11]], align 4
-; ALL-NEXT: [[I14]] = add nsw i32 [[DOT0]], 1
-; ALL-NEXT: br label [[BB3]]
-; ALL: bb15:
-; ALL-NEXT: [[I16:%.*]] = sext i32 [[ARG1]] to i64
-; ALL-NEXT: [[I17:%.*]] = getelementptr inbounds i32, ptr [[ARG2]], i64 [[I16]]
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[ARG2]]), "align"(ptr [[ARG2]], i64 4) ]
-; ALL-NEXT: [[I18:%.*]] = load i32, ptr [[I17]], align 4
-; ALL-NEXT: ret i32 [[I18]]
-;
; WITH-AC-LABEL: define {{[^@]+}}@test6
; WITH-AC-SAME: (ptr [[ARG:%.*]], i32 [[ARG1:%.*]], ptr [[ARG2:%.*]]) {
; WITH-AC-NEXT: bb:
@@ -1193,25 +995,6 @@ define i32 @test7(ptr nonnull %arg, i32 %arg1) {
; BASIC-NEXT: [[I11:%.*]] = load i32, ptr [[I10]], align 4
; BASIC-NEXT: ret i32 [[I11]]
;
-; ALL-LABEL: define {{[^@]+}}@test7
-; ALL-SAME: (ptr nonnull [[ARG:%.*]], i32 [[ARG1:%.*]]) {
-; ALL-NEXT: bb:
-; ALL-NEXT: [[I:%.*]] = sext i32 [[ARG1]] to i64
-; ALL-NEXT: [[I2:%.*]] = getelementptr inbounds [[STRUCT_A:%.*]], ptr [[ARG]], i64 0, i32 3
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[ARG]], i64 280), "align"(ptr [[ARG]], i64 16) ]
-; ALL-NEXT: [[I3:%.*]] = load i64, ptr [[I2]], align 8
-; ALL-NEXT: [[I4:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[ARG]], i64 0, i32 2, i64 [[I]], i64 [[I3]], i32 0
-; ALL-NEXT: [[I5:%.*]] = load i64, ptr [[I4]], align 32
-; ALL-NEXT: [[I6:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[ARG]], i64 0, i32 1
-; ALL-NEXT: [[I7:%.*]] = load ptr, ptr [[I6]], align 8
-; ALL-NEXT: [[I8:%.*]] = getelementptr inbounds i64, ptr [[I7]], i64 [[I3]]
-; ALL-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[I8]], i64 8), "nonnull"(ptr [[I7]]), "align"(ptr [[I7]], i64 8) ]
-; ALL-NEXT: store i64 [[I5]], ptr [[I8]], align 8
-; ALL-NEXT: store i64 [[I5]], ptr [[I8]], align 8
-; ALL-NEXT: [[I10:%.*]] = load ptr, ptr [[ARG]], align 8
-; ALL-NEXT: [[I11:%.*]] = load i32, ptr [[I10]], align 4
-; ALL-NEXT: ret i32 [[I11]]
-;
; WITH-AC-LABEL: define {{[^@]+}}@test7
; WITH-AC-SAME: (ptr nonnull [[ARG:%.*]], i32 [[ARG1:%.*]]) {
; WITH-AC-NEXT: bb:
diff --git a/llvm/test/Verifier/assume-bundles.ll b/llvm/test/Verifier/assume-bundles.ll
index 728b118c99fb6..18d04b978d013 100644
--- a/llvm/test/Verifier/assume-bundles.ll
+++ b/llvm/test/Verifier/assume-bundles.ll
@@ -7,32 +7,85 @@ define void @func(ptr %P, i32 %P1, ptr %P2, ptr %P3, i1 %cond) {
; CHECK: tags must be valid attribute names
; CHECK: "adazdazd"
call void @llvm.assume(i1 true) ["adazdazd"()]
+; CHECK: assume with operand bundles must have i1 true condition
+ call void @llvm.assume(i1 %cond) ["nonnull"(ptr %P)]
+
+; Align checks
+;
+; CHECK: alignment assumptions should have 2 or 3 arguments
+ call void @llvm.assume(i1 true) ["align"(ptr %P)]
+; This one is valid
+ call void @llvm.assume(i1 true) ["align"(ptr %P, i32 %P1)]
+; This one is valid
+ call void @llvm.assume(i1 true) ["align"(ptr %P, i32 %P1, i32 4)]
+; CHECK: alignment assumptions should have 2 or 3 arguments
+ call void @llvm.assume(i1 true) ["align"(ptr %P, i32 %P1, i32 4, i32 4)]
+; CHECK: first argument should be a pointer
+ call void @llvm.assume(i1 true) ["align"(i32 %P1, ptr %P2)]
+; CHECK: second argument should be an integer
+ call void @llvm.assume(i1 true) ["align"(ptr %P, ptr %P2)]
+; CHECK: third argument should be an integer if present
+ call void @llvm.assume(i1 true) ["align"(ptr %P, i32 %P1, ptr %P2)]
+
+; Cold checks
+;
+; CHECK: cold assumptions should have no arguments
+ call void @llvm.assume(i1 true) ["cold"(ptr %P)]
+
+; Dereferenceable checks
+;
; CHECK-NOT: call{{.+}}deref
call void @llvm.assume(i1 true) ["dereferenceable"(ptr %P, i32 %P1)]
+; CHECK: first argument should be a pointer
+ call void @llvm.assume(i1 true) ["dereferenceable"(i32 %P1, i32 %P1)]
; CHECK: second argument should be an integer
call void @llvm.assume(i1 true) ["dereferenceable"(ptr %P, float 1.5)]
; CHECK: dereferenceable assumptions should have 2 arguments
call void @llvm.assume(i1 true) ["dereferenceable"(ptr %P, i32 8, i32 8)]
; CHECK: dereferenceable assumptions should have 2 arguments
call void @llvm.assume(i1 true) ["dereferenceable"(ptr %P)]
-; CHECK: this attribute has no argument
- call void @llvm.assume(i1 true) ["dereferenceable"(ptr %P, i32 4), "cold"(ptr %P)]
-; CHECK: this attribute should have one argument
- call void @llvm.assume(i1 true) ["noalias"()]
- call void @llvm.assume(i1 true) ["align"(ptr %P, i32 %P1, i32 4)]
-; CHECK: alignment assumptions should have 2 or 3 arguments
- call void @llvm.assume(i1 true) ["align"(ptr %P, i32 %P1, i32 4, i32 4)]
+
+; DereferenceableOrNull checks
+ call void @llvm.assume(i1 true) ["dereferenceable_or_null"(ptr %P, i32 %P1)]
+; CHECK: first argument should be a pointer
+ call void @llvm.assume(i1 true) ["dereferenceable_or_null"(i32 %P1, i32 %P1)]
; CHECK: second argument should be an integer
- call void @llvm.assume(i1 true) ["align"(ptr %P, ptr %P2)]
-; CHECK: third argument should be an integer if present
- call void @llvm.assume(i1 true) ["align"(ptr %P, i32 %P1, ptr %P2)]
+ call void @llvm.assume(i1 true) ["dereferenceable_or_null"(ptr %P, float 1.5)]
+; CHECK: dereferenceable assumptions should have 2 arguments
+ call void @llvm.assume(i1 true) ["dereferenceable_or_null"(ptr %P, i32 8, i32 8)]
+; CHECK: dereferenceable assumptions should have 2 arguments
+ call void @llvm.assume(i1 true) ["dereferenceable_or_null"(ptr %P)]
+
+; NonNull checks
+;
+; CHECK: nonnull assumptions should have 1 argument
+ call void @llvm.assume(i1 true) ["nonnull"()]
+; CHECK: nonnull assumptions should have 1 argument
+ call void @llvm.assume(i1 true) ["nonnull"(ptr %P, ptr %P)]
+; CHECK: first argument should be a pointer
+ call void @llvm.assume(i1 true) ["nonnull"(i32 0)]
+
+; NoUndef checks
+;
+; CHECK: noundef assumptions should have 1 argument
+ call void @llvm.assume(i1 true) ["noundef"()]
+; CHECK: noundef assumptions should have 1 argument
+ call void @llvm.assume(i1 true) ["noundef"(ptr %P, ptr %P)]
+
+; SeparateStorage checks
+;
; CHECK: separate_storage assumptions should have 2 arguments
call void @llvm.assume(i1 true) ["separate_storage"(ptr %P)]
+; CHECK: separate_storage assumptions should have 2 arguments
+ call void @llvm.assume(i1 true) ["separate_storage"(ptr %P, ptr %P, ptr %P)]
; CHECK: arguments to separate_storage assumptions should be pointers
call void @llvm.assume(i1 true) ["separate_storage"(ptr %P, i32 123)]
+
+; Combining multiple attributes checks
+;
+; CHECK: cold assumptions should have no arguments
+ call void @llvm.assume(i1 true) ["dereferenceable"(ptr %P, i32 4), "cold"(ptr %P)]
; CHECK: dereferenceable assumptions should have 2 arguments
call void @llvm.assume(i1 true) ["align"(ptr %P, i32 4), "dereferenceable"(ptr %P)]
-; CHECK: assume with operand bundles must have i1 true condition
- call void @llvm.assume(i1 %cond) ["nonnull"(ptr %P)]
ret void
}
diff --git a/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp b/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp
index 485b70c068401..e99e2ec4930fc 100644
--- a/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp
+++ b/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp
@@ -22,10 +22,6 @@
using namespace llvm;
-namespace llvm {
-LLVM_ABI extern cl::opt<bool> ShouldPreserveAllAttributes;
-} // namespace llvm
-
static void RunTest(
StringRef Head, StringRef Tail,
std::vector<std::pair<StringRef, llvm::function_ref<void(Instruction *)>>>
@@ -126,16 +122,6 @@ TEST(AssumeQueryAPI, hasAttributeInAssume) {
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
Attribute::AttrKind::Alignment, 64));
}));
- Tests.push_back(std::make_pair(
- "call void @func_many(ptr align 8 noundef %P1) cold\n", [](Instruction *I) {
- ShouldPreserveAllAttributes.setValue(true);
- auto *Assume = buildAssumeFromInst(I);
- Assume->insertBefore(I->getIterator());
- ASSERT_TRUE(hasMatchesExactlyAttributes(
- Assume, nullptr,
- "(align|nounwind|norecurse|noundef|willreturn|cold)"));
- ShouldPreserveAllAttributes.setValue(false);
- }));
Tests.push_back(
std::make_pair("call void @llvm.assume(i1 true)\n", [](Instruction *I) {
auto *Assume = cast<AssumeInst>(I);
@@ -309,19 +295,6 @@ TEST(AssumeQueryAPI, fillMapFromAssume) {
ASSERT_TRUE(MapHasRightValue(
Map, Assume, {I->getOperand(0), Attribute::Alignment}, {64, 64}));
}));
- Tests.push_back(std::make_pair(
- "call void @func_many(ptr align 8 %P1) cold\n", [](Instruction *I) {
- ShouldPreserveAllAttributes.setValue(true);
- auto *Assume = buildAssumeFromInst(I);
- Assume->insertBefore(I->getIterator());
-
- RetainedKnowledgeMap Map;
- fillMapFromAssume(*Assume, Map);
-
- ASSERT_TRUE(FindExactlyAttributes(
- Map, nullptr, "(nounwind|norecurse|willreturn|cold)"));
- ShouldPreserveAllAttributes.setValue(false);
- }));
Tests.push_back(
std::make_pair("call void @llvm.assume(i1 true)\n", [](Instruction *I) {
RetainedKnowledgeMap Map;
>From fa8cc24c38a97a90be4913ee87f35cf2a4b72157 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 11 May 2026 23:21:34 +0200
Subject: [PATCH 02/12] Address comments
---
llvm/include/llvm/IR/BundleAttributes.h | 4 +-
llvm/lib/Analysis/ValueTracking.cpp | 12 ++----
llvm/lib/IR/BundleAttributes.cpp | 11 ++++--
.../InstCombine/InstCombineCalls.cpp | 9 ++---
llvm/test/Transforms/InstCombine/test.ll | 38 -------------------
5 files changed, 16 insertions(+), 58 deletions(-)
delete mode 100644 llvm/test/Transforms/InstCombine/test.ll
diff --git a/llvm/include/llvm/IR/BundleAttributes.h b/llvm/include/llvm/IR/BundleAttributes.h
index 789e5b95fc1e4..91c2d58c63d82 100644
--- a/llvm/include/llvm/IR/BundleAttributes.h
+++ b/llvm/include/llvm/IR/BundleAttributes.h
@@ -29,8 +29,8 @@ inline BundleAttr getBundleAttrFromOBU(OperandBundleUse OBU) {
struct AssumeAlignInfo {
Value *Ptr;
- Value *Alignment;
- Value *Offset;
+ std::optional<uint64_t> Alignment;
+ std::optional<uint64_t> Offset;
};
LLVM_ABI AssumeAlignInfo getAssumeAlignInfo(OperandBundleUse);
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 7a391182594ee..1f46a80e491d6 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1091,15 +1091,11 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
if (getBundleAttrFromOBU(OBU) == BundleAttr::Align) {
auto [Ptr, Alignment, Offset] = getAssumeAlignInfo(OBU);
assert(Ptr == V);
- if ((Offset && !isa<ConstantInt>(Offset)) ||
- !isa<ConstantInt>(Alignment))
+ if (!Alignment || !isPowerOf2_64(*Alignment))
continue;
- auto AlignVal =
- MinAlign(Offset ? cast<ConstantInt>(Offset)->getZExtValue() : 0,
- cast<ConstantInt>(Alignment)->getZExtValue());
- if (!isPowerOf2_64(AlignVal) || !isValidAssumeForContext(I, Q))
- continue;
- Known.Zero.setLowBits(Log2_64(AlignVal));
+ auto AlignVal = MinAlign(Offset.value_or(0), *Alignment);
+ if (isValidAssumeForContext(I, Q))
+ Known.Zero.setLowBits(Log2_64(AlignVal));
}
continue;
}
diff --git a/llvm/lib/IR/BundleAttributes.cpp b/llvm/lib/IR/BundleAttributes.cpp
index 19ff05a96ee27..e9320efbd0adc 100644
--- a/llvm/lib/IR/BundleAttributes.cpp
+++ b/llvm/lib/IR/BundleAttributes.cpp
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/BundleAttributes.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace llvm;
@@ -34,9 +34,12 @@ AssumeAlignInfo llvm::getAssumeAlignInfo(OperandBundleUse OBU) {
OBU.Inputs.size() <= 3);
AssumeAlignInfo Ret{};
Ret.Ptr = OBU.Inputs[0];
- Ret.Alignment = OBU.Inputs[1];
- if (OBU.Inputs.size() == 3)
- Ret.Offset = OBU.Inputs[2];
+ if (auto *Align = dyn_cast<ConstantInt>(OBU.Inputs[1]))
+ Ret.Alignment = Align->getZExtValue();
+ if (OBU.Inputs.size() == 3) {
+ if (auto *Offset = dyn_cast<ConstantInt>(OBU.Inputs[2]))
+ Ret.Offset = Offset->getZExtValue();
+ }
return Ret;
}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 3ee5d65f7f8b7..bd5388e2a090f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3630,14 +3630,11 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
// Try to remove redundant alignment assumptions.
auto [Ptr, Alignment, Offset] = getAssumeAlignInfo(OBU);
- if (Offset || !isa<ConstantInt>(Alignment))
- break;
- auto AlignVal = cast<ConstantInt>(Alignment)->getZExtValue();
- if (!isPowerOf2_64(AlignVal))
+ if (Offset || !Alignment || !isPowerOf2_64(*Alignment))
break;
// Remove align 1 bundles; they don't add any useful information.
- if (AlignVal == 1)
+ if (*Alignment == 1)
return CallBase::removeOperandBundle(II, OBU.getTagID());
// Don't try to remove align assumptions for pointers derived from
@@ -3650,7 +3647,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
// Compute known bits for the pointer and drop the assume if the
// known alignment isn't increased by it.
if ((1ULL << computeKnownBits(Ptr, II).countMinTrailingZeros()) <
- AlignVal)
+ *Alignment)
break;
return CallBase::removeOperandBundle(II, OBU.getTagID());
}
diff --git a/llvm/test/Transforms/InstCombine/test.ll b/llvm/test/Transforms/InstCombine/test.ll
deleted file mode 100644
index c5b859e19f486..0000000000000
--- a/llvm/test/Transforms/InstCombine/test.ll
+++ /dev/null
@@ -1,38 +0,0 @@
-
-define void @f2(ptr %a) {
-; CHECK-LABEL: @f2(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A:%.*]], i64 32, i32 24) ]
-; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 8
-; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[TMP0]] to i64
-; CHECK-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 8
-; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0
-; CHECK-NEXT: br i1 [[TMP3]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
-; CHECK: if.then:
-; CHECK-NEXT: store i64 16, ptr [[TMP0]], align 4
-; CHECK-NEXT: br label [[IF_END:%.*]]
-; CHECK: if.else:
-; CHECK-NEXT: store i8 1, ptr [[TMP0]], align 1
-; CHECK-NEXT: br label [[IF_END]]
-; CHECK: if.end:
-; CHECK-NEXT: ret void
-;
-entry:
- call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 32, i32 24) ]
- %0 = getelementptr inbounds i8, ptr %a, i64 8
- %1 = ptrtoint ptr %0 to i64
- %2 = and i64 %1, 15
- %3 = icmp eq i64 %2, 0
- br i1 %3, label %if.then, label %if.else
-
-if.then: ; preds = %entry
- store i64 16, ptr %0, align 4
- br label %if.end
-
-if.else: ; preds = %entry
- store i8 1, ptr %0, align 1
- br label %if.end
-
-if.end: ; preds = %if.else, %if.then
- ret void
-}
>From e62c100ea37c5e595e3e0b525007bb82913724a0 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 12 May 2026 13:38:30 +0200
Subject: [PATCH 03/12] Address comments
---
llvm/lib/Analysis/LazyValueInfo.cpp | 4 ++--
llvm/lib/Analysis/ValueTracking.cpp | 6 +++---
.../coro-split-musttail-chain-pgo-counter-promo.ll | 6 +++---
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 37771985bd455..593c2cd0e9dad 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -856,8 +856,8 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
continue;
if (AssumeVH.Index != AssumptionCache::ExprResultIdx) {
- auto OBU = I->operand_bundles().begin()[AssumeVH.Index];
- switch (getBundleAttrFromOBU(OBU)) {
+ switch (auto OBU = I->getOperandBundleAt(AssumeVH.Index);
+ getBundleAttrFromOBU(OBU)) {
case BundleAttr::NonNull:
assert(getAssumeNonNullInfo(OBU).Ptr == Val);
BBLV = BBLV.intersect(ValueLatticeElement::getNot(
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 1f46a80e491d6..d8ca20159c013 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -830,8 +830,8 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
"Got assumption for the wrong function!");
if (Elem.Index != AssumptionCache::ExprResultIdx) {
- auto OBU = I->operand_bundles().begin()[Elem.Index];
bool AssumeImpliesNonNull = [&]() {
+ auto OBU = I->getOperandBundleAt(Elem.Index);
switch (getBundleAttrFromOBU(OBU)) {
case BundleAttr::Dereferenceable: {
auto [Ptr, Count] = getAssumeDereferenceableInfo(OBU);
@@ -1087,8 +1087,8 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
"Got assumption for the wrong function!");
if (Elem.Index != AssumptionCache::ExprResultIdx) {
- auto OBU = I->operand_bundles().begin()[Elem.Index];
- if (getBundleAttrFromOBU(OBU) == BundleAttr::Align) {
+ if (auto OBU = I->getOperandBundleAt(Elem.Index);
+ getBundleAttrFromOBU(OBU) == BundleAttr::Align) {
auto [Ptr, Alignment, Offset] = getAssumeAlignInfo(OBU);
assert(Ptr == V);
if (!Alignment || !isPowerOf2_64(*Alignment))
diff --git a/llvm/test/Transforms/Coroutines/coro-split-musttail-chain-pgo-counter-promo.ll b/llvm/test/Transforms/Coroutines/coro-split-musttail-chain-pgo-counter-promo.ll
index f176ef59d64b5..70f15f6129d8e 100644
--- a/llvm/test/Transforms/Coroutines/coro-split-musttail-chain-pgo-counter-promo.ll
+++ b/llvm/test/Transforms/Coroutines/coro-split-musttail-chain-pgo-counter-promo.ll
@@ -2,14 +2,14 @@
; RUN: opt -passes='pgo-instr-gen,instrprof,coro-split' -do-counter-promotion=true -S < %s | FileCheck %s
; CHECK-LABEL: define internal fastcc void @f.resume
-; CHECK: musttail call fastcc void
+; CHECK: musttail call fastcc void
; CHECK-NEXT: ret void
-; CHECK: musttail call fastcc void
+; CHECK: musttail call fastcc void
; CHECK-NEXT: ret void
; CHECK-LABEL: define internal fastcc void @f.destroy
target triple = "x86_64-grtev4-linux-gnu"
-%CoroutinePromise = type { ptr, i64, [8 x i8], ptr}
+%CoroutinePromise = type { ptr, i64, [8 x i8], ptr}
%Awaitable.1 = type { ptr }
%Awaitable.2 = type { ptr, ptr }
>From 4ec7fa0bc251b4816425601b272fc1746e773d0e Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 12 May 2026 17:35:05 +0200
Subject: [PATCH 04/12] CI fux
---
llvm/lib/IR/BundleAttributes.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/IR/BundleAttributes.cpp b/llvm/lib/IR/BundleAttributes.cpp
index e9320efbd0adc..e9b4077033a99 100644
--- a/llvm/lib/IR/BundleAttributes.cpp
+++ b/llvm/lib/IR/BundleAttributes.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/BundleAttributes.h"
+#include "llvm/IR/Constants.h"
#include "llvm/ADT/StringSwitch.h"
using namespace llvm;
>From e7fc5cc5cddc7f957ba51e86ddc5bc92d9807d13 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 13 May 2026 17:06:19 +0200
Subject: [PATCH 05/12] Fix CI
---
.../ValueTracking/assume-queries-counter.ll | 34 ++++++++-----------
1 file changed, 14 insertions(+), 20 deletions(-)
diff --git a/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll b/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll
index 0cb8279f3db38..24b0cc923106a 100644
--- a/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll
+++ b/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll
@@ -14,13 +14,11 @@ define dso_local i1 @test1(ptr readonly %0) {
;
; COUNTER2-LABEL: @test1(
; COUNTER2-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
-; COUNTER2-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null
-; COUNTER2-NEXT: ret i1 [[TMP2]]
+; COUNTER2-NEXT: ret i1 false
;
; COUNTER3-LABEL: @test1(
; COUNTER3-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
-; COUNTER3-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null
-; COUNTER3-NEXT: ret i1 [[TMP2]]
+; COUNTER3-NEXT: ret i1 false
;
call void @llvm.assume(i1 true) ["nonnull"(ptr %0)]
%2 = icmp eq ptr %0, null
@@ -29,18 +27,16 @@ define dso_local i1 @test1(ptr readonly %0) {
define dso_local i1 @test2(ptr readonly %0) {
; COUNTER1-LABEL: @test2(
-; COUNTER1-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0:%.*]], null
-; COUNTER1-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0]]) ]
-; COUNTER1-NEXT: ret i1 [[TMP2]]
+; COUNTER1-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
+; COUNTER1-NEXT: ret i1 false
;
; COUNTER2-LABEL: @test2(
; COUNTER2-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
; COUNTER2-NEXT: ret i1 false
;
; COUNTER3-LABEL: @test2(
-; COUNTER3-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0:%.*]], null
-; COUNTER3-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0]]) ]
-; COUNTER3-NEXT: ret i1 [[TMP2]]
+; COUNTER3-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
+; COUNTER3-NEXT: ret i1 false
;
%2 = icmp eq ptr %0, null
call void @llvm.assume(i1 true) ["nonnull"(ptr %0)]
@@ -54,13 +50,12 @@ define dso_local i32 @test4(ptr readonly %0, i1 %cond) nofree nosync {
; COUNTER1: B:
; COUNTER1-NEXT: br label [[A]]
; COUNTER1: A:
-; COUNTER1-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null
-; COUNTER1-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
-; COUNTER1: 3:
+; COUNTER1-NEXT: br i1 false, label [[TMP5:%.*]], label [[TMP2:%.*]]
+; COUNTER1: 2:
; COUNTER1-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP0]], align 4
; COUNTER1-NEXT: br label [[TMP5]]
-; COUNTER1: 5:
-; COUNTER1-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP4]], [[TMP3]] ], [ 0, [[A]] ]
+; COUNTER1: 4:
+; COUNTER1-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP4]], [[TMP2]] ], [ poison, [[A]] ]
; COUNTER1-NEXT: ret i32 [[TMP6]]
;
; COUNTER2-LABEL: @test4(
@@ -69,13 +64,12 @@ define dso_local i32 @test4(ptr readonly %0, i1 %cond) nofree nosync {
; COUNTER2: B:
; COUNTER2-NEXT: br label [[A]]
; COUNTER2: A:
-; COUNTER2-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null
-; COUNTER2-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
-; COUNTER2: 3:
+; COUNTER2-NEXT: br i1 false, label [[TMP5:%.*]], label [[TMP2:%.*]]
+; COUNTER2: 2:
; COUNTER2-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP0]], align 4
; COUNTER2-NEXT: br label [[TMP5]]
-; COUNTER2: 5:
-; COUNTER2-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP4]], [[TMP3]] ], [ 0, [[A]] ]
+; COUNTER2: 4:
+; COUNTER2-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP4]], [[TMP2]] ], [ poison, [[A]] ]
; COUNTER2-NEXT: ret i32 [[TMP6]]
;
; COUNTER3-LABEL: @test4(
>From 8a8dfeebe006046ff9e88fe37d59e5bde4874fe1 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Fri, 15 May 2026 10:20:45 +0200
Subject: [PATCH 06/12] Fix formatting
---
llvm/lib/IR/BundleAttributes.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/IR/BundleAttributes.cpp b/llvm/lib/IR/BundleAttributes.cpp
index e9b4077033a99..aee4495d9d822 100644
--- a/llvm/lib/IR/BundleAttributes.cpp
+++ b/llvm/lib/IR/BundleAttributes.cpp
@@ -7,8 +7,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/BundleAttributes.h"
-#include "llvm/IR/Constants.h"
+
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/Constants.h"
using namespace llvm;
>From cddd3a22b389a9f1c589de11b3428c5776384c01 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 17 May 2026 14:52:25 +0200
Subject: [PATCH 07/12] Expose uses
---
llvm/include/llvm/IR/BundleAttributes.h | 23 ++++++++++---------
llvm/lib/Analysis/ValueTracking.cpp | 2 +-
llvm/lib/IR/BundleAttributes.cpp | 9 ++++----
.../InstCombine/InstCombineCalls.cpp | 6 ++---
4 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/llvm/include/llvm/IR/BundleAttributes.h b/llvm/include/llvm/IR/BundleAttributes.h
index 91c2d58c63d82..87bc4afbae904 100644
--- a/llvm/include/llvm/IR/BundleAttributes.h
+++ b/llvm/include/llvm/IR/BundleAttributes.h
@@ -28,20 +28,21 @@ inline BundleAttr getBundleAttrFromOBU(OperandBundleUse OBU) {
}
struct AssumeAlignInfo {
- Value *Ptr;
- std::optional<uint64_t> Alignment;
- std::optional<uint64_t> Offset;
+ const Use &Ptr;
+ const Use &Alignment;
+ std::optional<uint64_t> AlignmentVal;
+ std::optional<uint64_t> OffsetVal;
};
LLVM_ABI AssumeAlignInfo getAssumeAlignInfo(OperandBundleUse);
-struct AssumeSeparateStorageInfo {
- const Use *Ptr1;
- const Use *Ptr2;
+struct AssumeDereferenceableInfo {
+ const Use &Ptr;
+ const Use &Count;
};
LLVM_ABI
-AssumeSeparateStorageInfo getAssumeSeparateStorageInfo(OperandBundleUse);
+AssumeDereferenceableInfo getAssumeDereferenceableInfo(OperandBundleUse);
struct AssumeNonNullInfo {
Value *Ptr;
@@ -49,13 +50,13 @@ struct AssumeNonNullInfo {
LLVM_ABI AssumeNonNullInfo getAssumeNonNullInfo(OperandBundleUse);
-struct AssumeDereferenceableInfo {
- Value *Ptr;
- Value *Count;
+struct AssumeSeparateStorageInfo {
+ const Use &Ptr1;
+ const Use &Ptr2;
};
LLVM_ABI
-AssumeDereferenceableInfo getAssumeDereferenceableInfo(OperandBundleUse);
+AssumeSeparateStorageInfo getAssumeSeparateStorageInfo(OperandBundleUse);
} // namespace llvm
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 59500889555dc..6f78e3fb0ea54 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1089,7 +1089,7 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
if (Elem.Index != AssumptionCache::ExprResultIdx) {
if (auto OBU = I->getOperandBundleAt(Elem.Index);
getBundleAttrFromOBU(OBU) == BundleAttr::Align) {
- auto [Ptr, Alignment, Offset] = getAssumeAlignInfo(OBU);
+ auto [Ptr, _, Alignment, Offset] = getAssumeAlignInfo(OBU);
assert(Ptr == V);
if (!Alignment || !isPowerOf2_64(*Alignment))
continue;
diff --git a/llvm/lib/IR/BundleAttributes.cpp b/llvm/lib/IR/BundleAttributes.cpp
index aee4495d9d822..e64e7b55df3bf 100644
--- a/llvm/lib/IR/BundleAttributes.cpp
+++ b/llvm/lib/IR/BundleAttributes.cpp
@@ -34,13 +34,12 @@ BundleAttr llvm::getBundleAttrFromString(StringRef Str) {
AssumeAlignInfo llvm::getAssumeAlignInfo(OperandBundleUse OBU) {
assert(OBU.getTagName() == "align" && OBU.Inputs.size() >= 2 &&
OBU.Inputs.size() <= 3);
- AssumeAlignInfo Ret{};
- Ret.Ptr = OBU.Inputs[0];
+ AssumeAlignInfo Ret{OBU.Inputs[0], OBU.Inputs[1], std::nullopt, std::nullopt};
if (auto *Align = dyn_cast<ConstantInt>(OBU.Inputs[1]))
- Ret.Alignment = Align->getZExtValue();
+ Ret.AlignmentVal = Align->getZExtValue();
if (OBU.Inputs.size() == 3) {
if (auto *Offset = dyn_cast<ConstantInt>(OBU.Inputs[2]))
- Ret.Offset = Offset->getZExtValue();
+ Ret.OffsetVal = Offset->getZExtValue();
}
return Ret;
}
@@ -48,7 +47,7 @@ AssumeAlignInfo llvm::getAssumeAlignInfo(OperandBundleUse OBU) {
AssumeSeparateStorageInfo
llvm::getAssumeSeparateStorageInfo(OperandBundleUse OBU) {
assert(OBU.getTagName() == "separate_storage" && OBU.Inputs.size() == 2);
- return {&OBU.Inputs[0], &OBU.Inputs[1]};
+ return {OBU.Inputs[0], OBU.Inputs[1]};
}
AssumeNonNullInfo llvm::getAssumeNonNullInfo(OperandBundleUse OBU) {
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index bd5388e2a090f..465fde2c66442 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3628,7 +3628,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
llvm_unreachable("Unexpected Attribute");
case BundleAttr::Align: {
// Try to remove redundant alignment assumptions.
- auto [Ptr, Alignment, Offset] = getAssumeAlignInfo(OBU);
+ auto [Ptr, _, Alignment, Offset] = getAssumeAlignInfo(OBU);
if (Offset || !Alignment || !isPowerOf2_64(*Alignment))
break;
@@ -3687,8 +3687,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (Hint != UnderlyingObject)
replaceUse(const_cast<Use &>(U), UnderlyingObject);
};
- MaybeSimplifyHint(*Ptr1);
- MaybeSimplifyHint(*Ptr2);
+ MaybeSimplifyHint(Ptr1);
+ MaybeSimplifyHint(Ptr2);
} break;
// TODO: Drop these assumes when they are redundant
>From 4615c8559091010ab00e7c37ac773e782049f870 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Fri, 29 May 2026 10:14:03 +0200
Subject: [PATCH 08/12] Address comments
---
llvm/docs/LangRef.rst | 14 ++++++++++++--
llvm/docs/ReleaseNotes.md | 7 ++++++-
llvm/lib/Analysis/ValueTracking.cpp | 2 ++
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 74c90d1f06532..4924b61f08d05 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -3120,6 +3120,16 @@ assumptions, such as that a :ref:`parameter attribute <paramattrs>` or a
location. Operand bundles enable assumptions that are either hard or impossible
to represent as a boolean argument of an :ref:`llvm.assume <int_assume>`.
+The following attributes are currently accepted:
+* ``align``
+* ``cold``
+* ``dereferenceable``
+* ``dereferenceable_or_null``
+* ``ignore``
+* ``nonnull``
+* ``noundef``
+* ``separate_storage``
+
Assumes with operand bundles must have ``i1 true`` as the condition operand.
An assume operand bundle has the form:
@@ -8055,7 +8065,7 @@ Together these two attributes provide a four-way classification:
- ``body`` only: main vectorized loop body
- ``epilogue`` only: scalar epilogue loop after vectorization
-- Both ``body`` and ``epilogue``: vectorized epilogue
+- Both ``body`` and ``epilogue``: vectorized epilogue
(a remainder loop that was itself vectorized during epilogue
vectorization)
- Neither: a plain loop not produced by the vectorizer
@@ -8684,7 +8694,7 @@ is executed, followed by ``uint64_t`` value and execution count pairs.
The value profiling kind is 0 for indirect call targets and 1 for memory
operations. For indirect call targets, each profile value is a hash
of the callee function name, and for memory operations each value is the
-byte length. It is illegal to have duplicate profile values (e.g.,
+byte length. It is illegal to have duplicate profile values (e.g.,
duplicate function hashes for indirect calls or byte lengths for memory
operations).
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 013b5d0a52067..190202692293b 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -87,6 +87,11 @@ Makes programs 10x faster by doing Special New Thing.
and `ccc` agree for `void(ptr)` (x86_64, AArch64, RISC-V, ...) but is an ABI
break on i686, MIPS O32, PowerPC64 ELFv1, and Lanai.
+* Assume bundles now only accept attributes that are actually handled.
+ Specifically, they are ``align``, ``cold``, ``dereferenceable``,
+ ``dereferenceable_or_null``, ``nonnull``, ``noundef`` and
+ ``separate_storage``.
+
### Changes to LLVM infrastructure
* Removed ``Constant::isZeroValue``. It was functionally identical to
@@ -130,7 +135,7 @@ Makes programs 10x faster by doing Special New Thing.
([#177046](https://github.com/llvm/llvm-project/pull/125687)). Note that
there are still issues with invalid compiler reasoning about some functions
in bitcode, e.g. `malloc`. Not yet supported on MachO or when using
- distributed ThinLTO.
+ distributed ThinLTO.
* ``ConstantFP`` now supports vector types and is the canonical form returned by
``ConstantVector::getSplat(C)`` when ``C`` is a scalar ``ConstantFP``.
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 6f78e3fb0ea54..e6871e0f7fc32 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -835,6 +835,7 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
switch (getBundleAttrFromOBU(OBU)) {
case BundleAttr::Dereferenceable: {
auto [Ptr, Count] = getAssumeDereferenceableInfo(OBU);
+ assert(Ptr == V);
if (NullPointerIsDefined(Q.CxtI->getFunction(),
V->getType()->getPointerAddressSpace()))
return false;
@@ -844,6 +845,7 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
}
case BundleAttr::NonNull:
+ assert(getAssumeNonNullInfo(OBU).Ptr == V);
return true;
default:
>From 6d7647b250f7c0c198d4113dfeafbad55a75b09f Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 4 Jun 2026 14:17:37 +0200
Subject: [PATCH 09/12] Address comments
---
llvm/docs/LangRef.rst | 116 ++++++++----------
llvm/include/llvm/IR/BundleAttributes.def | 6 +-
llvm/include/llvm/IR/BundleAttributes.h | 2 +-
llvm/lib/Analysis/LazyValueInfo.cpp | 4 +-
llvm/lib/Analysis/ValueTracking.cpp | 4 +-
llvm/lib/IR/BundleAttributes.cpp | 2 +
.../InstCombine/InstCombineCalls.cpp | 2 +-
.../ValueTracking/assume-queries-counter.ll | 106 ----------------
llvm/test/Analysis/ValueTracking/assume.ll | 66 ++++++++++
llvm/test/Transforms/InstCombine/assume.ll | 71 +++++++++++
10 files changed, 203 insertions(+), 176 deletions(-)
delete mode 100644 llvm/test/Analysis/ValueTracking/assume-queries-counter.ll
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 342394d12d8a9..49b5234b6915f 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1587,6 +1587,8 @@ Currently, only the following parameter attributes are defined:
:ref:`bitcast instruction <i_bitcast>`. This is not a valid attribute for
return values and can only be applied to one parameter.
+.. _attr_nonnull:
+
``nonnull``
This indicates that the parameter or return pointer is not null. This
attribute may only be applied to pointer-typed parameters. This is not
@@ -1598,6 +1600,8 @@ Currently, only the following parameter attributes are defined:
The ``nonnull`` attribute should be combined with the ``noundef`` attribute
to ensure a pointer is not null or otherwise the behavior is undefined.
+.. _attr_dereferenceable:
+
``dereferenceable(<n>)``
This indicates that the parameter or return pointer is dereferenceable. This
attribute may only be applied to pointer-typed parameters. A pointer that
@@ -1610,9 +1614,9 @@ Currently, only the following parameter attributes are defined:
``null_pointer_is_valid`` function attribute is present.
``n`` should be a positive number. The pointer should be well defined,
otherwise it is undefined behavior. This means ``dereferenceable(<n>)``
- implies ``noundef``. When used in an assume operand bundle, more restricted
- semantics apply. See :ref:`assume operand bundles <assume_opbundles>` for
- more details.
+ implies ``noundef``.
+
+.. _attr_dereferenceable_or_null:
``dereferenceable_or_null(<n>)``
This indicates that the parameter or return value isn't both
@@ -1667,6 +1671,8 @@ Currently, only the following parameter attributes are defined:
only valid on intrinsic declarations and cannot be applied to a
call site or arbitrary function.
+.. _attr_noundef:
+
``noundef``
This attribute applies to parameters and return values. If the value
representation contains any undefined or poison bits, the behavior is
@@ -2149,6 +2155,9 @@ For example:
uses the ``nobuiltin`` attribute. This is only valid at call sites for
direct calls to functions that are declared with the ``nobuiltin``
attribute.
+
+.. _attr_cold:
+
``cold``
This attribute indicates that this function is rarely called. When
computing edge weights, basic blocks post-dominated by a cold
@@ -3127,43 +3136,57 @@ Assume Operand Bundles
^^^^^^^^^^^^^^^^^^^^^^
Operand bundles on an :ref:`llvm.assume <int_assume>` allow representing
-assumptions, such as that a :ref:`parameter attribute <paramattrs>` or a
-:ref:`function attribute <fnattrs>` holds for a certain value at a certain
-location. Operand bundles enable assumptions that are either hard or impossible
-to represent as a boolean argument of an :ref:`llvm.assume <int_assume>`.
-
-The following attributes are currently accepted:
-* ``align``
-* ``cold``
-* ``dereferenceable``
-* ``dereferenceable_or_null``
-* ``ignore``
-* ``nonnull``
-* ``noundef``
-* ``separate_storage``
+assumptions that hold at the location of the assume. Operand bundles enable
+assumptions that are either hard or impossible to represent as a boolean
+argument of an :ref:`llvm.assume <int_assume>`.
Assumes with operand bundles must have ``i1 true`` as the condition operand.
-An assume operand bundle has the form:
+Just like for the argument of :ref:`llvm.assume <int_assume>`, if any of the
+provided guarantees are violated at runtime the behavior is undefined.
+
+While attributes expect constant arguments, assume operand bundles may be
+provided a dynamic value, for example:
-::
+.. code-block:: llvm
- "<tag>"([ <arguments>] ])
+ call void @llvm.assume(i1 true) ["align"(ptr %val, i32 %align)]
-In the case of function or parameter attributes, the operand bundle has the
-restricted form:
+The following attributes are currently accepted:
-::
+``"align"(ptr %p, i64 %align)``, ``"align"(ptr %p, i64 %align, i64 %offset)``
+ Equivalent to :ref:`align(%align) <attr_align>` on ``%p``, or ``%p - %offset``
+ if the ``%offset`` argument exists, except that ``%align`` may be a
+ non-power-of-two alignment (including a zero alignment). If ``%align`` is not
+ a power of two the pointer value must be all-zero. Otherwise the behavior is
+ undefined.
+
+``"cold"()``
+ Equivalent to :ref:`cold <attr_cold>`.
+
+``"dereferenceable"(ptr %p, i64 %size)``
+ Equivalent to :ref:`dereferenceable(%size) <attr_dereferenceable>` on ``%p``,
+ except that ``%size`` may also be zero, in which case the attribute doesn't
+ imply ``nonnull``.
- "<tag>"([ <holds for value> [, <attribute argument>] ])
+``"dereferenceable_or_null"(ptr %p, i64 %size)``
+ Equivalent to :ref:`dereferenceable_or_null(%size)
+ <attr_dereferenceable_or_null>` on ``%p``, except that ``%size`` may also be
+ zero.
-* The tag of the operand bundle is usually the name of the attribute that can be
- assumed to hold. It can also be `ignore`; this tag doesn't contain any
- information and should be ignored.
-* The first argument, if present, is the value for which the attribute holds.
-* The second argument, if present, is an argument of the attribute.
+``"ignore"(...)``
+ Doesn't imply anything and is ignored. This is used to drop an assume where
+ modifying the ``llvm.assume`` call cannot be replaced or dropped.
-If there are no arguments the attribute is a property of the call location.
+``"nonnull"(ptr %p)``
+ Equivalent to :ref:`nonnull <attr_nonnull>` on ``%p``.
+
+``"noundef"(any_type %v)``
+ Equivalent to :ref:`noundef <attr_noundef>` on ``%v``.
+
+``"separate_storage"(ptr %p1, ptr %p2)``
+ This indicates that no pointer :ref:`based <pointeraliasing>` on one of its
+ arguments can alias any pointer based on the other.
For example:
@@ -3181,39 +3204,6 @@ allows the optimizer to assume that at location of call to
allows the optimizer to assume that the :ref:`llvm.assume <int_assume>`
call location is cold and that ``%val`` may not be null.
-Just like for the argument of :ref:`llvm.assume <int_assume>`, if any of the
-provided guarantees are violated at runtime the behavior is undefined.
-
-While attributes expect constant arguments, assume operand bundles may be
-provided a dynamic value, for example:
-
-.. code-block:: llvm
-
- call void @llvm.assume(i1 true) ["align"(ptr %val, i32 %align)]
-
-If the operand bundle value violates any requirements on the attribute value,
-the behavior is undefined, unless one of the following exceptions applies:
-
-* ``"align"`` operand bundles may specify a non-power-of-two alignment
- (including a zero alignment). If this is the case, then the pointer value
- must be an all-zero pointer, otherwise the behavior is undefined.
-
-* ``dereferenceable(<n>)`` operand bundles only guarantee the pointer is
- dereferenceable at the point of the assumption. The pointer may not be
- dereferenceable at later pointers, e.g., because it could have been freed.
- Only ``n > 0`` implies that the pointer is dereferenceable.
-
-In addition to allowing operand bundles encoding function and parameter
-attributes, an assume operand bundle may also encode a ``separate_storage``
-operand bundle. This has the form:
-
-.. code-block:: llvm
-
- separate_storage(<val1>, <val2>)``
-
-This indicates that no pointer :ref:`based <pointeraliasing>` on one of its
-arguments can alias any pointer based on the other.
-
Even if the assumed property can be encoded as a boolean value, like
``nonnull``, using operand bundles to express the property can still have
benefits:
diff --git a/llvm/include/llvm/IR/BundleAttributes.def b/llvm/include/llvm/IR/BundleAttributes.def
index 2d57a0b697edc..78c692393fb44 100644
--- a/llvm/include/llvm/IR/BundleAttributes.def
+++ b/llvm/include/llvm/IR/BundleAttributes.def
@@ -12,7 +12,11 @@ ATTR(Dereferenceable, dereferenceable)
ATTR(DereferenceableOrNull, dereferenceable_or_null)
ATTR(Ignore, ignore)
ATTR(NonNull, nonnull)
-ATTR(NoUndef, noundef) // FIXME: Is this actually useful? It's currently exclusively emitted through tests.
+
+// FIXME: Is this actually useful?
+// It's currently exclusively emitted through tests.
+ATTR(NoUndef, noundef)
+
ATTR(SeparateStorage, separate_storage)
#undef ATTR
diff --git a/llvm/include/llvm/IR/BundleAttributes.h b/llvm/include/llvm/IR/BundleAttributes.h
index 87bc4afbae904..ee6e5b4bc1ef6 100644
--- a/llvm/include/llvm/IR/BundleAttributes.h
+++ b/llvm/include/llvm/IR/BundleAttributes.h
@@ -45,7 +45,7 @@ LLVM_ABI
AssumeDereferenceableInfo getAssumeDereferenceableInfo(OperandBundleUse);
struct AssumeNonNullInfo {
- Value *Ptr;
+ const Use &Ptr;
};
LLVM_ABI AssumeNonNullInfo getAssumeNonNullInfo(OperandBundleUse);
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index d50720bab4d16..3a875bd680fb9 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -856,8 +856,8 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
continue;
if (AssumeVH.Index != AssumptionCache::ExprResultIdx) {
- switch (auto OBU = I->getOperandBundleAt(AssumeVH.Index);
- getBundleAttrFromOBU(OBU)) {
+ auto OBU = I->getOperandBundleAt(AssumeVH.Index);
+ switch (getBundleAttrFromOBU(OBU)) {
case BundleAttr::NonNull:
assert(getAssumeNonNullInfo(OBU).Ptr == Val);
BBLV = BBLV.intersect(ValueLatticeElement::getNot(
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 4a78f2fb4bb63..f46b4e9c94b7d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1091,9 +1091,9 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
getBundleAttrFromOBU(OBU) == BundleAttr::Align) {
auto [Ptr, _, Alignment, Offset] = getAssumeAlignInfo(OBU);
assert(Ptr == V);
- if (!Alignment || !isPowerOf2_64(*Alignment))
+ if (!Alignment || !Offset || !isPowerOf2_64(*Alignment))
continue;
- auto AlignVal = MinAlign(Offset.value_or(0), *Alignment);
+ auto AlignVal = MinAlign(*Offset, *Alignment);
if (isValidAssumeForContext(I, Q))
Known.Zero.setLowBits(Log2_64(AlignVal));
}
diff --git a/llvm/lib/IR/BundleAttributes.cpp b/llvm/lib/IR/BundleAttributes.cpp
index e64e7b55df3bf..3e4e65e8fd3d1 100644
--- a/llvm/lib/IR/BundleAttributes.cpp
+++ b/llvm/lib/IR/BundleAttributes.cpp
@@ -40,6 +40,8 @@ AssumeAlignInfo llvm::getAssumeAlignInfo(OperandBundleUse OBU) {
if (OBU.Inputs.size() == 3) {
if (auto *Offset = dyn_cast<ConstantInt>(OBU.Inputs[2]))
Ret.OffsetVal = Offset->getZExtValue();
+ } else {
+ Ret.OffsetVal = 0;
}
return Ret;
}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 768227d682765..92cb4ac2af23f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3656,7 +3656,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
// Try to remove redundant alignment assumptions.
auto [Ptr, _, Alignment, Offset] = getAssumeAlignInfo(OBU);
- if (Offset || !Alignment || !isPowerOf2_64(*Alignment))
+ if (!Alignment || !Offset || *Offset != 0 || !isPowerOf2_64(*Alignment))
break;
// Remove align 1 bundles; they don't add any useful information.
diff --git a/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll b/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll
deleted file mode 100644
index 24b0cc923106a..0000000000000
--- a/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll
+++ /dev/null
@@ -1,106 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-
-; RUN: opt < %s -passes=instcombine --debug-counter=assume-queries-counter=1 -S | FileCheck %s --check-prefixes=COUNTER1
-; RUN: opt < %s -passes=instcombine --debug-counter=assume-queries-counter=2-3 -S | FileCheck %s --check-prefixes=COUNTER2
-; RUN: opt < %s -passes=instcombine --debug-counter=assume-queries-counter=4-7 -S | FileCheck %s --check-prefixes=COUNTER3
-
-declare i1 @get_val()
-declare void @llvm.assume(i1)
-
-define dso_local i1 @test1(ptr readonly %0) {
-; COUNTER1-LABEL: @test1(
-; COUNTER1-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
-; COUNTER1-NEXT: ret i1 false
-;
-; COUNTER2-LABEL: @test1(
-; COUNTER2-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
-; COUNTER2-NEXT: ret i1 false
-;
-; COUNTER3-LABEL: @test1(
-; COUNTER3-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
-; COUNTER3-NEXT: ret i1 false
-;
- call void @llvm.assume(i1 true) ["nonnull"(ptr %0)]
- %2 = icmp eq ptr %0, null
- ret i1 %2
-}
-
-define dso_local i1 @test2(ptr readonly %0) {
-; COUNTER1-LABEL: @test2(
-; COUNTER1-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
-; COUNTER1-NEXT: ret i1 false
-;
-; COUNTER2-LABEL: @test2(
-; COUNTER2-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
-; COUNTER2-NEXT: ret i1 false
-;
-; COUNTER3-LABEL: @test2(
-; COUNTER3-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0:%.*]]) ]
-; COUNTER3-NEXT: ret i1 false
-;
- %2 = icmp eq ptr %0, null
- call void @llvm.assume(i1 true) ["nonnull"(ptr %0)]
- ret i1 %2
-}
-
-define dso_local i32 @test4(ptr readonly %0, i1 %cond) nofree nosync {
-; COUNTER1-LABEL: @test4(
-; COUNTER1-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0:%.*]], i32 4) ]
-; COUNTER1-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
-; COUNTER1: B:
-; COUNTER1-NEXT: br label [[A]]
-; COUNTER1: A:
-; COUNTER1-NEXT: br i1 false, label [[TMP5:%.*]], label [[TMP2:%.*]]
-; COUNTER1: 2:
-; COUNTER1-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP0]], align 4
-; COUNTER1-NEXT: br label [[TMP5]]
-; COUNTER1: 4:
-; COUNTER1-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP4]], [[TMP2]] ], [ poison, [[A]] ]
-; COUNTER1-NEXT: ret i32 [[TMP6]]
-;
-; COUNTER2-LABEL: @test4(
-; COUNTER2-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0:%.*]], i32 4) ]
-; COUNTER2-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
-; COUNTER2: B:
-; COUNTER2-NEXT: br label [[A]]
-; COUNTER2: A:
-; COUNTER2-NEXT: br i1 false, label [[TMP5:%.*]], label [[TMP2:%.*]]
-; COUNTER2: 2:
-; COUNTER2-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP0]], align 4
-; COUNTER2-NEXT: br label [[TMP5]]
-; COUNTER2: 4:
-; COUNTER2-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP4]], [[TMP2]] ], [ poison, [[A]] ]
-; COUNTER2-NEXT: ret i32 [[TMP6]]
-;
-; COUNTER3-LABEL: @test4(
-; COUNTER3-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0:%.*]], i32 4) ]
-; COUNTER3-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
-; COUNTER3: B:
-; COUNTER3-NEXT: br label [[A]]
-; COUNTER3: A:
-; COUNTER3-NEXT: br i1 false, label [[TMP4:%.*]], label [[TMP2:%.*]]
-; COUNTER3: 2:
-; COUNTER3-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP0]], align 4
-; COUNTER3-NEXT: br label [[TMP4]]
-; COUNTER3: 4:
-; COUNTER3-NEXT: [[TMP5:%.*]] = phi i32 [ [[TMP3]], [[TMP2]] ], [ poison, [[A]] ]
-; COUNTER3-NEXT: ret i32 [[TMP5]]
-;
- call void @llvm.assume(i1 true) ["dereferenceable"(ptr %0, i32 4)]
- br i1 %cond, label %A, label %B
-
-B:
- br label %A
-
-A:
- %2 = icmp eq ptr %0, null
- br i1 %2, label %5, label %3
-
-3: ; preds = %1
- %4 = load i32, ptr %0, align 4
- br label %5
-
-5: ; preds = %1, %3
- %6 = phi i32 [ %4, %3 ], [ 0, %A ]
- ret i32 %6
-}
diff --git a/llvm/test/Analysis/ValueTracking/assume.ll b/llvm/test/Analysis/ValueTracking/assume.ll
index dafc15c2b2d23..fa5a03ba997c4 100644
--- a/llvm/test/Analysis/ValueTracking/assume.ll
+++ b/llvm/test/Analysis/ValueTracking/assume.ll
@@ -191,3 +191,69 @@ define i1 @test_dereferenceable_non_zero_size_is_nonnull(ptr %ptr) {
%2 = icmp eq ptr %ptr, null
ret i1 %2
}
+
+define i1 @test_align_with_constant_offset_0(ptr %ptr) {
+; CHECK-LABEL: @test_align_with_constant_offset_0(
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 8, i64 0) ]
+; CHECK-NEXT: ret i1 true
+;
+ call void @llvm.assume(i1 true) ["align"(ptr %ptr, i64 8, i64 0)]
+ %intptr = ptrtoint ptr %ptr to i64
+ %and = and i64 %intptr, 7
+ %is_aligned = icmp eq i64 %and, 0
+ ret i1 %is_aligned
+}
+
+define i1 @test_align_with_constant_offset_1(ptr %ptr) {
+; CHECK-LABEL: @test_align_with_constant_offset_1(
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 8, i64 1) ]
+; CHECK-NEXT: [[INTPTR:%.*]] = ptrtoint ptr [[PTR]] to i64
+; CHECK-NEXT: [[AND:%.*]] = and i64 [[INTPTR]], 7
+; CHECK-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i64 [[AND]], 0
+; CHECK-NEXT: ret i1 [[IS_ALIGNED]]
+;
+ call void @llvm.assume(i1 true) ["align"(ptr %ptr, i64 8, i64 1)]
+ %intptr = ptrtoint ptr %ptr to i64
+ %and = and i64 %intptr, 7
+ %is_aligned = icmp eq i64 %and, 0
+ ret i1 %is_aligned
+}
+
+define i1 @test_align_with_constant_offset_4(ptr %ptr) {
+; CHECK-LABEL: @test_align_with_constant_offset_4(
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 8, i64 4) ]
+; CHECK-NEXT: [[INTPTR:%.*]] = ptrtoint ptr [[PTR]] to i64
+; CHECK-NEXT: [[AND:%.*]] = and i64 [[INTPTR]], 4
+; CHECK-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i64 [[AND]], 0
+; CHECK-NEXT: ret i1 [[IS_ALIGNED]]
+;
+ call void @llvm.assume(i1 true) ["align"(ptr %ptr, i64 8, i64 4)]
+ %intptr = ptrtoint ptr %ptr to i64
+ %and = and i64 %intptr, 7
+ %is_aligned = icmp eq i64 %and, 0
+ ret i1 %is_aligned
+}
+
+define i1 @test_align_with_constant_offset_8(ptr %ptr) {
+; CHECK-LABEL: @test_align_with_constant_offset_8(
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 8, i64 8) ]
+; CHECK-NEXT: ret i1 true
+;
+ call void @llvm.assume(i1 true) ["align"(ptr %ptr, i64 8, i64 8)]
+ %intptr = ptrtoint ptr %ptr to i64
+ %and = and i64 %intptr, 7
+ %is_aligned = icmp eq i64 %and, 0
+ ret i1 %is_aligned
+}
+
+define i1 @test_align_with_variable_offset(ptr %ptr, i64 %offset) {
+; CHECK-LABEL: @test_align_with_variable_offset(
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 8, i64 [[OFFSET:%.*]]) ]
+; CHECK-NEXT: ret i1 true
+;
+ call void @llvm.assume(i1 true) ["align"(ptr %ptr, i64 8, i64 %offset)]
+ %intptr = ptrtoint ptr %ptr to i64
+ %and = and i64 %intptr, 7
+ %is_aligned = icmp eq i64 %and, 0
+ ret i1 %is_aligned
+}
diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll
index a154e254c138e..c1ccb49209227 100644
--- a/llvm/test/Transforms/InstCombine/assume.ll
+++ b/llvm/test/Transforms/InstCombine/assume.ll
@@ -121,6 +121,77 @@ entry:
ret void
}
+define void @align_with_constant_offset_0(ptr %ptr) {
+; DEFAULT-LABEL: @align_with_constant_offset_0(
+; DEFAULT-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 16) ]
+; DEFAULT-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR]], i64 8, i64 0) ]
+; DEFAULT-NEXT: ret void
+;
+; BUNDLES-LABEL: @align_with_constant_offset_0(
+; BUNDLES-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 16, i64 0) ]
+; BUNDLES-NEXT: ret void
+;
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 16) ]
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 8, i64 0) ]
+ ret void
+}
+
+define void @align_with_constant_offset_1(ptr %ptr) {
+; CHECK-LABEL: @align_with_constant_offset_1(
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 16) ]
+; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 9
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR2]], i64 8, i64 1) ]
+; CHECK-NEXT: ret void
+;
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 16) ]
+ %ptr2 = getelementptr i8, ptr %ptr, i64 9
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr2, i64 8, i64 1) ]
+ ret void
+}
+
+define void @align_with_constant_offset_4(ptr %ptr) {
+; CHECK-LABEL: @align_with_constant_offset_4(
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 16) ]
+; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 4
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR2]], i64 8, i64 4) ]
+; CHECK-NEXT: ret void
+;
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 16) ]
+ %ptr2 = getelementptr i8, ptr %ptr, i64 4
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr2, i64 8, i64 4) ]
+ ret void
+}
+
+define void @align_with_constant_offset_8(ptr %ptr) {
+; DEFAULT-LABEL: @align_with_constant_offset_8(
+; DEFAULT-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 16) ]
+; DEFAULT-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR]], i64 8, i64 8) ]
+; DEFAULT-NEXT: ret void
+;
+; BUNDLES-LABEL: @align_with_constant_offset_8(
+; BUNDLES-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 16, i64 8) ]
+; BUNDLES-NEXT: ret void
+;
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 16) ]
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 8, i64 8) ]
+ ret void
+}
+
+define void @align_with_variable_offset(ptr %ptr, i64 %offset) {
+; DEFAULT-LABEL: @align_with_variable_offset(
+; DEFAULT-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 16) ]
+; DEFAULT-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR]], i64 8, i64 [[OFFSET:%.*]]) ]
+; DEFAULT-NEXT: ret void
+;
+; BUNDLES-LABEL: @align_with_variable_offset(
+; BUNDLES-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 16, i64 [[OFFSET:%.*]]) ]
+; BUNDLES-NEXT: ret void
+;
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 16) ]
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 8, i64 %offset) ]
+ ret void
+}
+
define void @redundant_align() {
; CHECK-LABEL: @redundant_align(
; CHECK-NEXT: [[PTR:%.*]] = call ptr @get_ptr()
>From 418b809d38200244d5d5b9586a73747c44cfb3f9 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 4 Jun 2026 15:53:33 +0200
Subject: [PATCH 10/12] Fix test
---
llvm/test/Analysis/ValueTracking/assume.ll | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/llvm/test/Analysis/ValueTracking/assume.ll b/llvm/test/Analysis/ValueTracking/assume.ll
index fa5a03ba997c4..c5fe253634716 100644
--- a/llvm/test/Analysis/ValueTracking/assume.ll
+++ b/llvm/test/Analysis/ValueTracking/assume.ll
@@ -249,7 +249,10 @@ define i1 @test_align_with_constant_offset_8(ptr %ptr) {
define i1 @test_align_with_variable_offset(ptr %ptr, i64 %offset) {
; CHECK-LABEL: @test_align_with_variable_offset(
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 8, i64 [[OFFSET:%.*]]) ]
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: [[INTPTR:%.*]] = ptrtoint ptr [[PTR]] to i64
+; CHECK-NEXT: [[AND:%.*]] = and i64 [[INTPTR]], 7
+; CHECK-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i64 [[AND]], 0
+; CHECK-NEXT: ret i1 [[IS_ALIGNED]]
;
call void @llvm.assume(i1 true) ["align"(ptr %ptr, i64 8, i64 %offset)]
%intptr = ptrtoint ptr %ptr to i64
>From 7f6307b35cd72571dc664778604cc6fbc4c58a82 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 4 Jun 2026 16:35:29 +0200
Subject: [PATCH 11/12] Reject alignment and offsets with more than 64 bits
---
llvm/lib/IR/Verifier.cpp | 15 +++++++++++----
llvm/test/Verifier/assume-bundles.ll | 8 ++++++--
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index cedf477472451..4420a090a146d 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -6120,10 +6120,17 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
"alignment assumptions should have 2 or 3 arguments", Call);
Check(GetTypeAt(0)->isPointerTy(), "first argument should be a pointer",
Call);
- Check(GetTypeAt(1)->isIntegerTy(),
- "second argument should be an integer", Call);
- Check(OBU.Inputs.size() < 3 || GetTypeAt(2)->isIntegerTy(),
- "third argument should be an integer if present", Call);
+ Check(GetTypeAt(1)->isIntegerTy() &&
+ GetTypeAt(1)->getIntegerBitWidth() <= 64,
+ "second argument should be an integer with a maximum width of 64 "
+ "bits",
+ Call);
+ Check(OBU.Inputs.size() < 3 ||
+ GetTypeAt(2)->isIntegerTy() &&
+ GetTypeAt(2)->getIntegerBitWidth() <= 64,
+ "third argument should be an integer with a maximum width of 64 "
+ "bits if present",
+ Call);
break;
case BundleAttr::Cold:
Check(OBU.Inputs.size() == 0,
diff --git a/llvm/test/Verifier/assume-bundles.ll b/llvm/test/Verifier/assume-bundles.ll
index 18d04b978d013..efba13dd7c7c5 100644
--- a/llvm/test/Verifier/assume-bundles.ll
+++ b/llvm/test/Verifier/assume-bundles.ll
@@ -22,10 +22,14 @@ define void @func(ptr %P, i32 %P1, ptr %P2, ptr %P3, i1 %cond) {
call void @llvm.assume(i1 true) ["align"(ptr %P, i32 %P1, i32 4, i32 4)]
; CHECK: first argument should be a pointer
call void @llvm.assume(i1 true) ["align"(i32 %P1, ptr %P2)]
-; CHECK: second argument should be an integer
+; CHECK: second argument should be an integer with a maximum width of 64 bits
call void @llvm.assume(i1 true) ["align"(ptr %P, ptr %P2)]
-; CHECK: third argument should be an integer if present
+; CHECK: second argument should be an integer with a maximum width of 64 bits
+ call void @llvm.assume(i1 true) ["align"(ptr %P, i65 1)]
+; CHECK: third argument should be an integer with a maximum width of 64 bits if present
call void @llvm.assume(i1 true) ["align"(ptr %P, i32 %P1, ptr %P2)]
+; CHECK: third argument should be an integer with a maximum width of 64 bits if present
+ call void @llvm.assume(i1 true) ["align"(ptr %P, i32 %P1, i65 1)]
; Cold checks
;
>From 9d8ed4b7628ec329ec4a3eefb0a266abd82fe2ef Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 4 Jun 2026 17:04:23 +0200
Subject: [PATCH 12/12] Fix test
---
llvm/test/Transforms/AlignmentFromAssumptions/simple.ll | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/llvm/test/Transforms/AlignmentFromAssumptions/simple.ll b/llvm/test/Transforms/AlignmentFromAssumptions/simple.ll
index c2f2d21fafc40..d908c2a5206fa 100644
--- a/llvm/test/Transforms/AlignmentFromAssumptions/simple.ll
+++ b/llvm/test/Transforms/AlignmentFromAssumptions/simple.ll
@@ -285,7 +285,7 @@ define i32 @koo2(ptr nocapture %a) {
; CHECK-LABEL: define i32 @koo2
; CHECK-SAME: (ptr captures(none) [[A:%.*]]) {
; CHECK-NEXT: entry:
-; CHECK-NEXT: tail call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i128 32, i128 0) ]
+; CHECK-NEXT: tail call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 32, i64 0) ]
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ -4, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
@@ -302,7 +302,7 @@ define i32 @koo2(ptr nocapture %a) {
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
;
entry:
- tail call void @llvm.assume(i1 true) ["align"(ptr %a, i128 32, i128 0)]
+ tail call void @llvm.assume(i1 true) ["align"(ptr %a, i64 32, i64 0)]
br label %for.body
for.body: ; preds = %entry, %for.body
@@ -399,4 +399,3 @@ declare void @llvm.assume(i1) nounwind
declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1) nounwind
declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1) nounwind
-
More information about the llvm-commits
mailing list