[llvm-branch-commits] [clang] [flang] [lld] [lldb] [llvm] [CodeGen] Declare command line options in TableGen (PR #228729)
Fangrui Song via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Oct 4 08:56:15 PDT 2026
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/228729
>From c275ebd64bf5b05e36a3a8e8b8daa32ba9a52aac Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Sun, 4 Oct 2026 00:17:21 -0700
Subject: [PATCH 01/18] [ADT] Use StorageT for temporary storage in
DenseMapBase::grow (NFC) (#228802)
Without this patch, the non-relocatable path of DenseMapBase::grow
rehashes into a temporary DenseMapBase instance:
DenseMapBase Tmp(NumBuckets, ExactBucketCount{});
This patch switches to:
StorageT Tmp;
while converting initEmpty, initWithExactBucketCount, and moveFrom to
static helpers to operate directly on StorageT. This brings the
following benefits:
- grow() no longer calls the destructor for Tmp because StorageT does
not have one. Without this patch, we call Tmp.~DenseMapBase(), which
in turn calls destroyAll() even though the bucket array has no
elements to destruct. Even with inlining enabled, the host compiler
retains the body of destroyAll() because NumBuckets == 0 is set inside
moveFrom, which is marked LLVM_ATTRIBUTE_NOINLINE.
- We get to remove the following helpers as their only purpose is to
facilitate a temporary instance of DenseMapBase during grow():
- DenseMapBase::ExactBucketCount
- DenseMapBase::DenseMapBase(unsigned, ExactBucketCount)
- DenseMapStorage::kill()
- SmallDenseMapStorage::kill()
Assisted-by: Antigravity
---
llvm/include/llvm/ADT/DenseMap.h | 88 +++++++++++++-------------------
1 file changed, 36 insertions(+), 52 deletions(-)
diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index dc77237f75d93..92eae370e0219 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -269,10 +269,6 @@ template <typename BucketT> class DenseMapStorage {
return true;
}
- // Put the zombie instance in a known good state after a move.
- // deallocateBuckets() already resets to the empty state.
- void kill() { deallocateBuckets(); }
-
static unsigned roundUpNumBuckets(unsigned MinNumBuckets) {
return std::max(64u, MinNumBuckets);
}
@@ -487,13 +483,6 @@ class SmallDenseMapStorage {
return true;
}
- // Put the zombie instance in a known good state after a move.
- void kill() {
- deallocateBuckets();
- Small = false;
- storage.Large = LargeRep{nullptr, nullptr, 0};
- }
-
static unsigned roundUpNumBuckets(unsigned MinNumBuckets) {
if (MinNumBuckets <= InlineBuckets)
return InlineBuckets;
@@ -762,11 +751,11 @@ class DenseMapBase : public DebugEpochBase {
auto [Reallocate, NewNumBuckets] = Storage.planShrinkAndClear();
destroyAll();
if (!Reallocate) {
- initEmpty();
+ initEmpty(Storage);
return;
}
Storage.deallocateBuckets();
- initWithExactBucketCount(NewNumBuckets);
+ initWithExactBucketCount(Storage, NewNumBuckets);
}
/// Return true if the specified key is in the map, false otherwise.
@@ -1002,7 +991,7 @@ class DenseMapBase : public DebugEpochBase {
/// that this number of elements can be inserted in the map without grow().
explicit DenseMapBase(unsigned NumElementsToReserve) {
initWithExactBucketCount(
- getMinBucketToReserveForEntries(NumElementsToReserve));
+ Storage, getMinBucketToReserveForEntries(NumElementsToReserve));
}
DenseMapBase(const DenseMapBase &other) : DenseMapBase() {
@@ -1038,7 +1027,7 @@ class DenseMapBase : public DebugEpochBase {
DenseMapBase &operator=(DenseMapBase &&other) {
this->destroyAll();
Storage.deallocateBuckets();
- this->initWithExactBucketCount(0);
+ initWithExactBucketCount(Storage, 0);
this->swap(other);
return *this;
}
@@ -1054,19 +1043,22 @@ class DenseMapBase : public DebugEpochBase {
private:
StorageT Storage;
- struct ExactBucketCount {};
-
using Rep = llvm::densemap::detail::StorageRep<BucketT>;
- DenseMapBase(unsigned NumBuckets, ExactBucketCount) {
- initWithExactBucketCount(NumBuckets);
+ static void initEmpty(StorageT &S) {
+ S.setNumEntries(0);
+
+ assert((S.getNumBuckets() & (S.getNumBuckets() - 1)) == 0 &&
+ "# initial buckets must be a power of two!");
+ if (S.getNumBuckets())
+ llvm::densemap::detail::clearUsed(S.getUsed(), S.getNumBuckets());
}
- void initWithExactBucketCount(unsigned NewNumBuckets) {
- if (Storage.allocateBuckets(NewNumBuckets))
- initEmpty();
+ static void initWithExactBucketCount(StorageT &S, unsigned NewNumBuckets) {
+ if (S.allocateBuckets(NewNumBuckets))
+ initEmpty(S);
else
- setNumEntries(0);
+ S.setNumEntries(0);
}
void destroyAll() {
@@ -1087,15 +1079,6 @@ class DenseMapBase : public DebugEpochBase {
});
}
- void initEmpty() {
- setNumEntries(0);
-
- assert((getNumBuckets() & (getNumBuckets() - 1)) == 0 &&
- "# initial buckets must be a power of two!");
- if (getNumBuckets())
- llvm::densemap::detail::clearUsed(getUsed(), getNumBuckets());
- }
-
/// Returns the number of buckets to allocate to ensure that the DenseMap can
/// accommodate \p NumEntries without need to grow().
unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
@@ -1111,27 +1094,27 @@ class DenseMapBase : public DebugEpochBase {
return llvm::densemap::detail::hasherFor<KeyT, KeyInfoT>();
}
- // Move key/value from Other to *this.
- // Other is left in a valid but empty state.
- LLVM_ATTRIBUTE_NOINLINE void moveFrom(DenseMapBase &Other) {
- assert(getNumEntries() == 0 && "moveFrom requires an empty destination");
- BucketT *OtherB = Other.getBuckets();
- UsedT *OtherU = Other.getUsed();
- const unsigned E = Other.getNumBuckets();
- UsedT *U = getUsed();
- BucketT *B = getBuckets();
- const unsigned Mask = getNumBuckets() - 1;
- llvm::densemap::detail::forEachUsed(OtherU, E, [&](unsigned I) {
+ // Move key/value from Src to Dst.
+ static LLVM_ATTRIBUTE_NOINLINE void moveFrom(StorageT &Dst, StorageT &Src) {
+ assert(Dst.getNumEntries() == 0 &&
+ "moveFrom requires an empty destination");
+ BucketT *SrcB = Src.getBuckets();
+ UsedT *SrcU = Src.getUsed();
+ const unsigned E = Src.getNumBuckets();
+ UsedT *U = Dst.getUsed();
+ BucketT *B = Dst.getBuckets();
+ const unsigned Mask = Dst.getNumBuckets() - 1;
+ llvm::densemap::detail::forEachUsed(SrcU, E, [&](unsigned I) {
// Find the first empty slot on this key's probe chain; there is no equal
// key in the destination, so nothing to compare against.
- unsigned BucketNo = KeyInfoT::getHashValue(OtherB[I].getFirst()) & Mask;
+ unsigned BucketNo = KeyInfoT::getHashValue(SrcB[I].getFirst()) & Mask;
while (llvm::densemap::detail::used(U, BucketNo))
BucketNo = (BucketNo + 1) & Mask;
- llvm::densemap::detail::relocateBucket(B + BucketNo, &OtherB[I]);
+ llvm::densemap::detail::relocateBucket(B + BucketNo, &SrcB[I]);
llvm::densemap::detail::setUsed(U, BucketNo);
});
- setNumEntries(Other.getNumEntries());
- Other.Storage.kill();
+ Dst.setNumEntries(Src.getNumEntries());
+ Src.deallocateBuckets();
}
LLVM_ATTRIBUTE_NOINLINE void copyFrom(const DenseMapBase &other) {
@@ -1253,12 +1236,13 @@ class DenseMapBase : public DebugEpochBase {
Storage.grow(MinNumBuckets, hasher());
} else {
unsigned NumBuckets = StorageT::roundUpNumBuckets(MinNumBuckets);
- DenseMapBase Tmp(NumBuckets, ExactBucketCount{});
- Tmp.moveFrom(*this);
- if (Storage.maybeMoveFast(std::move(Tmp.Storage)))
+ StorageT Tmp;
+ initWithExactBucketCount(Tmp, NumBuckets);
+ moveFrom(Tmp, Storage);
+ if (Storage.maybeMoveFast(std::move(Tmp)))
return;
- initWithExactBucketCount(NumBuckets);
- moveFrom(Tmp);
+ initWithExactBucketCount(Storage, NumBuckets);
+ moveFrom(Storage, Tmp);
}
}
>From 2c9a3d2870b263526d803b1ea6c5c98923a70d0f Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 4 Oct 2026 10:10:47 +0200
Subject: [PATCH 02/18] offload: Remove Johannes from current maintainers
(#228853)
---
offload/Maintainers.md | 3 ---
1 file changed, 3 deletions(-)
diff --git a/offload/Maintainers.md b/offload/Maintainers.md
index 8dd4b6221d6cc..972ab3e28aa89 100644
--- a/offload/Maintainers.md
+++ b/offload/Maintainers.md
@@ -6,8 +6,5 @@ the LLVM Offloading library.
# Current Maintainers
-Johannes Doerfert \
-jdoerfert at llnl.gov (email), [jdoerfert](https://github.com/jdoerfert) (GitHub)
-
Joseph Huber \
joseph.huber at amd.com (email), [jhuber6](https://github.com/jhuber6) (Github)
>From 32d1053b64b5f26f06960e65da313879ec968086 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Sun, 4 Oct 2026 01:20:48 -0700
Subject: [PATCH 03/18] [CodeGen] Remove unused functions (NFC) (#228844)
LiveVariables::replaceKillInstruction: The last caller was removed on
October 1, 2026 in commit 8068182dd6fb1a8efae0291db1d2462d29025cd1.
TargetLoweringBase::getSupportedLibcallImpl: The last caller was
removed on October 24, 2025 in commit
26450db480761c0fedf319fc350178798ce7e547.
Assisted-by: Antigravity
---
llvm/include/llvm/CodeGen/LiveVariables.h | 5 -----
llvm/include/llvm/CodeGen/TargetLowering.h | 6 ------
llvm/lib/CodeGen/LiveVariables.cpp | 8 --------
3 files changed, 19 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/LiveVariables.h b/llvm/include/llvm/CodeGen/LiveVariables.h
index c6e0c8419f35b..4b06c5b48335f 100644
--- a/llvm/include/llvm/CodeGen/LiveVariables.h
+++ b/llvm/include/llvm/CodeGen/LiveVariables.h
@@ -192,11 +192,6 @@ class LiveVariables {
/// machine function to be in SSA form.
LLVM_ABI void recomputeForSingleDefVirtReg(Register Reg);
- /// replaceKillInstruction - Update register kill info by replacing a kill
- /// instruction with a new one.
- LLVM_ABI void replaceKillInstruction(Register Reg, MachineInstr &OldMI,
- MachineInstr &NewMI);
-
/// addVirtualRegisterKilled - Add information about the fact that the
/// specified register is killed after being used by the specified
/// instruction. If AddIfNotFound is true, add a implicit operand if it's
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 91221f31b49a3..ab92757abeb66 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -3785,12 +3785,6 @@ class LLVM_ABI TargetLoweringBase {
RTLIB::LibcallImpl getMemcpyImpl() const { return Libcalls.getMemcpyImpl(); }
- /// Check if this is valid libcall for the current module, otherwise
- /// RTLIB::Unsupported.
- RTLIB::LibcallImpl getSupportedLibcallImpl(StringRef FuncName) const {
- return RuntimeLibcallInfo.getSupportedLibcallImpl(FuncName);
- }
-
/// Get the CallingConv that should be used for the specified libcall
/// implementation.
CallingConv::ID getLibcallImplCallingConv(RTLIB::LibcallImpl Call) const {
diff --git a/llvm/lib/CodeGen/LiveVariables.cpp b/llvm/lib/CodeGen/LiveVariables.cpp
index 1d6168618b751..5ce12c481bf16 100644
--- a/llvm/lib/CodeGen/LiveVariables.cpp
+++ b/llvm/lib/CodeGen/LiveVariables.cpp
@@ -729,14 +729,6 @@ void LiveVariables::recomputeForSingleDefVirtReg(Register Reg) {
}
}
-/// replaceKillInstruction - Update register kill info by replacing a kill
-/// instruction with a new one.
-void LiveVariables::replaceKillInstruction(Register Reg, MachineInstr &OldMI,
- MachineInstr &NewMI) {
- VarInfo &VI = getVarInfo(Reg);
- llvm::replace(VI.Kills, &OldMI, &NewMI);
-}
-
/// removeVirtualRegistersKilled - Remove all killed info for the specified
/// instruction.
void LiveVariables::removeVirtualRegistersKilled(MachineInstr &MI) {
>From eddb17da45c0d2c23d71a1cef3e09821989988f2 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Sun, 4 Oct 2026 02:26:22 -0700
Subject: [PATCH 04/18] [clang] Migrate away from PointerUnion::dyn_cast (NFC)
(#228843)
Note that PointerUnion::dyn_cast has been soft deprecated in
PointerUnion.h:
// FIXME: Replace the uses of is(), get() and dyn_cast() with
// isa<T>, cast<T> and the llvm::dyn_cast<T>
Literal migration would result in dyn_cast_if_present (see the
definition of PointerUnion::dyn_cast), but this patch uses dyn_cast.
Note that the if-then-else chain ends with:
} else
llvm_unreachable("Unhandled CausingFact type");
which guarantees that CausingFact is nonnull.
Assisted-by: Antigravity
---
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index c4cc872dcd568..29063398bfcd8 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -277,7 +277,7 @@ class LifetimeChecker {
const Expr *MovedExpr = Warning.MovedExpr;
SourceLocation ExpiryLoc = Warning.ExpiryLoc;
- if (const auto *UF = CausingFact.dyn_cast<const UseFact *>()) {
+ if (const auto *UF = dyn_cast<const UseFact *>(CausingFact)) {
llvm::SmallVector<const Expr *> ExprChain =
getExprChain(LoanPropagation.buildOriginFlowChain(UF, LID, Cfg));
if (Warning.InvalidatedByExpr) {
@@ -298,7 +298,7 @@ class LifetimeChecker {
MovedExpr, ExpiryLoc, ExprChain);
} else if (const auto *OEF =
- CausingFact.dyn_cast<const OriginEscapesFact *>()) {
+ dyn_cast<const OriginEscapesFact *>(CausingFact)) {
if (Warning.InvalidatedByExpr) {
if (const auto *FieldEscape = dyn_cast<FieldEscapeFact>(OEF)) {
// Invalidated object escapes to a field.
>From b11606a912ae297cc4b9db6a7c59f44b0e326aa6 Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Sun, 4 Oct 2026 06:38:51 -0400
Subject: [PATCH 05/18] [SLP]Fix regressions after the fmul/fadd fusion cost
changes
Revisit the standalone seeds skipped as dependent on the lanes of a
vectorized window, instead of dropping them until the next SLP run.
Do not credit the fusion of the root of a loop-carried fadd reduction:
the chain through the loop phi is bound by its latency, which the
vector code cuts.
Fixes regressions in RAJAPerf.
Assisted-by: Cursor
Reviewers: RKSimon, bababuck
Pull Request: https://github.com/llvm/llvm-project/pull/228720
---
.../Transforms/Vectorize/SLPVectorizer.cpp | 30 ++++++++++++-----
.../AArch64/loop-accumulator-reduction.ll | 32 +++++++++----------
.../Transforms/SLPVectorizer/X86/c-ray.ll | 16 ++++++----
.../SLPVectorizer/X86/dependent-seeds.ll | 7 ++--
4 files changed, 50 insertions(+), 35 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index a03dfe49a85f1..c105f41bc15ab 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -30649,8 +30649,8 @@ bool SLPVectorizerPass::tryToVectorizeList(ArrayRef<Value *> VL, BoUpSLP &R,
SmallVector<Value *> Ops(ActualVF, nullptr);
unsigned Idx = 0;
SmallPtrSet<const Value *, 8> Taken;
- bool DependentSkipped = false;
- for (Value *V : VL.drop_front(I)) {
+ std::optional<unsigned> FirstSkipped;
+ for (auto [Off, V] : enumerate(VL.drop_front(I))) {
// Check that a previous iteration of this loop did not delete the
// Value.
auto *Inst = dyn_cast<Instruction>(V);
@@ -30661,7 +30661,8 @@ bool SLPVectorizerPass::tryToVectorizeList(ArrayRef<Value *> VL, BoUpSLP &R,
if (StandaloneSeeds && Inst &&
any_of(Inst->operand_values(),
[&](const Value *Op) { return Taken.contains(Op); })) {
- DependentSkipped = true;
+ if (!FirstSkipped)
+ FirstSkipped = I + Off;
continue;
}
Ops[Idx] = V;
@@ -30674,7 +30675,7 @@ bool SLPVectorizerPass::tryToVectorizeList(ArrayRef<Value *> VL, BoUpSLP &R,
// Not enough vectorizable instructions - exit. A skipped dependent seed
// may start the next window, so the scan must not stop because of it.
if (Idx != ActualVF) {
- if (!DependentSkipped)
+ if (!FirstSkipped)
break;
continue;
}
@@ -30727,8 +30728,9 @@ bool SLPVectorizerPass::tryToVectorizeList(ArrayRef<Value *> VL, BoUpSLP &R,
<< ore::NV("TreeSize", R.getTreeSize()));
R.vectorizeTree();
- // Move to the next bundle.
- I += VF - 1;
+ // Move to the next bundle. The skipped dependent seeds are fed by the
+ // vectorized lanes now, the next bundle starts from the first of them.
+ I = FirstSkipped ? *FirstSkipped - 1 : I + VF - 1;
NextInst = I + 1;
Changed = true;
} else {
@@ -34009,6 +34011,15 @@ class HorizontalReduction {
return cast<Instruction>(U);
return cast<Instruction>(RdxVal);
};
+ // The root is accumulated through the phi of its loop.
+ const bool IsLoopCarriedRoot =
+ RdxKind == RecurKind::FAdd &&
+ any_of(ReductionRoot->users(), [&](User *U) {
+ auto *Phi = dyn_cast<PHINode>(U);
+ return Phi &&
+ DT.dominates(Phi->getParent(),
+ cast<Instruction>(ReductionRoot)->getParent());
+ });
auto EvaluateScalarCost =
[&](function_ref<InstructionCost(Instruction *)> GenCostFn) {
InstructionCost Cost = 0;
@@ -34032,8 +34043,11 @@ class HorizontalReduction {
for (User *U : RdxVal->users()) {
auto *RdxOp = cast<Instruction>(U);
// The reduction root is used outside of the reduction any
- // number of times, its fmul operand is still fused into it.
- if ((RdxKind == RecurKind::FAdd && RdxOp == ReductionRoot) ||
+ // number of times, its fmul operand is still fused into it. The
+ // loop-carried chain is bound by its latency, so the fusion does
+ // not make it cheaper than the vector code, which cuts the chain.
+ if ((RdxKind == RecurKind::FAdd && RdxOp == ReductionRoot &&
+ !IsLoopCarriedRoot) ||
hasRequiredNumberOfUses(IsCmpSelMinMax, RdxOp)) {
InstructionsState RdxOpS = RdxKind == RecurKind::FAdd
? getSameOpcode(RdxOp, TLI)
diff --git a/llvm/test/Transforms/SLPVectorizer/AArch64/loop-accumulator-reduction.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/loop-accumulator-reduction.ll
index 41b197a68e4d0..15223e0bbe69b 100644
--- a/llvm/test/Transforms/SLPVectorizer/AArch64/loop-accumulator-reduction.ll
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/loop-accumulator-reduction.ll
@@ -1359,12 +1359,12 @@ define double @loop_acc_fmul_chain(ptr %a, ptr %b, i64 %n, i64 %na, i64 %nb, dou
; CHECK-LABEL: define double @loop_acc_fmul_chain(
; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i64 [[N:%.*]], i64 [[NA:%.*]], i64 [[NB:%.*]], double [[ALPHA:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x double> poison, double [[ALPHA]], i64 0
-; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x double> [[TMP0]], <2 x double> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x double> <double poison, double 1.000000e+00, double poison, double poison>, double [[ALPHA]], i64 0
+; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x double> [[TMP0]], <4 x double> poison, <4 x i32> <i32 0, i32 0, i32 0, i32 1>
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[K:%.*]] = phi i64 [ [[K_NEXT:%.*]], %[[LOOP]] ], [ 0, %[[ENTRY]] ]
-; CHECK-NEXT: [[DOT1:%.*]] = phi double [ [[OP_RDX1:%.*]], %[[LOOP]] ], [ 0.000000e+00, %[[ENTRY]] ]
+; CHECK-NEXT: [[DOT:%.*]] = phi double [ [[OP_RDX1:%.*]], %[[LOOP]] ], [ 0.000000e+00, %[[ENTRY]] ]
; CHECK-NEXT: [[AM0:%.*]] = mul nuw nsw i64 [[K]], [[NA]]
; CHECK-NEXT: [[PA0:%.*]] = getelementptr double, ptr [[A]], i64 [[AM0]]
; CHECK-NEXT: [[A0:%.*]] = load double, ptr [[PA0]], align 8
@@ -1373,32 +1373,32 @@ define double @loop_acc_fmul_chain(ptr %a, ptr %b, i64 %n, i64 %na, i64 %nb, dou
; CHECK-NEXT: [[PB0:%.*]] = getelementptr double, ptr [[B]], i64 [[BM0]]
; CHECK-NEXT: [[B0:%.*]] = load double, ptr [[PB0]], align 8
; CHECK-NEXT: [[PROD0:%.*]] = fmul fast double [[SCALED0]], [[B0]]
-; CHECK-NEXT: [[ADD0:%.*]] = fadd fast double [[PROD0]], [[DOT1]]
; CHECK-NEXT: [[K1:%.*]] = add nuw nsw i64 [[K]], 1
; CHECK-NEXT: [[PA1:%.*]] = getelementptr double, ptr [[A]], i64 [[K1]]
-; CHECK-NEXT: [[A1:%.*]] = load double, ptr [[PA1]], align 8
-; CHECK-NEXT: [[SCALED1:%.*]] = fmul fast double [[A1]], [[ALPHA]]
; CHECK-NEXT: [[BM1:%.*]] = mul nuw nsw i64 [[K1]], [[NB]]
; CHECK-NEXT: [[PB1:%.*]] = getelementptr double, ptr [[B]], i64 [[BM1]]
; CHECK-NEXT: [[B1:%.*]] = load double, ptr [[PB1]], align 8
-; CHECK-NEXT: [[PROD1:%.*]] = fmul fast double [[SCALED1]], [[B1]]
-; CHECK-NEXT: [[ADD1:%.*]] = fadd fast double [[PROD1]], [[ADD0]]
; CHECK-NEXT: [[K2:%.*]] = add nuw nsw i64 [[K]], 2
-; CHECK-NEXT: [[PA2:%.*]] = getelementptr double, ptr [[A]], i64 [[K2]]
; CHECK-NEXT: [[BM2:%.*]] = mul nuw nsw i64 [[K2]], [[NB]]
; CHECK-NEXT: [[PB2:%.*]] = getelementptr double, ptr [[B]], i64 [[BM2]]
; CHECK-NEXT: [[B2:%.*]] = load double, ptr [[PB2]], align 8
; CHECK-NEXT: [[K3:%.*]] = add nuw nsw i64 [[K]], 3
-; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr [[PA2]], align 8
-; CHECK-NEXT: [[TMP3:%.*]] = fmul fast <2 x double> [[TMP2]], [[TMP1]]
-; CHECK-NEXT: [[TMP4:%.*]] = extractelement <2 x double> [[TMP3]], i64 0
-; CHECK-NEXT: [[PROD2:%.*]] = fmul fast double [[TMP4]], [[B2]]
-; CHECK-NEXT: [[DOT:%.*]] = fadd fast double [[PROD2]], [[ADD1]]
+; CHECK-NEXT: [[PA3:%.*]] = getelementptr double, ptr [[A]], i64 [[K3]]
+; CHECK-NEXT: [[A3:%.*]] = load double, ptr [[PA3]], align 8
; CHECK-NEXT: [[BM3:%.*]] = mul nuw nsw i64 [[K3]], [[NB]]
; CHECK-NEXT: [[PB3:%.*]] = getelementptr double, ptr [[B]], i64 [[BM3]]
; CHECK-NEXT: [[B3:%.*]] = load double, ptr [[PB3]], align 8
-; CHECK-NEXT: [[TMP5:%.*]] = extractelement <2 x double> [[TMP3]], i64 1
-; CHECK-NEXT: [[OP_RDX:%.*]] = fmul fast double [[TMP5]], [[B3]]
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr [[PA1]], align 8
+; CHECK-NEXT: [[TMP3:%.*]] = insertelement <4 x double> <double poison, double poison, double poison, double 1.000000e+00>, double [[A3]], i64 2
+; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <2 x double> [[TMP2]], <2 x double> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <4 x double> [[TMP3]], <4 x double> [[TMP4]], <4 x i32> <i32 4, i32 5, i32 2, i32 3>
+; CHECK-NEXT: [[TMP6:%.*]] = fmul fast <4 x double> [[TMP5]], [[TMP1]]
+; CHECK-NEXT: [[TMP7:%.*]] = insertelement <4 x double> <double poison, double poison, double poison, double 0.000000e+00>, double [[B1]], i64 0
+; CHECK-NEXT: [[TMP8:%.*]] = insertelement <4 x double> [[TMP7]], double [[B2]], i64 1
+; CHECK-NEXT: [[TMP9:%.*]] = insertelement <4 x double> [[TMP8]], double [[B3]], i64 2
+; CHECK-NEXT: [[TMP10:%.*]] = fmul fast <4 x double> [[TMP9]], [[TMP6]]
+; CHECK-NEXT: [[TMP11:%.*]] = call fast double @llvm.vector.reduce.fadd.v4f64(double 0.000000e+00, <4 x double> [[TMP10]])
+; CHECK-NEXT: [[OP_RDX:%.*]] = fadd fast double [[TMP11]], [[PROD0]]
; CHECK-NEXT: [[OP_RDX1]] = fadd fast double [[OP_RDX]], [[DOT]]
; CHECK-NEXT: [[K_NEXT]] = add nuw nsw i64 [[K]], 4
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[K_NEXT]], [[N]]
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/c-ray.ll b/llvm/test/Transforms/SLPVectorizer/X86/c-ray.ll
index 79945d8372b05..b19ace8e6abdd 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/c-ray.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/c-ray.ll
@@ -13,7 +13,6 @@ define i32 @ray_sphere(ptr nocapture noundef readonly %sph, ptr nocapture nounde
; SSE2-NEXT: entry:
; SSE2-NEXT: [[DIR:%.*]] = getelementptr inbounds [[STRUCT_RAY:%.*]], ptr [[RAY:%.*]], i64 0, i32 1
; SSE2-NEXT: [[Z:%.*]] = getelementptr inbounds [[STRUCT_RAY]], ptr [[RAY]], i64 0, i32 1, i32 2
-; SSE2-NEXT: [[TMP3:%.*]] = load double, ptr [[Z]], align 8
; SSE2-NEXT: [[TMP5:%.*]] = load double, ptr [[RAY]], align 8
; SSE2-NEXT: [[TMP6:%.*]] = load double, ptr [[SPH:%.*]], align 8
; SSE2-NEXT: [[SUB:%.*]] = fsub double [[TMP5]], [[TMP6]]
@@ -31,16 +30,17 @@ define i32 @ray_sphere(ptr nocapture noundef readonly %sph, ptr nocapture nounde
; SSE2-NEXT: [[TMP45:%.*]] = fmul <2 x double> [[TMP43]], [[TMP44]]
; SSE2-NEXT: [[TMP46:%.*]] = insertelement <2 x double> [[TMP40]], double [[SUB]], i64 1
; SSE2-NEXT: [[TMP47:%.*]] = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> [[TMP41]], <2 x double> [[TMP46]], <2 x double> [[TMP45]])
-; SSE2-NEXT: [[TMP48:%.*]] = extractelement <2 x double> [[TMP47]], i64 0
-; SSE2-NEXT: [[TMP4:%.*]] = tail call double @llvm.fmuladd.f64(double [[TMP3]], double [[TMP3]], double [[TMP48]])
-; SSE2-NEXT: [[MUL26:%.*]] = fmul double [[TMP3]], 2.000000e+00
; SSE2-NEXT: [[Z28:%.*]] = getelementptr inbounds [[STRUCT_VEC3]], ptr [[RAY]], i64 0, i32 2
; SSE2-NEXT: [[TMP10:%.*]] = load double, ptr [[Z28]], align 8
; SSE2-NEXT: [[Z30:%.*]] = getelementptr inbounds [[STRUCT_VEC3]], ptr [[SPH]], i64 0, i32 2
; SSE2-NEXT: [[TMP11:%.*]] = load double, ptr [[Z30]], align 8
; SSE2-NEXT: [[SUB31:%.*]] = fsub double [[TMP10]], [[TMP11]]
-; SSE2-NEXT: [[TMP9:%.*]] = extractelement <2 x double> [[TMP47]], i64 1
-; SSE2-NEXT: [[TMP12:%.*]] = tail call double @llvm.fmuladd.f64(double [[MUL26]], double [[SUB31]], double [[TMP9]])
+; SSE2-NEXT: [[TMP48:%.*]] = load double, ptr [[Z]], align 8
+; SSE2-NEXT: [[TMP49:%.*]] = insertelement <2 x double> poison, double [[TMP48]], i64 0
+; SSE2-NEXT: [[TMP50:%.*]] = shufflevector <2 x double> [[TMP49]], <2 x double> poison, <2 x i32> zeroinitializer
+; SSE2-NEXT: [[TMP51:%.*]] = fmul <2 x double> [[TMP50]], <double 1.000000e+00, double 2.000000e+00>
+; SSE2-NEXT: [[TMP52:%.*]] = insertelement <2 x double> [[TMP50]], double [[SUB31]], i64 1
+; SSE2-NEXT: [[TMP53:%.*]] = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> [[TMP51]], <2 x double> [[TMP52]], <2 x double> [[TMP47]])
; SSE2-NEXT: [[MUL42:%.*]] = fmul double [[TMP8]], [[TMP8]]
; SSE2-NEXT: [[TMP13:%.*]] = tail call double @llvm.fmuladd.f64(double [[TMP6]], double [[TMP6]], double [[MUL42]])
; SSE2-NEXT: [[TMP14:%.*]] = tail call double @llvm.fmuladd.f64(double [[TMP11]], double [[TMP11]], double [[TMP13]])
@@ -58,8 +58,10 @@ define i32 @ray_sphere(ptr nocapture noundef readonly %sph, ptr nocapture nounde
; SSE2-NEXT: [[TMP22:%.*]] = load double, ptr [[RAD]], align 8
; SSE2-NEXT: [[NEG82:%.*]] = fneg double [[TMP22]]
; SSE2-NEXT: [[TMP23:%.*]] = tail call double @llvm.fmuladd.f64(double [[NEG82]], double [[TMP22]], double [[TMP21]])
+; SSE2-NEXT: [[TMP4:%.*]] = extractelement <2 x double> [[TMP53]], i64 0
; SSE2-NEXT: [[TMP24:%.*]] = fmul double [[TMP4]], -4.000000e+00
; SSE2-NEXT: [[NEG86:%.*]] = fmul double [[TMP24]], [[TMP23]]
+; SSE2-NEXT: [[TMP12:%.*]] = extractelement <2 x double> [[TMP53]], i64 1
; SSE2-NEXT: [[TMP25:%.*]] = tail call double @llvm.fmuladd.f64(double [[TMP12]], double [[TMP12]], double [[NEG86]])
; SSE2-NEXT: [[CMP:%.*]] = fcmp olt double [[TMP25]], 0.000000e+00
; SSE2-NEXT: br i1 [[CMP]], label [[CLEANUP:%.*]], label [[IF_END:%.*]]
@@ -70,7 +72,7 @@ define i32 @ray_sphere(ptr nocapture noundef readonly %sph, ptr nocapture nounde
; SSE2-NEXT: [[TMP26:%.*]] = insertelement <2 x double> poison, double [[FNEG87]], i64 0
; SSE2-NEXT: [[TMP27:%.*]] = insertelement <2 x double> [[TMP26]], double [[CALL]], i64 1
; SSE2-NEXT: [[TMP28:%.*]] = shufflevector <2 x double> [[TMP27]], <2 x double> poison, <2 x i32> <i32 1, i32 poison>
-; SSE2-NEXT: [[TMP29:%.*]] = insertelement <2 x double> [[TMP28]], double [[TMP12]], i64 1
+; SSE2-NEXT: [[TMP29:%.*]] = shufflevector <2 x double> [[TMP28]], <2 x double> [[TMP53]], <2 x i32> <i32 0, i32 3>
; SSE2-NEXT: [[TMP30:%.*]] = fsub <2 x double> [[TMP27]], [[TMP29]]
; SSE2-NEXT: [[TMP31:%.*]] = insertelement <2 x double> poison, double [[MUL88]], i64 0
; SSE2-NEXT: [[TMP32:%.*]] = shufflevector <2 x double> [[TMP31]], <2 x double> poison, <2 x i32> zeroinitializer
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/dependent-seeds.ll b/llvm/test/Transforms/SLPVectorizer/X86/dependent-seeds.ll
index db2e8017e3c27..b97a62c3b2538 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/dependent-seeds.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/dependent-seeds.ll
@@ -34,12 +34,11 @@ define double @second_level_seeds(ptr noalias %x, ptr noalias %y, ptr noalias %m
; CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[Y]], align 8
; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr [[X]], align 8
; CHECK-NEXT: [[TMP3:%.*]] = fadd <2 x double> [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = extractelement <2 x double> [[TMP3]], i64 0
-; CHECK-NEXT: [[TMP5:%.*]] = fadd fast double [[TMP4]], 1.000000e+00
+; CHECK-NEXT: [[TMP4:%.*]] = fadd fast <2 x double> [[TMP3]], splat (double 1.000000e+00)
+; CHECK-NEXT: [[TMP5:%.*]] = extractelement <2 x double> [[TMP4]], i64 0
; CHECK-NEXT: store double [[TMP5]], ptr [[M]], align 8
-; CHECK-NEXT: [[TMP7:%.*]] = extractelement <2 x double> [[TMP3]], i64 1
-; CHECK-NEXT: [[TMP6:%.*]] = fadd fast double [[TMP7]], 1.000000e+00
; CHECK-NEXT: [[L:%.*]] = load double, ptr [[M]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = extractelement <2 x double> [[TMP4]], i64 1
; CHECK-NEXT: [[R:%.*]] = fadd double [[TMP6]], [[L]]
; CHECK-NEXT: ret double [[R]]
;
>From f137bc0f5cad3bc498bbee0469223a815031846a Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Sun, 4 Oct 2026 14:30:25 +0200
Subject: [PATCH 06/18] [clang][X86] bring `regparm` in line with GCC (#227130)
Removes some divergences between GCC and Clang using `regparm`. In
particular
- All floats count as floats (previously `f16`, `f16b`, `long double`
and `f128` did not)
- Complex numbers are always passed via the stack
- Unions are always passed like integers
- Some changes to how wrapping structs (with a single non-ZST field) are
handled
I've tested this empirically (with abi-cafe)
---------
Co-authored-by: Reid Kleckner <rkleckner at nvidia.com>
---
clang/docs/ReleaseNotes.md | 7 ++
clang/include/clang/Basic/ABIVersions.def | 2 +
clang/lib/CodeGen/Targets/X86.cpp | 115 +++++++++++++++++++---
clang/test/CodeGen/regparm-struct.c | 89 ++++++++++++++++-
4 files changed, 196 insertions(+), 17 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index bf194e87f76a6..7ec126a065ae5 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -105,6 +105,13 @@ features cannot lower the translation-unit ABI level;
This also fixes a crash when such a struct was passed or returned.
`-fclang-abi-compat=23` restores the previous behavior. (#GH202205)
+- On 32-bit x86, Clang now matches GCC when classifying arguments for the
+ `regparm` calling convention. Floating-point types other than `float` and
+ `double` no longer consume general-purpose register slots, complex values
+ are passed on the stack without consuming register slots, and unions are no
+ longer classified according to a single member. `-fclang-abi-compat=23`
+ restores the previous behavior. (#GH227130)
+
- Clang now considers matrix types in its isHomogeneousAggregate() handling,
which can lead to differences in how structures containing matrix types are
classified for ABI purposes. The previous exclusion of matrix types appears
diff --git a/clang/include/clang/Basic/ABIVersions.def b/clang/include/clang/Basic/ABIVersions.def
index 3c434da91bfab..399be760fc7a3 100644
--- a/clang/include/clang/Basic/ABIVersions.def
+++ b/clang/include/clang/Basic/ABIVersions.def
@@ -167,6 +167,8 @@ ABI_VER_MAJOR(22)
/// faithfully reproduces Clang 23, including its crash on aggregates such
/// as a run of `__int128` bit-fields, where skipping the unnamed field
/// leaves part of a wider access unit unclassified.)
+/// - On 32-bit x86, use the legacy `regparm` classification for floating-point
+/// types other than `float` and `double`, complex types, and unions.
ABI_VER_MAJOR(23)
/// Conform to the underlying platform's C and C++ ABIs as closely as we can.
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index 21f9929cfa882..c0947c481d2b0 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -101,10 +101,7 @@ struct CCState {
/// X86_32ABIInfo - The X86-32 ABI information.
class X86_32ABIInfo : public ABIInfo {
- enum Class {
- Integer,
- Float
- };
+ enum Class { Integer, Float, AlwaysStack };
static const unsigned MinABIStackAlignInBytes = 4;
@@ -634,25 +631,111 @@ ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal,
Realign);
}
+/// Like isSingleElementStruct, but only looks through one level of records.
+/// This mirrors how GCC gives a record the mode of its only field.
+static const Type *getSingleFieldType(QualType T, ASTContext &Context) {
+ const auto *RD = T->getAsRecordDecl();
+ if (!RD)
+ return nullptr;
+
+ if (RD->hasFlexibleArrayMember())
+ return nullptr;
+
+ const Type *Found = nullptr;
+
+ // If this is a C++ record, check the bases first.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (const auto &I : CXXRD->bases()) {
+ // Ignore empty records.
+ if (isEmptyRecord(Context, I.getType(), true))
+ continue;
+
+ // If we already found an element then this isn't a single-element struct.
+ if (Found)
+ return nullptr;
+
+ Found = I.getType().getTypePtr();
+ }
+ }
+
+ // Check for single element.
+ for (const auto *FD : RD->fields()) {
+ QualType FT = FD->getType();
+
+ // Ignore empty fields.
+ if (isEmptyField(Context, FD, true))
+ continue;
+
+ // If we already found an element then this isn't a single-element
+ // struct.
+ if (Found)
+ return nullptr;
+
+ // Treat single element arrays as the element.
+ while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
+ if (AT->getZExtSize() != 1)
+ break;
+ FT = AT->getElementType();
+ }
+
+ Found = FT.getTypePtr();
+ }
+
+ // We don't consider a struct a single-element struct if it has
+ // padding beyond the element type.
+ if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T))
+ return nullptr;
+
+ return Found;
+}
+
X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
- const Type *T = isSingleElementStruct(Ty, getContext());
- if (!T)
- T = Ty.getTypePtr();
+ if (getContext().getLangOpts().isCompatibleWith(
+ LangOptions::ClangABI::Ver23)) {
+ const Type *T = isSingleElementStruct(Ty, getContext());
+ if (!T)
+ T = Ty.getTypePtr();
+
+ if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
+ BuiltinType::Kind K = BT->getKind();
+ if (K == BuiltinType::Float || K == BuiltinType::Double)
+ return Float;
+ }
+ return Integer;
+ }
- if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
- BuiltinType::Kind K = BT->getKind();
- if (K == BuiltinType::Float || K == BuiltinType::Double)
- return Float;
+ while (const RecordDecl *RD = Ty->getAsRecordDecl()) {
+ // Unions are always passed as integers.
+ if (RD->isUnion())
+ return Integer;
+
+ const Type *FT = getSingleFieldType(Ty, getContext());
+
+ // Pick integer for zero-sized types. They will be ignored down the line.
+ if (!FT)
+ return Integer;
+
+ Ty = QualType(FT, 0);
}
+
+ // All complex values are passed via the stack.
+ if (Ty->isAnyComplexType())
+ return AlwaysStack;
+
+ // Types like bfloat16 or __float128 are all passed like floats.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
+ if (BT->isFloatingPoint())
+ return Float;
+
return Integer;
}
bool X86_32ABIInfo::updateFreeRegs(QualType Ty, CCState &State) const {
- if (!IsSoftFloatABI) {
- Class C = classify(Ty);
- if (C == Float)
- return false;
- }
+ Class C = classify(Ty);
+ if (C == AlwaysStack && !IsMCUABI)
+ return false;
+ if (C == Float && !IsSoftFloatABI)
+ return false;
unsigned Size = getContext().getTypeSize(Ty);
unsigned SizeInRegs = (Size + 31) / 32;
diff --git a/clang/test/CodeGen/regparm-struct.c b/clang/test/CodeGen/regparm-struct.c
index a533f6cedbba2..5dc2d96c36bfe 100644
--- a/clang/test/CodeGen/regparm-struct.c
+++ b/clang/test/CodeGen/regparm-struct.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -target-feature +sse2 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,LATEST
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -target-feature +sse2 -fclang-abi-compat=23 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,COMPAT23
__attribute__((regparm(3))) void f1(int a, int b, int c, int d);
// CHECK: declare void @f1(i32 inreg noundef, i32 inreg noundef, i32 inreg noundef, i32 noundef)
@@ -175,3 +176,89 @@ void g18(void) {
struct s13 x = {{41}};
f18(x, 42, 43, 44);
}
+
+__attribute__((regparm(3))) void pass_f16(_Float16 a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_f16(half noundef %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_f16(half inreg noundef %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 noundef %d)
+
+__attribute__((regparm(3))) void pass_bf16(__bf16 a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_bf16(bfloat noundef %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_bf16(bfloat inreg noundef %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 noundef %d)
+
+__attribute__((regparm(3))) void pass_f80(long double a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_f80(x86_fp80 noundef %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_f80(x86_fp80 inreg noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d)
+
+__attribute__((regparm(3))) void pass_f128(__float128 a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_f128(fp128 noundef %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_f128(fp128 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d)
+
+struct s14 {
+ _Float16 x1;
+};
+__attribute__((regparm(3))) void pass_wrapped_f16(struct s14 a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_wrapped_f16(ptr noundef byval(%struct.s14) align 4 %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_wrapped_f16(i32 inreg %a.coerce, i32 inreg noundef %b, i32 inreg noundef %c, i32 noundef %d)
+
+struct s15 {
+ __float128 x1;
+};
+__attribute__((regparm(3))) void pass_wrapped_f128(struct s15 a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_wrapped_f128(ptr noundef byval(%struct.s15) align 4 {{%[^,]*}}, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_wrapped_f128(ptr noundef byval(%struct.s15) align 4 {{%[^,]*}}, i32 noundef %b, i32 noundef %c, i32 noundef %d)
+
+__attribute__((regparm(3))) void pass_complex_float(_Complex float a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_complex_float(ptr noundef byval({ float, float }) align 4 %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_complex_float(i32 inreg noundef %a.coerce0, i32 inreg noundef %a.coerce1, i32 inreg noundef %b, i32 noundef %c, i32 noundef %d)
+
+__attribute__((regparm(3))) void pass_complex_int(int a, _Complex int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_complex_int(i32 inreg noundef %a, ptr noundef byval({ i32, i32 }) align 4 %b, i32 inreg noundef %c, i32 inreg noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_complex_int(i32 inreg noundef %a, i32 inreg noundef %b.coerce0, i32 inreg noundef %b.coerce1, i32 noundef %c, i32 noundef %d)
+
+struct s16 {
+ _Complex float x1;
+};
+__attribute__((regparm(3))) void pass_wrapped_complex_float(struct s16 a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_wrapped_complex_float(float %a.0, float %a.1, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_wrapped_complex_float(i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg noundef %b, i32 noundef %c, i32 noundef %d)
+
+struct s17 {
+ _Complex int x1[1];
+};
+__attribute__((regparm(3))) void pass_wrapped_complex_int(struct s17 a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_wrapped_complex_int(ptr noundef byval(%struct.s17) align 4 %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_wrapped_complex_int(i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg noundef %b, i32 noundef %c, i32 noundef %d)
+
+struct s18 {
+ float x1[1];
+};
+__attribute__((regparm(3))) void pass_struct_singleton_array_float(struct s18 a, int b, int c, int d) {}
+// CHECK-LABEL: define{{.*}} void @pass_struct_singleton_array_float(ptr noundef byval(%struct.s18) align 4 %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+
+// Unions are passed like integers.
+union u1 {
+ float x1;
+};
+__attribute__((regparm(3))) void pass_union_float(union u1 a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_union_float(i32 inreg %a.coerce, i32 inreg noundef %b, i32 inreg noundef %c, i32 noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_union_float(float %a.0, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+
+union u2 {
+ struct s5 x1;
+};
+__attribute__((regparm(3))) void pass_union_struct_float(union u2 a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_union_struct_float(i32 inreg %a.coerce, i32 inreg noundef %b, i32 inreg noundef %c, i32 noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_union_struct_float(ptr noundef byval(%union.u2) align 4 %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
+
+union u3 {
+ _Complex float x1;
+};
+__attribute__((regparm(3))) void pass_union_complex_float(union u3 a, int b, int c, int d) {}
+// CHECK-LABEL: define{{.*}} void @pass_union_complex_float(i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg noundef %b, i32 noundef %c, i32 noundef %d)
+
+struct s19 {
+ union u1 x1;
+};
+__attribute__((regparm(3))) void pass_nested_union_float(struct s19 a, int b, int c, int d) {}
+// LATEST-LABEL: define{{.*}} void @pass_nested_union_float(i32 inreg %a.coerce, i32 inreg noundef %b, i32 inreg noundef %c, i32 noundef %d)
+// COMPAT23-LABEL: define{{.*}} void @pass_nested_union_float(ptr noundef byval(%struct.s19) align 4 %a, i32 inreg noundef %b, i32 inreg noundef %c, i32 inreg noundef %d)
>From 8b0127c14e18f5856afbc2cc61461e2ab7e67609 Mon Sep 17 00:00:00 2001
From: Akash Manna <akash.manna.mymail at gmail.com>
Date: Sun, 4 Oct 2026 18:43:27 +0530
Subject: [PATCH 07/18] [Clang][OpenMP][NFC] Add test for `class-type` data
members as loop counters (#228831)
Fixes #140243
An OpenMP loop whose init assigns to a data member of class type, like
`for (a = x; ...)` with `I<int> a`, crashed in
`OpenMPIterationSpaceChecker::checkAndSetInit`. Such an assignment is an
`operator=` call, so it goes through the `CXXOperatorCallExpr` branch,
and two of the `setLCDeclAndLB` calls there took the bound from `BO`,
the `BinaryOperator` cast that had already failed and is null at that
point. The invalid code in the report is not needed: a valid loop over
an iterator-typed data member crashed the same way.
#203252 replaced those `BO->getRHS()` uses with `CE->getArg(1)` as part
of another fix, so the crash is gone on trunk and no source change is
needed. This PR only adds a regression test so the issue can be closed.
---
.../OpenMP/parallel_for_loop_messages.cpp | 39 +++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/clang/test/OpenMP/parallel_for_loop_messages.cpp b/clang/test/OpenMP/parallel_for_loop_messages.cpp
index 0b755f7411748..644dfed66cc79 100644
--- a/clang/test/OpenMP/parallel_for_loop_messages.cpp
+++ b/clang/test/OpenMP/parallel_for_loop_messages.cpp
@@ -629,3 +629,42 @@ void test_loop_firstprivate_lastprivate() {
for (int i = 0; i < 16; ++i)
;
}
+
+namespace GH140243 {
+template <typename T>
+class I { };
+struct R { R () {}; ~R () {}; I<int> r; };
+struct T { T () {}; virtual ~T () {}; I<int> t; };
+// expected-note at +1 {{A defined here}}
+struct A : public R, virtual public T { A () {} I<int> a; void m1 (const I<int> &, const I<int> &); };
+
+// expected-error at +1 {{out-of-line definition of 'm1' does not match any declaration in 'GH140243::A'}}
+void A::m1 (const I<int> &x)
+{
+ int w = 0;
+// expected-error at +5 {{invalid operands to binary expression ('I<int>' and 'int')}}
+// expected-error at +4 {{cannot increment value of type 'I<int>'}}
+// expected-error at +3 {{condition of OpenMP for loop must be a relational comparison}}
+// expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'a'}}
+ #pragma omp parallel for reduction(|:w)
+ for (a = x; A::a < 10; a++)
+ w |= (1 << *A::a); // expected-error {{indirection requires pointer operand ('I<int>' invalid)}}
+}
+
+struct B {
+ GoodIter it;
+ void m1(GoodIter begin, GoodIter end);
+};
+
+void B::m1(GoodIter begin, GoodIter end) {
+#pragma omp parallel for
+ for (it = begin; it < end; ++it)
+ ;
+#pragma omp parallel for
+ for (this->it = begin; B::it < end; ++B::it)
+ ;
+#pragma omp parallel for private(it)
+ for (it = begin; it < end; ++it)
+ ;
+}
+}
>From 751b3a4562e947a1bfc1169d480adc906a2f8e13 Mon Sep 17 00:00:00 2001
From: Ivy Xu <ivyxu1337 at gmail.com>
Date: Sun, 4 Oct 2026 21:16:02 +0800
Subject: [PATCH 08/18] [clang][www] Fix typos in OpenProjects page (#228822)
Fix various typos in Clang's [OpenProjects
page](https://clang.llvm.org/OpenProjects.html).
Assisted-by: Claude Sonnet 5.5
---
clang/www/OpenProjects.html | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/clang/www/OpenProjects.html b/clang/www/OpenProjects.html
index 71ce7ecf416d8..98c4840adab0a 100755
--- a/clang/www/OpenProjects.html
+++ b/clang/www/OpenProjects.html
@@ -39,13 +39,13 @@ <h1>Open Clang Projects</h1>
diagnostic group flags</a> (adding code examples of what is diagnosed, or
other relevant information), or</li>
<li>documenting <a href="https://github.com/llvm/llvm-project/blob/main/clang/include/clang/Options/Options.td">
- command line options</a>, or</li>
+ command-line options</a>, or</li>
<li>help with completing other missing documentation.</li>
</ul>
These projects are independent of each other.</li>
<li><b>Complete the investigation into Clang's C conformance</b>: Clang's
-<a href="c_status.html">C status page</a> contain a number of entries marked as
+<a href="c_status.html">C status page</a> contains a number of entries marked as
<code>Unknown</code>. Completing the investigation involves adding
<a href="https://github.com/llvm/llvm-project/tree/main/clang/test/C">test
coverage</a> for the various standards papers and updating the documentation
@@ -77,14 +77,14 @@ <h1>Open Clang Projects</h1>
defect reports and updating the documentation accordingly.</li>
<li><b>Bug triage</b>: Clang's <a href="https://github.com/llvm/llvm-project/issues">
-issue tracker</a>currently has over 20,000 open issues, many of which are not
+issue tracker</a> currently has over 20,000 open issues, many of which are not
appropriately tagged, are no longer reproducible, could use a reduced test case,
-or otherwise needs some manual interaction. We can always use help with
+or otherwise need some manual interaction. We can always use help with
<a href="https://llvm.org/docs/BugLifeCycle.html#triaging-bugs">bug triage and
issue tracker maintenance</a>.
</li>
-<li><b>Improve build times with Clang</b>: the time it takes Clang to process a
+<li><b>Improve build times with Clang</b>: The time it takes Clang to process a
translation unit is very important to our users; the lower the build time, the
better the overall user experience. It would be good to improve Clang's
performance as well as to find ways to proactively alert us when we've
@@ -97,15 +97,15 @@ <h1>Open Clang Projects</h1>
from source code. The tool is in early stages of development and could use more
dedicated effort to complete the implementation.</li>
-<li><b>Self-testing using clang</b>: There are several neat ways to
-improve the quality of clang by self-testing. Some examples:
+<li><b>Self-testing using Clang</b>: There are several neat ways to
+improve the quality of Clang by self-testing. Some examples:
<ul>
<li>Improve the reliability of AST printing and serialization by
- ensuring that the AST produced by clang on an input doesn't change
+ ensuring that the AST produced by Clang on an input doesn't change
when it is reparsed or unserialized.
<li>Improve parser reliability and error generation by automatically
- or randomly changing the input checking that clang doesn't crash and
+ or randomly changing the input checking that Clang doesn't crash and
that it doesn't generate excessive errors for small input
changes. Manipulating the input at both the text and token levels is
likely to produce interesting test cases.
@@ -120,7 +120,7 @@ <h1>Open Clang Projects</h1>
<li><b>StringRef'ize APIs</b>: A thankless but incredibly useful project is
StringRef'izing (converting to use <tt>llvm::StringRef</tt> instead of <tt>const
-char *</tt> or <tt>std::string</tt>) various clang interfaces. This generally
+char *</tt> or <tt>std::string</tt>) various Clang interfaces. This generally
simplifies the code and makes it more efficient.</li>
<li><b>Configuration Manager</b>: Clang/LLVM works on a large number of
@@ -142,7 +142,7 @@ <h1>Open Clang Projects</h1>
<p>The second stage would be to produce a configuration file (that can be used
independently of the Host) so that Clang can read it and not need a gazillion
-of command-line options. Such file should be simple JSON / INI or anything that
+command-line options. Such a file should be simple JSON / INI or anything that
a text editor could change.</p></li>
</ul>
>From 5f9b69e99d5f1949273c3bf407b631072a15cac4 Mon Sep 17 00:00:00 2001
From: Shengxin Pei <TPPPP72 at outlook.com>
Date: Sun, 4 Oct 2026 21:46:42 +0800
Subject: [PATCH 09/18] [clang][test] Combine and clean up decltype parser
tests NFC (#228889)
Follow-up #211221
---
clang/test/Parser/decltype-crash.cpp | 39 +++++++++++++++----------
clang/test/Parser/decltype-gh188014.cpp | 4 ---
clang/test/Parser/gh114815.cpp | 6 ----
3 files changed, 23 insertions(+), 26 deletions(-)
delete mode 100644 clang/test/Parser/decltype-gh188014.cpp
delete mode 100644 clang/test/Parser/gh114815.cpp
diff --git a/clang/test/Parser/decltype-crash.cpp b/clang/test/Parser/decltype-crash.cpp
index 8471309665f1d..9f22baef698d5 100644
--- a/clang/test/Parser/decltype-crash.cpp
+++ b/clang/test/Parser/decltype-crash.cpp
@@ -1,20 +1,27 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
-// A 'decltype' that is not followed by '(' fails to parse as a
-// decltype-specifier. ParseOptionalCXXScopeSpecifier used to still annotate it
-// and treat it as a nested-name-specifier, which tripped an assertion in
-// Preprocessor::AnnotatePreviousCachedTokens. It should just diagnose the
-// error instead.
-int decltype = 0;
-// expected-error at -1 {{expected '(' after 'decltype'}}
-// expected-error at -2 {{expected unqualified-id}}
+namespace GH114815{
+ #define ID(X) X
+ extern int ID(decltype);
+ // expected-error at -1 {{expected '(' after 'decltype'}}
+ // expected-error at -2 {{expected unqualified-id}}
+}
-int *decltype = 0;
-// expected-error at -1 {{expected '(' after 'decltype'}}
-// expected-error at -2 {{expected unqualified-id}}
+namespace GH165246 {
+ int decltype {};
+ // expected-error at -1 {{expected '(' after 'decltype'}}
+ // expected-error at -2 {{expected unqualified-id}}
+}
-// GH165246
-int decltype {};
-// expected-error at -1 {{expected '(' after 'decltype'}}
-// expected-error at -2 {{expected unqualified-id}}
+namespace GH211207 {
+ int decltype = 0;
+ // expected-error at -1 {{expected '(' after 'decltype'}}
+ // expected-error at -2 {{expected unqualified-id}}
+
+ int *decltype = 0;
+ // expected-error at -1 {{expected '(' after 'decltype'}}
+ // expected-error at -2 {{expected unqualified-id}}
+}
+
+// GH188014
+& decltype ( ( union { // expected-error {{expected ';' after union}} expected-error {{expected '}'}} expected-error {{expected ')'}} expected-error {{expected expression}} expected-error {{expected unqualified-id}} expected-note {{to match this '('}} expected-note {{to match this '{'}}
diff --git a/clang/test/Parser/decltype-gh188014.cpp b/clang/test/Parser/decltype-gh188014.cpp
deleted file mode 100644
index e8403bdcbe3bb..0000000000000
--- a/clang/test/Parser/decltype-gh188014.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-
-// GH188014
-& decltype ( ( union { // expected-error {{expected ';' after union}} expected-error {{expected '}'}} expected-error {{expected ')'}} expected-error {{expected expression}} expected-error {{expected unqualified-id}} expected-note {{to match this '('}} expected-note {{to match this '{'}}
diff --git a/clang/test/Parser/gh114815.cpp b/clang/test/Parser/gh114815.cpp
deleted file mode 100644
index 6a89384e9e66d..0000000000000
--- a/clang/test/Parser/gh114815.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUN: %clang_cc1 -verify %s -std=c++11 -fsyntax-only
-
-#define ID(X) X
-extern int ID(decltype);
-// expected-error at -1 {{expected '(' after 'decltype'}} \
-// expected-error at -1 {{expected unqualified-id}}
>From ed390ca4d61b412e595757b35dcb4fff07147c9e Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Sun, 4 Oct 2026 08:47:55 -0500
Subject: [PATCH 10/18] [flang][OpenMP] Remove unnecessary check for extension
clauses (#228878)
Remove the check for extension clauses. These now do have descriptors,
so the check guarding the descriptor retrieval is no longer necessary.
---
flang/lib/Semantics/check-omp-syntax.cpp | 4 ----
1 file changed, 4 deletions(-)
diff --git a/flang/lib/Semantics/check-omp-syntax.cpp b/flang/lib/Semantics/check-omp-syntax.cpp
index ceda90edaf640..03f8e554be350 100644
--- a/flang/lib/Semantics/check-omp-syntax.cpp
+++ b/flang/lib/Semantics/check-omp-syntax.cpp
@@ -519,10 +519,6 @@ void OmpStructureChecker::VerifyModifierSyntax(const parser::OmpClause &x) {
llvm::omp::Clause id{x.Id()};
auto clauseId{WithSource(id, x.source)};
switch (id) {
- case llvm::omp::Clause::OMPC_ompx_bare:
- case llvm::omp::Clause::OMPC_cancellation_construct_type:
- // Those are extensions/synthetic clauses and they don't have descriptors.
- break;
case llvm::omp::Clause::OMPC_uses_allocators: {
// The traits of the deprecated syntax are stored as a traits-array
// modifier, but they are not the 5.2 modifier, so they must not be
>From c819bff6a970e48f6084d6af0841fccc03b46f0b Mon Sep 17 00:00:00 2001
From: Yao Qi <yao_qi at apple.com>
Date: Sun, 4 Oct 2026 15:04:21 +0100
Subject: [PATCH 11/18] [lldb] Replay the cached error from
GetLoadImageUtilityFunction (#226986)
`Process::LoadImage` needs a live process to load a library: on POSIX it
makes the C library's `dlopen` run inside the debuggee, and on Windows
it makes `LoadLibraryExW` run there, both through a JIT-compiled
function call that needs a process to run the call in. On a core file
(or, on Windows, a saved minidump) there is no such process, so the load
fails every time. POSIX and Windows each lose the resulting error
message, but for two different reasons.
On POSIX, only the first failure is reported correctly. Load a corefile,
and load two libraries that do not exist shows this:
```
(lldb) process load /tmp/does-not-exist-1.dylib
error: failed to load '/tmp/does-not-exist-1.dylib': dlopen error: could not make function caller: Can't make a function caller without a process.
(lldb) process load /tmp/does-not-exist-2.dylib
error: failed to load '/tmp/does-not-exist-2.dylib': (null)
```
`Process::GetLoadImageUtilityFunction` builds the `UtilityFunction` that
performs the `dlopen` call, and caches it in the `Process` The cache is
a `llvm::call_once`: only the first caller's factory function actually
runs, and every later caller just gets the same cached pointer back,
whether or not the first attempt succeeded. Each caller had been passing
its own local `Status &error`, populated only when its own factory ran,
so any caller after the first got a `Status` nobody had written to.
On Windows the same missing-process failure loses its message on the
very first call, not just later ones. Loading a saved minidump and
calling `process load` twice shows this:
```
(lldb) process load /tmp/does-not-exist-1.dll
error: failed to load '/tmp/does-not-exist-1.dll': (null)
(lldb) process load /tmp/does-not-exist-2.dll
error: failed to load '/tmp/does-not-exist-2.dll': (null)
```
`process load` decides success or failure from the returned image token,
so it prints "failed to load" here at all; an SB API caller that checks
`error.Fail()` directly sees a false success on both calls. This is a
different bug from the POSIX one above: it is not about the cache
replaying a stale result, it is that `PlatformWindows::DoLoadImage`
never populated its `error` output parameter in the first place. Its
factory wrote the failure into a local `Status status` that nothing ever
read, instead of into the function's own `error` parameter.
Give the `Process` its own `Status` member alongside the cached
`UtilityFunction`, and have `GetLoadImageUtilityFunction` take an
`error` output parameter. The one factory call that runs stores its
result in the member; every call, whether or not it ran the factory,
copies the member back out to its caller. `Status` cannot be copied
directly because it wraps a move-only `llvm::Error`, so this uses
`Status::Clone()`, the pattern already used elsewhere in lldb to stash
an error and hand copies of it to more than one reader.
`DWARFUnit` uses the same technique to cache a load failure:
`ExtractUnitDIEIfNeeded` runs its loading step once per unit, guarded by
the member `m_has_parsed_non_skeleton_unit`, and stores any failure in
the member `m_dwo_error` via `SetDwoError`.
`SymbolFileDWARF::CalculateFrameVariableError` later reads it back with
`GetDwoError()` and clones it for its own caller.
Fix `PlatformWindows::DoLoadImage` the same way, by routing its factory
through the function's `error` parameter instead of the local `status`
that nothing read.
Add a test that saves a core file, loads it back, and calls
`SBProcess::LoadImage` twice with a path that cannot be opened. Both
calls must fail, with the same non-empty message. Add a second test,
using a checked-in Windows minidump in place of a core file, that does
the same thing against `PlatformWindows::DoLoadImage`.
---------
Co-authored-by: Charles Zablit <c_zablit at apple.com>
---
lldb/include/lldb/Target/Process.h | 12 +++--
.../Plugins/Platform/POSIX/PlatformPOSIX.cpp | 54 ++++++++-----------
.../Plugins/Platform/POSIX/PlatformPOSIX.h | 5 +-
.../Platform/Windows/PlatformWindows.cpp | 37 ++++++-------
.../Platform/Windows/PlatformWindows.h | 5 +-
lldb/source/Target/Process.cpp | 23 +++++---
.../process-load-error-postmortem/Makefile | 4 ++
.../TestProcessLoadErrorPostmortem.py | 51 ++++++++++++++++++
.../process-load-error-postmortem/main.c | 4 ++
.../wow64_minidump/TestWow64MiniDump.py | 27 ++++++++++
10 files changed, 153 insertions(+), 69 deletions(-)
create mode 100644 lldb/test/API/functionalities/load_unload/process-load-error-postmortem/Makefile
create mode 100644 lldb/test/API/functionalities/load_unload/process-load-error-postmortem/TestProcessLoadErrorPostmortem.py
create mode 100644 lldb/test/API/functionalities/load_unload/process-load-error-postmortem/main.c
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 207c9cf290035..029f7f422caee 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -666,11 +666,12 @@ class Process : public std::enable_shared_from_this<Process>,
/// been initialized yet.
///
/// \return
- /// The cached utility function or null if the platform is not the
- /// same as the target's platform.
- UtilityFunction *GetLoadImageUtilityFunction(
+ /// The cached utility function, or an Error if the platform is not
+ /// the same as the target's platform, or if it could not be created.
+ llvm::Expected<UtilityFunction &> GetLoadImageUtilityFunction(
Platform *platform,
- llvm::function_ref<std::unique_ptr<UtilityFunction>()> factory);
+ llvm::function_ref<llvm::Expected<std::unique_ptr<UtilityFunction>>()>
+ factory);
/// Get the dynamic loader plug-in for this process.
///
@@ -3594,6 +3595,9 @@ void PruneThreadPlans();
std::unique_ptr<UtilityFunction> m_dlopen_utility_func_up;
llvm::once_flag m_dlopen_utility_func_flag_once;
+ /// The error from the one attempt to create m_dlopen_utility_func_up,
+ /// set only if that attempt failed.
+ Status m_dlopen_utility_func_error;
/// Per process source file cache.
SourceManager::SourceFileCache m_source_file_cache;
diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
index 2a5a3d55ec98c..b52d4da817f49 100644
--- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
+++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
@@ -553,9 +553,8 @@ Status PlatformPOSIX::EvaluateLibdlExpression(
return Status();
}
-std::unique_ptr<UtilityFunction>
-PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx,
- Status &error) {
+llvm::Expected<std::unique_ptr<UtilityFunction>>
+PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx) {
// Remember to prepend this with the prefix from
// GetLibdlFunctionDeclarations. The returned values are all in
// __lldb_dlopen_result for consistency. The wrapper returns a void * but
@@ -630,23 +629,21 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx,
std::move(expr), dlopen_wrapper_name, eLanguageTypeC_plus_plus, exe_ctx);
if (!utility_fn_or_error) {
std::string error_str = llvm::toString(utility_fn_or_error.takeError());
- error = Status::FromErrorStringWithFormat(
+ return llvm::createStringError(
"dlopen error: could not create utility function: %s",
error_str.c_str());
- return nullptr;
}
std::unique_ptr<UtilityFunction> dlopen_utility_func_up =
std::move(*utility_fn_or_error);
Value value;
ValueList arguments;
- FunctionCaller *do_dlopen_function = nullptr;
// Fetch the clang types we will need:
TypeSystemClangSP scratch_ts_sp =
ScratchTypeSystemClang::GetForTarget(process->GetTarget());
if (!scratch_ts_sp)
- return nullptr;
+ return llvm::createStringError("dlopen error: no scratch type system");
CompilerType clang_void_pointer_type =
scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
@@ -663,24 +660,18 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx,
arguments.PushValue(value);
arguments.PushValue(value);
arguments.PushValue(value);
-
- do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller(
+
+ dlopen_utility_func_up->MakeFunctionCaller(
clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error);
- if (utility_error.Fail()) {
- error = Status::FromErrorStringWithFormat(
+ if (utility_error.Fail())
+ return llvm::createStringError(
"dlopen error: could not make function caller: %s",
utility_error.AsCString());
- return nullptr;
- }
-
- do_dlopen_function = dlopen_utility_func_up->GetFunctionCaller();
- if (!do_dlopen_function) {
- error =
- Status::FromErrorString("dlopen error: could not get function caller.");
- return nullptr;
- }
-
- // We made a good utility function, so cache it in the process:
+
+ if (!dlopen_utility_func_up->GetFunctionCaller())
+ return llvm::createStringError(
+ "dlopen error: could not get function caller.");
+
return dlopen_utility_func_up;
}
@@ -708,21 +699,20 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
thread_sp->CalculateExecutionContext(exe_ctx);
Status utility_error;
- UtilityFunction *dlopen_utility_func;
ValueList arguments;
- FunctionCaller *do_dlopen_function = nullptr;
// The UtilityFunction is held in the Process. Platforms don't track the
// lifespan of the Targets that use them, we can't put this in the Platform.
- dlopen_utility_func = process->GetLoadImageUtilityFunction(
- this, [&]() -> std::unique_ptr<UtilityFunction> {
- return MakeLoadImageUtilityFunction(exe_ctx, error);
- });
- // If we couldn't make it, the error will be in error, so we can exit here.
- if (!dlopen_utility_func)
+ llvm::Expected<UtilityFunction &> dlopen_utility_func_or_err =
+ process->GetLoadImageUtilityFunction(
+ this, [&]() { return MakeLoadImageUtilityFunction(exe_ctx); });
+ if (!dlopen_utility_func_or_err) {
+ error = Status::FromError(dlopen_utility_func_or_err.takeError());
return LLDB_INVALID_IMAGE_TOKEN;
-
- do_dlopen_function = dlopen_utility_func->GetFunctionCaller();
+ }
+
+ FunctionCaller *do_dlopen_function =
+ dlopen_utility_func_or_err->GetFunctionCaller();
if (!do_dlopen_function) {
error =
Status::FromErrorString("dlopen error: could not get function caller.");
diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
index 0a02ecd279cfe..6c27a36b3b1e3 100644
--- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
+++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
@@ -86,9 +86,8 @@ class PlatformPOSIX : public lldb_private::RemoteAwarePlatform {
llvm::StringRef expr_prefix,
lldb::ValueObjectSP &result_valobj_sp);
- std::unique_ptr<lldb_private::UtilityFunction>
- MakeLoadImageUtilityFunction(lldb_private::ExecutionContext &exe_ctx,
- lldb_private::Status &error);
+ llvm::Expected<std::unique_ptr<lldb_private::UtilityFunction>>
+ MakeLoadImageUtilityFunction(lldb_private::ExecutionContext &exe_ctx);
virtual
llvm::StringRef GetLibdlFunctionDeclarations(lldb_private::Process *process);
diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
index d977d60b9a766..6764289973088 100644
--- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
@@ -228,15 +228,15 @@ uint32_t PlatformWindows::DoLoadImage(Process *process,
ExecutionContext context;
thread->CalculateExecutionContext(context);
- Status status;
- UtilityFunction *loader =
- process->GetLoadImageUtilityFunction(this, [&]() -> std::unique_ptr<UtilityFunction> {
- return MakeLoadImageUtilityFunction(context, status);
- });
- if (loader == nullptr)
+ llvm::Expected<UtilityFunction &> loader_or_err =
+ process->GetLoadImageUtilityFunction(
+ this, [&]() { return MakeLoadImageUtilityFunction(context); });
+ if (!loader_or_err) {
+ error = Status::FromError(loader_or_err.takeError());
return LLDB_INVALID_IMAGE_TOKEN;
+ }
- FunctionCaller *invocation = loader->GetFunctionCaller();
+ FunctionCaller *invocation = loader_or_err->GetFunctionCaller();
if (!invocation) {
error = Status::FromErrorString(
"LoadLibrary error: could not get function caller");
@@ -253,6 +253,7 @@ uint32_t PlatformWindows::DoLoadImage(Process *process,
name.emplace_back(L'\0');
/* Inject name paramter into inferior */
+ Status status;
lldb::addr_t injected_name =
process->AllocateMemory(name.size() * sizeof(llvm::UTF16),
ePermissionsReadable | ePermissionsWritable,
@@ -741,9 +742,8 @@ PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target,
}
}
-std::unique_ptr<UtilityFunction>
-PlatformWindows::MakeLoadImageUtilityFunction(ExecutionContext &context,
- Status &status) {
+llvm::Expected<std::unique_ptr<UtilityFunction>>
+PlatformWindows::MakeLoadImageUtilityFunction(ExecutionContext &context) {
// FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
static constexpr const char kLoaderDecls[] = R"(
extern "C" {
@@ -858,16 +858,15 @@ void * __lldb_LoadLibraryHelper(const wchar_t *name, const wchar_t *paths,
context);
if (!function) {
std::string error = llvm::toString(function.takeError());
- status = Status::FromErrorStringWithFormat(
+ return llvm::createStringError(
"LoadLibrary error: could not create utility function: %s",
error.c_str());
- return nullptr;
}
TypeSystemClangSP scratch_ts_sp =
ScratchTypeSystemClang::GetForTarget(target);
if (!scratch_ts_sp)
- return nullptr;
+ return llvm::createStringError("LoadLibrary error: no scratch type system");
CompilerType VoidPtrTy =
scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
@@ -890,18 +889,14 @@ void * __lldb_LoadLibraryHelper(const wchar_t *name, const wchar_t *paths,
std::unique_ptr<UtilityFunction> utility{std::move(*function)};
utility->MakeFunctionCaller(VoidPtrTy, parameters, context.GetThreadSP(),
error);
- if (error.Fail()) {
- status = Status::FromErrorStringWithFormat(
+ if (error.Fail())
+ return llvm::createStringError(
"LoadLibrary error: could not create function caller: %s",
error.AsCString());
- return nullptr;
- }
- if (!utility->GetFunctionCaller()) {
- status = Status::FromErrorString(
+ if (!utility->GetFunctionCaller())
+ return llvm::createStringError(
"LoadLibrary error: could not get function caller");
- return nullptr;
- }
return utility;
}
diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
index 6f8c20a8456a2..392ca75f64664 100644
--- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
@@ -85,9 +85,8 @@ class PlatformWindows : public RemoteAwarePlatform {
std::vector<ArchSpec> m_supported_architectures;
private:
- std::unique_ptr<lldb_private::UtilityFunction>
- MakeLoadImageUtilityFunction(lldb_private::ExecutionContext &context,
- lldb_private::Status &status);
+ llvm::Expected<std::unique_ptr<lldb_private::UtilityFunction>>
+ MakeLoadImageUtilityFunction(lldb_private::ExecutionContext &context);
lldb_private::Status EvaluateLoaderExpression(lldb_private::Process *process,
const char *expression,
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index fe58b732a6497..546b676f72f63 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -6698,14 +6698,25 @@ Status Process::UpdateAutomaticSignalFiltering() {
return Status();
}
-UtilityFunction *Process::GetLoadImageUtilityFunction(
+llvm::Expected<UtilityFunction &> Process::GetLoadImageUtilityFunction(
Platform *platform,
- llvm::function_ref<std::unique_ptr<UtilityFunction>()> factory) {
+ llvm::function_ref<llvm::Expected<std::unique_ptr<UtilityFunction>>()>
+ factory) {
if (platform != GetTarget().GetPlatform().get())
- return nullptr;
- llvm::call_once(m_dlopen_utility_func_flag_once,
- [&] { m_dlopen_utility_func_up = factory(); });
- return m_dlopen_utility_func_up.get();
+ return llvm::createStringError(
+ "the platform requesting the load-image utility function is not "
+ "the target's platform");
+ llvm::call_once(m_dlopen_utility_func_flag_once, [&] {
+ llvm::Expected<std::unique_ptr<UtilityFunction>> factory_result = factory();
+ if (factory_result)
+ m_dlopen_utility_func_up = std::move(*factory_result);
+ else
+ m_dlopen_utility_func_error =
+ Status::FromError(factory_result.takeError());
+ });
+ if (m_dlopen_utility_func_up)
+ return *m_dlopen_utility_func_up;
+ return m_dlopen_utility_func_error.ToError();
}
llvm::Expected<TraceSupportedResponse> Process::TraceSupported() {
diff --git a/lldb/test/API/functionalities/load_unload/process-load-error-postmortem/Makefile b/lldb/test/API/functionalities/load_unload/process-load-error-postmortem/Makefile
new file mode 100644
index 0000000000000..c7256ac7e3263
--- /dev/null
+++ b/lldb/test/API/functionalities/load_unload/process-load-error-postmortem/Makefile
@@ -0,0 +1,4 @@
+C_SOURCES = main.c
+MAKE_DSYM := NO
+
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/load_unload/process-load-error-postmortem/TestProcessLoadErrorPostmortem.py b/lldb/test/API/functionalities/load_unload/process-load-error-postmortem/TestProcessLoadErrorPostmortem.py
new file mode 100644
index 0000000000000..320953747df56
--- /dev/null
+++ b/lldb/test/API/functionalities/load_unload/process-load-error-postmortem/TestProcessLoadErrorPostmortem.py
@@ -0,0 +1,51 @@
+"""
+Test that Process::LoadImage reports a real error, not an empty/null one, on
+every call after the first, when there is no live process to call dlopen in
+(e.g. debugging a core file).
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ProcessLoadErrorPostmortemTestCase(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ @skipIfWindows # Windows does not support "process load" the same way.
+ @skipIfRemote # save-core / core loading is local-target only here.
+ def test_load_image_error_replayed_on_core(self):
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ core = self.getBuildArtifact("process.core")
+
+ (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+ self, "// break here", lldb.SBFileSpec("main.c")
+ )
+
+ self.runCmd("process save-core --style=stack " + core)
+ process.Kill()
+ self.dbg.DeleteTarget(target)
+
+ target = self.dbg.CreateTarget(exe)
+ process = target.LoadCore(core)
+ self.assertTrue(process.IsValid(), "Could not load the core file")
+
+ nonexistent = lldb.SBFileSpec(
+ "/NoSuchDir/NoSuchSubdir/not-a-real-library", False
+ )
+
+ messages = []
+ for _ in range(2):
+ error = lldb.SBError()
+ token = process.LoadImage(nonexistent, error)
+ self.assertEqual(token, lldb.LLDB_INVALID_IMAGE_TOKEN)
+ self.assertTrue(error.Fail())
+ message = error.GetCString()
+ self.assertIsNotNone(message)
+ self.assertNotEqual(message, "")
+ self.assertNotIn("(null)", message)
+ messages.append(message)
+
+ self.assertEqual(messages[0], messages[1])
diff --git a/lldb/test/API/functionalities/load_unload/process-load-error-postmortem/main.c b/lldb/test/API/functionalities/load_unload/process-load-error-postmortem/main.c
new file mode 100644
index 0000000000000..fa0d6e8b5f797
--- /dev/null
+++ b/lldb/test/API/functionalities/load_unload/process-load-error-postmortem/main.c
@@ -0,0 +1,4 @@
+int main() {
+ int stack_int = 5;
+ return stack_int; // break here
+}
diff --git a/lldb/test/API/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py b/lldb/test/API/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py
index b4c19ee8fc7b1..eb4d7a2eee29e 100644
--- a/lldb/test/API/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py
+++ b/lldb/test/API/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py
@@ -65,3 +65,30 @@ def test_stack_info_in_wow64_mini_dump(self):
eip = frame.FindRegister("pc")
self.assertTrue(eip.IsValid())
self.assertEqual(pc, eip.GetValueAsUnsigned())
+
+ @skipIfLLVMTargetMissing("X86")
+ def test_load_image_error_replayed_on_wow64_mini_dump(self):
+ """Test that Process::LoadImage reports a real error, not an empty
+ one, on every call, when debugging a minidump."""
+ self.runCmd("platform select remote-windows")
+ target = self.dbg.CreateTarget("")
+ process = target.LoadCore("fizzbuzz_wow64.dmp")
+ self.assertTrue(process, PROCESS_IS_VALID)
+
+ nonexistent = lldb.SBFileSpec(
+ r"Z:\NoSuchDir\NoSuchSubdir\not-a-real-library.dll", False
+ )
+
+ messages = []
+ for _ in range(2):
+ error = lldb.SBError()
+ token = process.LoadImage(nonexistent, error)
+ self.assertEqual(token, lldb.LLDB_INVALID_IMAGE_TOKEN)
+ self.assertTrue(error.Fail())
+ message = error.GetCString()
+ self.assertIsNotNone(message)
+ self.assertNotEqual(message, "")
+ self.assertNotIn("(null)", message)
+ messages.append(message)
+
+ self.assertEqual(messages[0], messages[1])
>From 7a7950df02b272fb99e5135e0e7f652b4fadf839 Mon Sep 17 00:00:00 2001
From: Jiaxun Yang <jiaxun.yang at flygoat.com>
Date: Sun, 4 Oct 2026 15:29:00 +0100
Subject: [PATCH 12/18] [Mips] Emit 16-bit microMIPS NOPs for alignment
(#228879)
Zero-filled halfword padding is not a complete microMIPS NOP. Emit
move $zero, $zero when alignment requires a two-byte instruction, then
use zero-encoded 32-bit NOPs for the remaining padding.
Handle an odd leading byte as data padding and preserve zero filling in
standard MIPS mode. Extend the unaligned-NOP test to cover both byte
orders, odd-sized data, and mode changes.
Assisted-by: OpenAI Codex # Testcases
---
.../Mips/MCTargetDesc/MipsAsmBackend.cpp | 26 ++++++++++----
llvm/test/MC/Mips/unaligned-nops.s | 36 +++++++++++++++++++
2 files changed, 56 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
index 74e7baf1db293..71069722aa4a1 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -24,6 +24,7 @@
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/MCValue.h"
+#include "llvm/Support/EndianStream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
@@ -583,13 +584,26 @@ MCFixupKindInfo MipsAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
/// \return - True on success.
bool MipsAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
- // Check for a less than instruction size number of bytes
- // FIXME: 16 bit instructions are not handled yet here.
- // We shouldn't be using a hard coded number for instruction size.
+ // We mostly follow binutils' convention here: align to an even boundary with
+ // zero-fill padding, then emit up to one 2-byte NOP. Use move $zero, $zero
+ // for microMIPS, or zero-fill for standard MIPS. Pad the remainder with
+ // 4-byte NOPs.
+
+ // An odd byte is data padding. Align to an instruction boundary first.
+ if (Count % 2) {
+ OS.write_zeros(1);
+ Count -= 1;
+ }
+
+ if (Count % 4 == 2) {
+ // Use move $zero, $zero for a microMIPS 16-bit NOP. For standard MIPS,
+ // this halfword is data padding.
+ uint16_t Nop = STI && STI->hasFeature(Mips::FeatureMicroMips) ? 0x0c00 : 0;
+ support::endian::write<uint16_t>(OS, Nop, Endian);
+ Count -= 2;
+ }
- // If the count is not 4-byte aligned, we must be writing data into the text
- // section (otherwise we have unaligned instructions, and thus have far
- // bigger problems), so just write zeros instead.
+ // Zero encodes a 32-bit NOP in both standard MIPS and microMIPS.
OS.write_zeros(Count);
return true;
}
diff --git a/llvm/test/MC/Mips/unaligned-nops.s b/llvm/test/MC/Mips/unaligned-nops.s
index ebbbb40f4dc69..45dc65d9b2ec5 100644
--- a/llvm/test/MC/Mips/unaligned-nops.s
+++ b/llvm/test/MC/Mips/unaligned-nops.s
@@ -1,4 +1,40 @@
+# RUN: llvm-mc -triple=mipsel -mcpu=mips32r2 -mattr=+micromips -filetype=obj %s -o %t.le.o
+# RUN: llvm-objdump -s -j .text.micromips %t.le.o | FileCheck %s --check-prefix=LE
+# RUN: llvm-mc -triple=mips -mcpu=mips32r2 -mattr=+micromips -filetype=obj %s -o %t.be.o
+# RUN: llvm-objdump -s -j .text.micromips %t.be.o | FileCheck %s --check-prefix=BE
# RUN: llvm-mc -filetype=obj -triple=mipsel %s -o %t
.byte 1
.p2align 2
foo:
+
+.section .text.micromips,"ax", at progbits
+.set micromips
+.set noreorder
+ move $2, $3
+ .p2align 2
+ move $2, $3
+ .p2align 3
+ move $2, $3
+ .p2align 3
+
+## Emit one 16-bit NOP (0x0c00), then fill the remaining words with zero NOPs.
+# LE: 0000 430c000c 430c000c 430c000c 00000000
+# BE: 0000 0c430c00 0c430c00 0c430c00 00000000
+
+## An odd-sized data item needs a zero byte before the NOPs.
+ .byte 0xff
+ .p2align 3
+
+## Standard MIPS padding remains zero; .set pop restores microMIPS padding.
+.set push
+.set nomicromips
+ nop
+ .p2align 3
+.set pop
+ move $2, $3
+ .p2align 3
+
+# LE: 0010 ff00000c 00000000 00000000 00000000
+# BE: 0010 ff000c00 00000000 00000000 00000000
+# LE: 0020 430c000c 00000000
+# BE: 0020 0c430c00 00000000
>From 2f99c9c58eb656ae80f621d9afdfa700d693d78d Mon Sep 17 00:00:00 2001
From: Jiaxun Yang <jiaxun.yang at flygoat.com>
Date: Sun, 4 Oct 2026 15:35:41 +0100
Subject: [PATCH 13/18] [lld][Mips] Remove signed range check for
R_MICROMIPS_26_S1 (#228880)
R_MICROMIPS_26_S1 encodes a shifted index within the current PC region,
not a signed absolute address. Applying the PC-relative relocation's
signed 27-bit check rejects valid destinations in higher address
regions.
Write the jump index without that check, as for R_MIPS_26, while
retaining
the signed range check for R_MICROMIPS_PC26_S1. Cover both jumps and
calls
at a high address in little- and big-endian objects.
Assisted-by: OpenAI Codex # Testcases
---
lld/ELF/Arch/Mips.cpp | 4 ++++
lld/test/ELF/mips-micro-jump-region.s | 27 +++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
create mode 100644 lld/test/ELF/mips-micro-jump-region.s
diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp
index ba751660df1fa..308a0f75e588d 100644
--- a/lld/ELF/Arch/Mips.cpp
+++ b/lld/ELF/Arch/Mips.cpp
@@ -907,6 +907,10 @@ void MIPS<ELFT>::relocate(uint8_t *loc, const Relocation &rel,
writeValue(ctx, loc, val, 32, 0);
break;
case R_MICROMIPS_26_S1:
+ // Like R_MIPS_26, this encodes an index within the current PC region,
+ // not a signed absolute address. The destination need not fit in 27 bits.
+ writeShuffle<e>(ctx, loc, val, 26, 1);
+ break;
case R_MICROMIPS_PC26_S1:
checkInt(ctx, loc, val, 27, rel);
writeShuffle<e>(ctx, loc, val, 26, 1);
diff --git a/lld/test/ELF/mips-micro-jump-region.s b/lld/test/ELF/mips-micro-jump-region.s
new file mode 100644
index 0000000000000..ceb604f561911
--- /dev/null
+++ b/lld/test/ELF/mips-micro-jump-region.s
@@ -0,0 +1,27 @@
+# REQUIRES: mips
+# RUN: llvm-mc -triple=mipsel -mcpu=mips32r2 -mattr=+micromips -filetype=obj %s -o %t.le.o
+# RUN: ld.lld -Ttext=0x80100000 %t.le.o -o %t.le
+# RUN: llvm-objdump -s -j .text %t.le | FileCheck %s --check-prefix=LE
+# RUN: llvm-mc -triple=mips -mcpu=mips32r2 -mattr=+micromips -filetype=obj %s -o %t.be.o
+# RUN: ld.lld -Ttext=0x80100000 %t.be.o -o %t.be
+# RUN: llvm-objdump -s -j .text %t.be | FileCheck %s --check-prefix=BE
+
+## The jump index occupies 26 bits within the current PC region; the full
+## destination address need not fit in a signed 27-bit value.
+## Both a tail jump and a call must retain the low 27 address bits.
+# LE: 80100000 08d40800 00000000 08f40800 00000000
+# BE: 80100000 d4080008 00000000 f4080008 00000000
+
+.set micromips
+.set noreorder
+.globl __start, target
+.type __start, at function
+__start:
+ j target
+ sll $0, $0, 0
+ jal target
+ sll $0, $0, 0
+.type target, at function
+target:
+ jr $ra
+ sll $0, $0, 0
>From 22c49fe69417d8678b535d38fb115bf8371d8f73 Mon Sep 17 00:00:00 2001
From: Jiaxun Yang <jiaxun.yang at flygoat.com>
Date: Sun, 4 Oct 2026 15:40:57 +0100
Subject: [PATCH 14/18] [Mips] Restrict microMIPS GP load folding to word loads
(#228881)
Only LW has a GP-relative variant, so restrict the folding to LW_MM and
LW_MMR6.
Assisted-by: OpenAI Codex # Testcases
---
llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index 48163a54f4837..d2ef7003721e1 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -2135,7 +2135,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
}
if (inMicroMipsMode()) {
- if (MCID.mayLoad() && Opcode != Mips::LWP_MM) {
+ if (Opcode == Mips::LW_MM || Opcode == Mips::LW_MMR6) {
// Try to create 16-bit GP relative load instruction.
for (unsigned i = 0; i < MCID.getNumOperands(); i++) {
const MCOperandInfo &OpInfo = MCID.operands()[i];
@@ -2159,7 +2159,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
}
}
} // for
- } // if load
+ } // if load
// TODO: Handle this with the AsmOperandClass.PredicateMethod.
>From 092c5518e3f9d927d856619ff32a10c30f7b916f Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Sun, 4 Oct 2026 16:51:21 +0200
Subject: [PATCH 15/18] [OCaml] Use DataLayout instead of string in
(set_)data_layout (#228445)
Now that DataLayout is part of llvm rather than llvm_target, make use of
it in the `data_layout` and `set_data_layout` APIs.
---
llvm/bindings/ocaml/llvm/llvm.ml | 4 ++--
llvm/bindings/ocaml/llvm/llvm.mli | 15 +++++++--------
llvm/bindings/ocaml/llvm/llvm_ocaml.c | 10 ++++------
llvm/bindings/ocaml/llvm/llvm_ocaml.h | 1 +
llvm/docs/ReleaseNotes.md | 4 ++++
llvm/test/Bindings/OCaml/core.ml | 4 ++--
llvm/test/Bindings/OCaml/debuginfo.ml | 5 ++---
7 files changed, 22 insertions(+), 21 deletions(-)
diff --git a/llvm/bindings/ocaml/llvm/llvm.ml b/llvm/bindings/ocaml/llvm/llvm.ml
index ce57b4316e879..48bd48b9e4eba 100644
--- a/llvm/bindings/ocaml/llvm/llvm.ml
+++ b/llvm/bindings/ocaml/llvm/llvm.ml
@@ -483,9 +483,9 @@ external target_triple: llmodule -> string
= "llvm_target_triple"
external set_target_triple: string -> llmodule -> unit
= "llvm_set_target_triple"
-external data_layout: llmodule -> string
+external data_layout: llmodule -> DataLayout.t
= "llvm_data_layout"
-external set_data_layout: string -> llmodule -> unit
+external set_data_layout: DataLayout.t -> llmodule -> unit
= "llvm_set_data_layout"
external dump_module : llmodule -> unit = "llvm_dump_module"
external print_module : string -> llmodule -> unit = "llvm_print_module"
diff --git a/llvm/bindings/ocaml/llvm/llvm.mli b/llvm/bindings/ocaml/llvm/llvm.mli
index 93e0364227ebc..294f88c70f8f1 100644
--- a/llvm/bindings/ocaml/llvm/llvm.mli
+++ b/llvm/bindings/ocaml/llvm/llvm.mli
@@ -604,14 +604,13 @@ val target_triple: llmodule -> string
the string [triple]. See the method [llvm::Module::setTargetTriple]. *)
val set_target_triple: string -> llmodule -> unit
-(** [data_layout m] is the data layout specifier for the module [m], something
- like [e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-...-a0:0:64-f80:128:128]. See the
- method [llvm::Module::getDataLayout]. *)
-val data_layout: llmodule -> string
-
-(** [set_data_layout s m] changes the data layout specifier for the module [m]
- to the string [s]. See the method [llvm::Module::setDataLayout]. *)
-val set_data_layout: string -> llmodule -> unit
+(** [data_layout m] is the data layout for the module [m].
+ See the method [llvm::Module::getDataLayout]. *)
+val data_layout: llmodule -> DataLayout.t
+
+(** [set_data_layout dl m] changes the data layout specifier for the module [m]
+ to [dl]. See the method [llvm::Module::setDataLayout]. *)
+val set_data_layout: DataLayout.t -> llmodule -> unit
(** [dump_module m] prints the .ll representation of the module [m] to standard
error. See the method [llvm::Module::dump]. *)
diff --git a/llvm/bindings/ocaml/llvm/llvm_ocaml.c b/llvm/bindings/ocaml/llvm/llvm_ocaml.c
index 42a07c8dc79a0..e08797cf0e3d9 100644
--- a/llvm/bindings/ocaml/llvm/llvm_ocaml.c
+++ b/llvm/bindings/ocaml/llvm/llvm_ocaml.c
@@ -328,14 +328,14 @@ value llvm_set_target_triple(value Trip, value M) {
return Val_unit;
}
-/* llmodule -> string */
+/* llmodule -> DataLayout.t */
value llvm_data_layout(value M) {
- return caml_copy_string(LLVMGetDataLayout(Module_val(M)));
+ return llvm_alloc_data_layout(LLVMGetModuleDataLayout(Module_val(M)));
}
-/* string -> llmodule -> unit */
+/* DataLayout.t -> llmodule -> unit */
value llvm_set_data_layout(value Layout, value M) {
- LLVMSetDataLayout(Module_val(M), String_val(Layout));
+ LLVMSetModuleDataLayout(Module_val(M), DataLayout_val(Layout));
return Val_unit;
}
@@ -2780,8 +2780,6 @@ value llvm_memorybuffer_dispose(value MemBuf) {
/*===---- Data Layout -----------------------------------------------------===*/
-#define DataLayout_val(v) (*(LLVMTargetDataRef *)(Data_custom_val(v)))
-
static void llvm_finalize_data_layout(value DataLayout) {
LLVMDisposeTargetData(DataLayout_val(DataLayout));
}
diff --git a/llvm/bindings/ocaml/llvm/llvm_ocaml.h b/llvm/bindings/ocaml/llvm/llvm_ocaml.h
index 79cadba6275ee..6b4082a84baad 100644
--- a/llvm/bindings/ocaml/llvm/llvm_ocaml.h
+++ b/llvm/bindings/ocaml/llvm/llvm_ocaml.h
@@ -58,6 +58,7 @@ void *from_val_array(value Elements);
#define Use_val(v) ((LLVMUseRef)from_val(v))
#define BasicBlock_val(v) ((LLVMBasicBlockRef)from_val(v))
#define MemoryBuffer_val(v) ((LLVMMemoryBufferRef)from_val(v))
+#define DataLayout_val(v) (*(LLVMTargetDataRef *)(Data_custom_val(v)))
/* Convert a C pointer to an OCaml option */
value ptr_to_option(void *Ptr);
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 9a5dbbcdb6609..93674c1825367 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -310,6 +310,10 @@ Makes programs 10x faster by doing Special New Thing.
* `DataLayout` has been moved from `Llvm_target` to `Llvm`.
+* `data_layout` now returns a `DataLayout` instead of a `string`. Similarly
+ `set_data_layout` now accepts a `DataLayout` instead of a `string`. You can
+ use `DataLayout.of_string` and `DataLayout.as_string` to convert between them.
+
### Changes to the Python bindings
### Changes to the C API
diff --git a/llvm/test/Bindings/OCaml/core.ml b/llvm/test/Bindings/OCaml/core.ml
index 797f8d27f73df..b44058b2ad25a 100644
--- a/llvm/test/Bindings/OCaml/core.ml
+++ b/llvm/test/Bindings/OCaml/core.ml
@@ -83,8 +83,8 @@ let test_target () =
begin group "layout";
let layout = "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:128-n8:16:32-S128" in
- set_data_layout layout m;
- insist (layout = data_layout m)
+ set_data_layout (DataLayout.of_string layout) m;
+ insist (layout = DataLayout.as_string (data_layout m))
end
(* CHECK: target datalayout = "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:128-n8:16:32-S128"
* CHECK: target triple = "i686-apple-darwin8"
diff --git a/llvm/test/Bindings/OCaml/debuginfo.ml b/llvm/test/Bindings/OCaml/debuginfo.ml
index 1f1d5c2c4c3ce..9135f183743b0 100644
--- a/llvm/test/Bindings/OCaml/debuginfo.ml
+++ b/llvm/test/Bindings/OCaml/debuginfo.ml
@@ -28,11 +28,10 @@ let prepare_target llmod =
let triple = Llvm_target.Target.default_triple () in
let lltarget = Llvm_target.Target.by_triple triple in
let llmachine = Llvm_target.TargetMachine.create ~triple lltarget in
- let lldly = Llvm.DataLayout.as_string
- (Llvm_target.TargetMachine.data_layout llmachine)
+ let dl = Llvm_target.TargetMachine.data_layout llmachine
in
let _ = Llvm.set_target_triple triple llmod in
- let _ = Llvm.set_data_layout lldly llmod in
+ let _ = Llvm.set_data_layout dl llmod in
()
let new_module () =
>From 9068deb36344cc50c549d2d3238f76a167ce09b9 Mon Sep 17 00:00:00 2001
From: Jiaxun Yang <jiaxun.yang at flygoat.com>
Date: Sun, 4 Oct 2026 16:28:23 +0100
Subject: [PATCH 16/18] [Mips] Add microMIPS hazard-barrier jump encodings
(#228885)
Add microMIPS encodings for jr.hb and jalr.hb. Use BaseOpcode and MMRel
to map the standard opcodes to their microMIPS encodings.
Assisted-by: OpenAI Codex # Testcases
---
llvm/lib/Target/Mips/MicroMipsInstrInfo.td | 8 ++++++++
llvm/lib/Target/Mips/MipsInstrInfo.td | 12 +++++++-----
llvm/lib/Target/Mips/MipsScheduleGeneric.td | 4 ++--
.../MC/Mips/micromips-jump-instructions.s | 19 +++++++++++++++++++
4 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/Mips/MicroMipsInstrInfo.td b/llvm/lib/Target/Mips/MicroMipsInstrInfo.td
index dff57a5d59dc1..100d213af1b9b 100644
--- a/llvm/lib/Target/Mips/MicroMipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/MicroMipsInstrInfo.td
@@ -938,6 +938,11 @@ let DecoderNamespace = "MicroMips" in {
def JALR_MM : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM_MM<0x03c>,
ISA_MICROMIPS32_NOT_MIPS32R6;
+ def JR_HB_MM : MMRel, JR_HB_DESC<GPR32Opnd>, JR_FM_MM<0x7c>,
+ ISA_MICROMIPS32_NOT_MIPS32R6;
+ def JALR_HB_MM : MMRel, JALR_HB_DESC<GPR32Opnd>, JALR_FM_MM<0x07c>, MMArch,
+ ISA_MICROMIPS32_NOT_MIPS32R6;
+
/// Jump Instructions - Short Delay Slot
def JALS_MM : JumpLinkMM<"jals", calltarget_mm>, J_FM_MM<0x1d>,
ISA_MICROMIPS32_NOT_MIPS32R6;
@@ -1393,6 +1398,9 @@ let EncodingPredicates = [InMicroMips] in {
def : MipsInstAlias<"bal $offset", (BGEZAL_MM ZERO, brtarget_mm:$offset), 1>,
ISA_MICROMIPS32_NOT_MIPS32R6;
+ def : MipsInstAlias<"jalr.hb $rs", (JALR_HB_MM RA, GPR32Opnd:$rs), 0>,
+ ISA_MICROMIPS32_NOT_MIPS32R6;
+
def : MipsInstAlias<"j $rs", (JR_MM GPR32Opnd:$rs), 0>,
ISA_MICROMIPS32_NOT_MIPS32R6;
}
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.td b/llvm/lib/Target/Mips/MipsInstrInfo.td
index 3b523af856d1c..73824b28340e4 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.td
@@ -2516,7 +2516,8 @@ class JALR_HB_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> {
}
class JR_HB_DESC<RegisterOperand RO> :
- InstSE<(outs), (ins), "", [], FrmJ>, JR_HB_DESC_BASE<"jr.hb", RO> {
+ InstSE<(outs), (ins), "", [], FrmJ, "jr.hb">,
+ JR_HB_DESC_BASE<"jr.hb", RO> {
let isBranch=1;
let isIndirectBranch=1;
let hasDelaySlot=1;
@@ -2526,8 +2527,8 @@ class JR_HB_DESC<RegisterOperand RO> :
}
class JALR_HB_DESC<RegisterOperand RO> :
- InstSE<(outs), (ins), "", [], FrmJ>, JALR_HB_DESC_BASE<"jalr.hb",
- RO> {
+ InstSE<(outs), (ins), "", [], FrmJ, "jalr.hb">,
+ JALR_HB_DESC_BASE<"jalr.hb", RO> {
let isIndirectBranch=1;
let hasDelaySlot=1;
bit isCTI = 1;
@@ -2536,8 +2537,9 @@ class JALR_HB_DESC<RegisterOperand RO> :
class JR_HB_ENC : JR_HB_FM<8>;
class JALR_HB_ENC : JALR_HB_FM<9>;
-def JR_HB : JR_HB_DESC<GPR32Opnd>, JR_HB_ENC, ISA_MIPS32R2_NOT_32R6_64R6;
-def JALR_HB : JALR_HB_DESC<GPR32Opnd>, JALR_HB_ENC, ISA_MIPS32;
+def JR_HB : MMRel, JR_HB_DESC<GPR32Opnd>, JR_HB_ENC,
+ ISA_MIPS32R2_NOT_32R6_64R6;
+def JALR_HB : MMRel, JALR_HB_DESC<GPR32Opnd>, JALR_HB_ENC, ISA_MIPS32;
let AdditionalPredicates = [NotInMicroMips, UseIndirectJumpsHazard] in
def JALRHBPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR_HB, RA>;
diff --git a/llvm/lib/Target/Mips/MipsScheduleGeneric.td b/llvm/lib/Target/Mips/MipsScheduleGeneric.td
index d2526ee238f72..81d7d4a7646c3 100644
--- a/llvm/lib/Target/Mips/MipsScheduleGeneric.td
+++ b/llvm/lib/Target/Mips/MipsScheduleGeneric.td
@@ -285,7 +285,7 @@ def GenericWriteJumpAndLink : SchedWriteRes<[GenericIssueCTISTD]> {
// jalr, jr.hb, jr, jalr.hb, jarlc, jialc
def : InstRW<[GenericWriteJump], (instrs B, BAL, BAL_BR, BEQ, BNE, BGTZ, BGEZ,
BLEZ, BLTZ, BLTZAL, J, JALX, JR, JR_HB, ERET,
- ERet, ERETNC, DERET, NAL)>;
+ ERet, ERETNC, DERET, NAL, JR_HB_MM)>;
def : InstRW<[GenericWriteJump], (instrs BEQL, BNEL, BGEZL, BGTZL, BLEZL,
BLTZL)>;
@@ -296,7 +296,7 @@ def : InstRW<[GenericWriteJump], (instrs TAILCALL, TAILCALLREG,
RetRA)>;
def : InstRW<[GenericWriteJumpAndLink], (instrs BGEZAL, JAL, JALR, JALR_HB,
- JALRHBPseudo, JALRPseudo)>;
+ JALRHBPseudo, JALRPseudo, JALR_HB_MM)>;
def : InstRW<[GenericWriteJumpAndLink], (instrs BGEZALL, BLTZALL)>;
diff --git a/llvm/test/MC/Mips/micromips-jump-instructions.s b/llvm/test/MC/Mips/micromips-jump-instructions.s
index f8d4974de6cd3..f42d534706e8e 100644
--- a/llvm/test/MC/Mips/micromips-jump-instructions.s
+++ b/llvm/test/MC/Mips/micromips-jump-instructions.s
@@ -1,3 +1,5 @@
+# RUN: llvm-mc -triple=mipsel -mcpu=mips32r2 -mattr=+micromips -filetype=obj %s | llvm-objdump -d --mattr=+micromips - | FileCheck %s --check-prefix=DIS
+# RUN: llvm-mc -triple=mips -mcpu=mips32r2 -mattr=+micromips -filetype=obj %s | llvm-objdump -d --mattr=+micromips - | FileCheck %s --check-prefix=DIS
# RUN: llvm-mc %s -triple=mipsel -show-encoding -mattr=micromips \
# RUN: | FileCheck %s -check-prefix=CHECK-EL
# RUN: llvm-mc %s -triple=mips -show-encoding -mattr=micromips \
@@ -63,3 +65,20 @@
jalrs $ra, $6
jal $25
jal $4, $25
+
+ .set noreorder
+ jr.hb $3
+# CHECK-EL: jr.hb $3 # encoding: [0x03,0x00,0x3c,0x1f]
+# CHECK-EB: jr.hb $3 # encoding: [0x00,0x03,0x1f,0x3c]
+# DIS: jr.hb $3
+ nop
+ jalr.hb $6, $7
+# CHECK-EL: jalr.hb $6, $7 # encoding: [0xc7,0x00,0x3c,0x1f]
+# CHECK-EB: jalr.hb $6, $7 # encoding: [0x00,0xc7,0x1f,0x3c]
+# DIS: jalr.hb $6, $7
+ nop
+ jalr.hb $8
+# CHECK-EL: jalr.hb $ra, $8 # encoding: [0xe8,0x03,0x3c,0x1f]
+# CHECK-EB: jalr.hb $ra, $8 # encoding: [0x03,0xe8,0x1f,0x3c]
+# DIS: jalr.hb $ra, $8
+ nop
>From 9870703eb8e7fe5799abe68d0b8fee29e5bf504d Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Sun, 4 Oct 2026 17:43:37 +0200
Subject: [PATCH 17/18] [Loongarch] fix int to float conversion on non-MVT
vector types (#228896)
fixes https://github.com/llvm/llvm-project/issues/228894
The code added in https://github.com/llvm/llvm-project/pull/202496 can
construct an invalid MVT (e.g. a 5-element vector, which is not
something any architecture has a specific register for). So, instead use
an `EVT` which is less restrictive.
---
.../LoongArch/LoongArchISelLowering.cpp | 2 +-
.../LoongArch/lasx/ir-instruction/sitofp.ll | 31 ++++++++++
.../LoongArch/lasx/ir-instruction/uitofp.ll | 31 ++++++++++
.../LoongArch/lsx/ir-instruction/sitofp.ll | 54 ++++++++++++++++++
.../LoongArch/lsx/ir-instruction/uitofp.ll | 56 ++++++++++++++++++-
5 files changed, 171 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 07f6a438bbb1b..88a164034e15f 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -8366,7 +8366,7 @@ static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp) {
return SDValue();
MVT WidenEltVT = MVT::getIntegerVT(DstEltBits);
- MVT WidenSrcVT = MVT::getVectorVT(WidenEltVT, DstElts);
+ EVT WidenSrcVT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, DstElts);
SDValue Extend = DAG.getNode(ExtendOp, DL, WidenSrcVT, Src);
return DAG.getNode(N->getOpcode(), DL, VT, Extend);
diff --git a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/sitofp.ll b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/sitofp.ll
index b0cbc6e34192c..94410e2f4cf66 100644
--- a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/sitofp.ll
+++ b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/sitofp.ll
@@ -190,3 +190,34 @@ define <4 x double> @sitofp_v16i8_v4f64(<16 x i8> %a) {
%shuf = shufflevector <16 x double> %cvt, <16 x double> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
ret <4 x double> %shuf
}
+
+define <5 x double> @sitofp_v5i32_v5f64(<5 x i32> %a) {
+; CHECK-LABEL: sitofp_v5i32_v5f64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xvpermi.q $xr1, $xr0, 1
+; CHECK-NEXT: vext2xv.d.w $xr1, $xr1
+; CHECK-NEXT: xvffint.d.l $xr1, $xr1
+; CHECK-NEXT: vext2xv.d.w $xr0, $xr0
+; CHECK-NEXT: xvffint.d.l $xr0, $xr0
+; CHECK-NEXT: xvst $xr0, $a0, 0
+; CHECK-NEXT: xvstelm.d $xr1, $a0, 32, 0
+; CHECK-NEXT: ret
+ %v = sitofp <5 x i32> %a to <5 x double>
+ ret <5 x double> %v
+}
+
+define <7 x double> @sitofp_v7i32_v7f64(<7 x i32> %a) {
+; CHECK-LABEL: sitofp_v7i32_v7f64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xvpermi.q $xr1, $xr0, 1
+; CHECK-NEXT: vext2xv.d.w $xr1, $xr1
+; CHECK-NEXT: xvffint.d.l $xr1, $xr1
+; CHECK-NEXT: vext2xv.d.w $xr0, $xr0
+; CHECK-NEXT: xvffint.d.l $xr0, $xr0
+; CHECK-NEXT: xvst $xr0, $a0, 0
+; CHECK-NEXT: xvstelm.d $xr1, $a0, 48, 2
+; CHECK-NEXT: vst $vr1, $a0, 32
+; CHECK-NEXT: ret
+ %v = sitofp <7 x i32> %a to <7 x double>
+ ret <7 x double> %v
+}
diff --git a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/uitofp.ll b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/uitofp.ll
index 340e45dbfdb84..e6f4db627709c 100644
--- a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/uitofp.ll
+++ b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/uitofp.ll
@@ -117,3 +117,34 @@ define <4 x double> @uitofp_v16i8_v4f64(<16 x i8> %a) {
%shuf = shufflevector <16 x double> %cvt, <16 x double> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
ret <4 x double> %shuf
}
+
+define <5 x double> @uitofp_v5i32_v5f64(<5 x i32> %a) {
+; CHECK-LABEL: uitofp_v5i32_v5f64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xvpermi.q $xr1, $xr0, 1
+; CHECK-NEXT: vext2xv.du.wu $xr1, $xr1
+; CHECK-NEXT: xvffint.d.l $xr1, $xr1
+; CHECK-NEXT: vext2xv.du.wu $xr0, $xr0
+; CHECK-NEXT: xvffint.d.l $xr0, $xr0
+; CHECK-NEXT: xvst $xr0, $a0, 0
+; CHECK-NEXT: xvstelm.d $xr1, $a0, 32, 0
+; CHECK-NEXT: ret
+ %v = uitofp <5 x i32> %a to <5 x double>
+ ret <5 x double> %v
+}
+
+define <7 x double> @uitofp_v7i32_v7f64(<7 x i32> %a) {
+; CHECK-LABEL: uitofp_v7i32_v7f64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xvpermi.q $xr1, $xr0, 1
+; CHECK-NEXT: vext2xv.du.wu $xr1, $xr1
+; CHECK-NEXT: xvffint.d.l $xr1, $xr1
+; CHECK-NEXT: vext2xv.du.wu $xr0, $xr0
+; CHECK-NEXT: xvffint.d.l $xr0, $xr0
+; CHECK-NEXT: xvst $xr0, $a0, 0
+; CHECK-NEXT: xvstelm.d $xr1, $a0, 48, 2
+; CHECK-NEXT: vst $vr1, $a0, 32
+; CHECK-NEXT: ret
+ %v = uitofp <7 x i32> %a to <7 x double>
+ ret <7 x double> %v
+}
diff --git a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/sitofp.ll b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/sitofp.ll
index a3b5a17622114..d6177d5ca0969 100644
--- a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/sitofp.ll
+++ b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/sitofp.ll
@@ -226,3 +226,57 @@ define <4 x double> @sitofp_v16i8_v4f64(<16 x i8> %a) {
%shuf = shufflevector <16 x double> %cvt, <16 x double> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
ret <4 x double> %shuf
}
+
+define <5 x double> @sitofp_v5i32_v5f64(<5 x i32> %a) {
+; LA32-LABEL: sitofp_v5i32_v5f64:
+; LA32: # %bb.0:
+; LA32-NEXT: ld.w $a2, $a1, 16
+; LA32-NEXT: vinsgr2vr.w $vr0, $a2, 0
+; LA32-NEXT: ld.w $a2, $a1, 0
+; LA32-NEXT: ld.w $a3, $a1, 4
+; LA32-NEXT: ld.w $a4, $a1, 8
+; LA32-NEXT: ld.w $a1, $a1, 12
+; LA32-NEXT: vinsgr2vr.w $vr1, $a2, 0
+; LA32-NEXT: vinsgr2vr.w $vr1, $a3, 1
+; LA32-NEXT: vinsgr2vr.w $vr1, $a4, 2
+; LA32-NEXT: vinsgr2vr.w $vr1, $a1, 3
+; LA32-NEXT: vslti.w $vr2, $vr1, 0
+; LA32-NEXT: vilvl.w $vr3, $vr2, $vr1
+; LA32-NEXT: vffint.d.l $vr3, $vr3
+; LA32-NEXT: vilvh.w $vr1, $vr2, $vr1
+; LA32-NEXT: vffint.d.l $vr1, $vr1
+; LA32-NEXT: vslti.w $vr2, $vr0, 0
+; LA32-NEXT: vilvl.w $vr0, $vr2, $vr0
+; LA32-NEXT: vffint.d.l $vr0, $vr0
+; LA32-NEXT: vstelm.d $vr0, $a0, 32, 0
+; LA32-NEXT: vst $vr1, $a0, 16
+; LA32-NEXT: vst $vr3, $a0, 0
+; LA32-NEXT: ret
+;
+; LA64-LABEL: sitofp_v5i32_v5f64:
+; LA64: # %bb.0:
+; LA64-NEXT: ld.w $a2, $a1, 32
+; LA64-NEXT: vinsgr2vr.w $vr0, $a2, 0
+; LA64-NEXT: ld.w $a2, $a1, 0
+; LA64-NEXT: ld.w $a3, $a1, 8
+; LA64-NEXT: ld.w $a4, $a1, 16
+; LA64-NEXT: ld.w $a1, $a1, 24
+; LA64-NEXT: vinsgr2vr.w $vr1, $a2, 0
+; LA64-NEXT: vinsgr2vr.w $vr1, $a3, 1
+; LA64-NEXT: vinsgr2vr.w $vr1, $a4, 2
+; LA64-NEXT: vinsgr2vr.w $vr1, $a1, 3
+; LA64-NEXT: vslti.w $vr2, $vr1, 0
+; LA64-NEXT: vilvl.w $vr3, $vr2, $vr1
+; LA64-NEXT: vffint.d.l $vr3, $vr3
+; LA64-NEXT: vilvh.w $vr1, $vr2, $vr1
+; LA64-NEXT: vffint.d.l $vr1, $vr1
+; LA64-NEXT: vslti.w $vr2, $vr0, 0
+; LA64-NEXT: vilvl.w $vr0, $vr2, $vr0
+; LA64-NEXT: vffint.d.l $vr0, $vr0
+; LA64-NEXT: vstelm.d $vr0, $a0, 32, 0
+; LA64-NEXT: vst $vr1, $a0, 16
+; LA64-NEXT: vst $vr3, $a0, 0
+; LA64-NEXT: ret
+ %v = sitofp <5 x i32> %a to <5 x double>
+ ret <5 x double> %v
+}
diff --git a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/uitofp.ll b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/uitofp.ll
index 6d7a1b1554563..dd526904af415 100644
--- a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/uitofp.ll
+++ b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/uitofp.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3
-; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lsx < %s | FileCheck %s
-; RUN: llc --mtriple=loongarch64 --mattr=+lsx < %s | FileCheck %s
+; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lsx < %s | FileCheck %s --check-prefixes=CHECK,LA32
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx < %s | FileCheck %s --check-prefixes=CHECK,LA64
define void @uitofp_v4i32_v4f32(ptr %res, ptr %in){
; CHECK-LABEL: uitofp_v4i32_v4f32:
@@ -87,3 +87,55 @@ define <4 x double> @uitofp_v16i8_v4f64(<16 x i8> %a) {
%shuf = shufflevector <16 x double> %cvt, <16 x double> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
ret <4 x double> %shuf
}
+
+define <5 x double> @uitofp_v5i32_v5f64(<5 x i32> %a) {
+; LA32-LABEL: uitofp_v5i32_v5f64:
+; LA32: # %bb.0:
+; LA32-NEXT: ld.w $a2, $a1, 16
+; LA32-NEXT: ld.w $a3, $a1, 0
+; LA32-NEXT: ld.w $a4, $a1, 4
+; LA32-NEXT: vinsgr2vr.w $vr0, $a2, 0
+; LA32-NEXT: vinsgr2vr.w $vr1, $a3, 0
+; LA32-NEXT: vinsgr2vr.w $vr1, $a4, 1
+; LA32-NEXT: ld.w $a2, $a1, 12
+; LA32-NEXT: ld.w $a1, $a1, 8
+; LA32-NEXT: vrepli.b $vr2, 0
+; LA32-NEXT: vilvl.w $vr1, $vr2, $vr1
+; LA32-NEXT: vffint.d.lu $vr1, $vr1
+; LA32-NEXT: vinsgr2vr.w $vr3, $a1, 0
+; LA32-NEXT: vinsgr2vr.w $vr3, $a2, 1
+; LA32-NEXT: vilvl.w $vr3, $vr2, $vr3
+; LA32-NEXT: vffint.d.lu $vr3, $vr3
+; LA32-NEXT: vilvl.w $vr0, $vr2, $vr0
+; LA32-NEXT: vffint.d.lu $vr0, $vr0
+; LA32-NEXT: vstelm.d $vr0, $a0, 32, 0
+; LA32-NEXT: vst $vr3, $a0, 16
+; LA32-NEXT: vst $vr1, $a0, 0
+; LA32-NEXT: ret
+;
+; LA64-LABEL: uitofp_v5i32_v5f64:
+; LA64: # %bb.0:
+; LA64-NEXT: ld.w $a2, $a1, 32
+; LA64-NEXT: ld.w $a3, $a1, 0
+; LA64-NEXT: ld.w $a4, $a1, 8
+; LA64-NEXT: vinsgr2vr.w $vr0, $a2, 0
+; LA64-NEXT: vinsgr2vr.w $vr1, $a3, 0
+; LA64-NEXT: vinsgr2vr.w $vr1, $a4, 1
+; LA64-NEXT: ld.w $a2, $a1, 24
+; LA64-NEXT: ld.w $a1, $a1, 16
+; LA64-NEXT: vrepli.b $vr2, 0
+; LA64-NEXT: vilvl.w $vr1, $vr2, $vr1
+; LA64-NEXT: vffint.d.lu $vr1, $vr1
+; LA64-NEXT: vinsgr2vr.w $vr3, $a1, 0
+; LA64-NEXT: vinsgr2vr.w $vr3, $a2, 1
+; LA64-NEXT: vilvl.w $vr3, $vr2, $vr3
+; LA64-NEXT: vffint.d.lu $vr3, $vr3
+; LA64-NEXT: vilvl.w $vr0, $vr2, $vr0
+; LA64-NEXT: vffint.d.lu $vr0, $vr0
+; LA64-NEXT: vstelm.d $vr0, $a0, 32, 0
+; LA64-NEXT: vst $vr3, $a0, 16
+; LA64-NEXT: vst $vr1, $a0, 0
+; LA64-NEXT: ret
+ %v = uitofp <5 x i32> %a to <5 x double>
+ ret <5 x double> %v
+}
>From e65d18f5c1fb050dec83ae73df2f6a28b96a20e5 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 4 Oct 2026 08:50:05 -0700
Subject: [PATCH 18/18] [CodeGen] Declare command line options in TableGen
Move the cl::opts of TargetPassConfig.cpp and CodeGenPrepare.cpp into
CodeGenOptions.td, private to lib/CodeGen; other files will follow.
-enable-machine-outliner (cl::ValueOptional) and -regalloc
(RegisterPassParser) stay cl::opt.
CodeGenPrepare and its addressing-mode helpers hold
`const CodeGenOptions &Opts`; TargetPassConfig functions read
CodeGenOptions::Global. getCGPassBuilderOption() converts BoolOrDefault
members to the cl::boolOrDefault and std::optional<bool> fields of the
public CGPassBuilderOption. -basic-block-section-match-infer, which was
not cl::Hidden, is now listed by -help-hidden only.
Aided by Opus 5.5
---
llvm/lib/CodeGen/CMakeLists.txt | 8 +
llvm/lib/CodeGen/CodeGenOptions.cpp | 15 +
llvm/lib/CodeGen/CodeGenOptions.h | 19 +
llvm/lib/CodeGen/CodeGenOptions.td | 202 ++++++++
llvm/lib/CodeGen/CodeGenPrepare.cpp | 317 ++++--------
llvm/lib/CodeGen/RegisterUsageInfo.cpp | 7 +-
llvm/lib/CodeGen/TargetPassConfig.cpp | 462 ++++++------------
.../gn/secondary/llvm/lib/CodeGen/BUILD.gn | 10 +
.../llvm-project-overlay/llvm/BUILD.bazel | 11 +
9 files changed, 507 insertions(+), 544 deletions(-)
create mode 100644 llvm/lib/CodeGen/CodeGenOptions.cpp
create mode 100644 llvm/lib/CodeGen/CodeGenOptions.h
create mode 100644 llvm/lib/CodeGen/CodeGenOptions.td
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index 7db7c1ca93243..211ce644a4162 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -33,6 +33,11 @@ elseif (DEFINED LLVM_HAVE_TF_AOT OR LLVM_HAVE_TFLITE)
endif()
endif()
+set(LLVM_TABLEGEN_PROJECT LLVM_HEADERS)
+set(LLVM_TARGET_DEFINITIONS CodeGenOptions.td)
+tablegen(LLVM CodeGenOptions.inc -gen-opt-parser-defs)
+add_public_tablegen_target(CodeGenOptionsTableGen)
+
add_llvm_component_library(LLVMCodeGen
AggressiveAntiDepBreaker.cpp
AllocationOrder.cpp
@@ -54,6 +59,7 @@ add_llvm_component_library(LLVMCodeGen
CFIInstrInserter.cpp
CodeGen.cpp
CodeGenCommonISel.cpp
+ CodeGenOptions.cpp
CodeGenPrepare.cpp
CommandFlags.cpp
ComplexDeinterleavingPass.cpp
@@ -284,6 +290,7 @@ add_llvm_component_library(LLVMCodeGen
LINK_LIBS ${LLVM_PTHREAD_LIB} ${MLLinkDeps}
DEPENDS
+ CodeGenOptionsTableGen
intrinsics_gen
vt_gen
${MLDeps}
@@ -297,6 +304,7 @@ add_llvm_component_library(LLVMCodeGen
Core
MC
ObjCARC
+ Option
ProfileData
Scalar
Support
diff --git a/llvm/lib/CodeGen/CodeGenOptions.cpp b/llvm/lib/CodeGen/CodeGenOptions.cpp
new file mode 100644
index 0000000000000..31cb2dafa020b
--- /dev/null
+++ b/llvm/lib/CodeGen/CodeGenOptions.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "CodeGenOptions.h"
+#include "llvm/Option/LibraryOptions.h"
+
+#define OPTIONS_STRUCT_DEFS
+#include "CodeGenOptions.inc"
+
+static llvm::opt::RegisterLibraryOptions<llvm::CodeGenOptions> Registration;
diff --git a/llvm/lib/CodeGen/CodeGenOptions.h b/llvm/lib/CodeGen/CodeGenOptions.h
new file mode 100644
index 0000000000000..657850dcbe5df
--- /dev/null
+++ b/llvm/lib/CodeGen/CodeGenOptions.h
@@ -0,0 +1,19 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_LIB_CODEGEN_CODEGENOPTIONS_H
+#define LLVM_LIB_CODEGEN_CODEGENOPTIONS_H
+
+#include "llvm/Target/TargetOptions.h"
+#include <cstdint>
+#include <optional>
+
+#define OPTIONS_STRUCT_DECL
+#include "CodeGenOptions.inc"
+
+#endif // LLVM_LIB_CODEGEN_CODEGENOPTIONS_H
diff --git a/llvm/lib/CodeGen/CodeGenOptions.td b/llvm/lib/CodeGen/CodeGenOptions.td
new file mode 100644
index 0000000000000..f2b9d07f4276a
--- /dev/null
+++ b/llvm/lib/CodeGen/CodeGenOptions.td
@@ -0,0 +1,202 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/Option/LibraryOptions.td"
+
+def CodeGenOptions : OptionsStruct;
+
+// CodeGenPrepare.cpp
+defm : BoolField<"bbsections-guided-section-prefix", "true",
+ "Use the basic-block-sections profile to determine the text section prefix for hot functions. "
+ "Functions with basic-block-sections profile will be placed in `.text.hot` regardless of their FDO profile info. "
+ "Other functions won't be impacted, i.e., their prefixes will be decided by FDO/sampleFDO profiles">;
+defm : BoolField<"addr-sink-combine-base-gv", "true",
+ "Allow combining of BaseGV field in Address sinking">;
+defm : BoolField<"addr-sink-combine-base-offs", "true",
+ "Allow combining of BaseOffs field in Address sinking">;
+defm : BoolField<"addr-sink-combine-base-reg", "true",
+ "Allow combining of BaseReg field in Address sinking">;
+defm : BoolField<"addr-sink-combine-scaled-reg", "true",
+ "Allow combining of ScaledReg field in Address sinking">;
+defm : BoolField<"addr-sink-new-phis", "false",
+ "Allow creation of Phis in Address sinking">;
+defm : BoolField<"addr-sink-new-select", "true",
+ "Allow creation of selects in Address sinking">;
+defm : OptionalBoolField<"addr-sink-using-gep",
+ "Address sinking in CGP using GEPs">;
+defm : BoolField<"enable-andcmp-sinking", "true",
+ "Enable sinking and/cmp into branches">;
+defm : BoolField<"disable-cgp-branch-opts", "false",
+ "Disable branch optimizations in CodeGenPrepare">;
+defm : BoolField<"disable-complex-addr-modes", "false",
+ "Disables combining addressing modes with different parts in optimizeMemoryInst">;
+defm : BoolField<"disable-cgp-delete-phis", "false",
+ "Disable elimination of dead PHI nodes">;
+defm : BoolField<"disable-cgp-ext-ld-promotion", "false",
+ "Disable ext(promotable(ld)) -> promoted(ext(ld)) optimization in CodeGenPrepare">;
+defm : BoolField<"force-split-store", "false",
+ "Force store splitting no matter what the target query says">;
+defm : ValueField<"cgp-freq-ratio-to-skip-merge", "uint64_t", "2",
+ "Skip merging empty blocks if (frequency of empty block) / (frequency of destination block) is greater than this ratio">;
+defm : BoolField<"disable-cgp-gc-opts", "false",
+ "Disable GC optimizations in CodeGenPrepare">;
+defm : ValueField<"cgpp-huge-func", "unsigned", "10000",
+ "Least BB number of huge function">;
+defm : BoolField<"cgp-icmp-eq2icmp-st", "false",
+ "Enable ICMP_EQ to ICMP_S(L|G)T conversion">;
+defm : ValueField<"cgp-max-address-users-to-scan", "unsigned", "100",
+ "Max number of address users to look at">;
+defm : BoolField<"cgp-optimize-phi-types", "true",
+ "Enable converting phi types in CodeGenPrepare">;
+defm : BoolField<"disable-preheader-prot", "false",
+ "Disable protection against removing loop preheaders">;
+defm : BoolField<"disable-cgp-select2branch", "false",
+ "Disable select to branch conversion">;
+defm : BoolField<"cgp-split-large-offset-gep", "true",
+ "Enable splitting large offset of GEP">;
+defm : BoolField<"disable-cgp-store-extract", "false",
+ "Disable store(extract) optimizations in CodeGenPrepare">;
+defm : BoolField<"stress-cgp-ext-ld-promotion", "false",
+ "Stress test ext(promotable(ld)) -> promoted(ext(ld)) optimization in CodeGenPrepare">;
+defm : BoolField<"stress-cgp-store-extract", "false",
+ "Stress test store(extract) optimizations in CodeGenPrepare">;
+defm : BoolField<"cgp-type-promotion-merge", "true",
+ "Enable merging of redundant sexts when one is dominating the other">;
+defm : BoolField<"cgp-verify-bfi-updates", "false",
+ "Enable BFI update verification for CodeGenPrepare">;
+defm : BoolField<"profile-guided-section-prefix", "true",
+ "Use profile info to add section prefix for hot/cold functions">;
+defm : BoolField<"profile-unknown-in-special-section", "false",
+ "In profiling mode like sampleFDO, if a function doesn't have profile, we cannot tell the function is cold for sure because it may be a function newly added without ever being sampled. "
+ "With the flag enabled, compiler can put such profile unknown functions into a special section, so runtime system can choose to handle it in a different way than .text section, to save RAM for example">;
+
+// TargetPassConfig.cpp
+defm : BoolField<"basic-block-section-match-infer", "false",
+ "Enable matching and inference when generating basic block sections">;
+defm : BoolField<"codegen-pipeline-trigger-crash", "false",
+ "Trigger crash in codegen pipeline">;
+defm : OptionalBoolField<"debugify-and-strip-all-safe",
+ "Debugify MIR before and Strip debug after each pass except those known to be unsafe when debug info is present">;
+defm : OptionalBoolField<"debugify-check-and-strip-all-safe",
+ "Debugify MIR before, by checking and stripping the debug info after, each pass except those known to be unsafe when debug info is present">;
+defm : BoolField<"disable-atexit-based-global-dtor-lowering", "false",
+ "For MachO, disable atexit()-based global destructor lowering">;
+defm : BoolField<"disable-block-placement", "false",
+ "Disable probability-driven block placement">;
+defm : BoolField<"disable-branch-fold", "false",
+ "Disable branch folding">;
+// Disable the pass to fix unwind information. Whether the pass is included in
+// the pipeline is controlled via the target options, this option serves as
+// manual override.
+defm : BoolField<"disable-cfi-fixup", "false",
+ "Disable the CFI fixup pass">;
+defm : BoolField<"disable-cgp", "false",
+ "Disable Codegen Prepare">;
+defm : BoolField<"disable-constant-hoisting", "false",
+ "Disable ConstantHoisting">;
+defm : BoolField<"disable-copyprop", "false",
+ "Disable Copy Propagation pass">;
+defm : BoolField<"disable-early-ifcvt", "false",
+ "Disable Early If-conversion">;
+defm : BoolField<"disable-early-taildup", "false",
+ "Disable pre-register allocation tail duplication">;
+defm : BoolField<"disable-expand-reductions", "false",
+ "Disable the expand reduction intrinsics pass from running">;
+// Disable MIRProfileLoader before BlockPlacement. This is for debugging and
+// tuning purposes.
+defm : BoolField<"disable-layout-fsprofile-loader", "false",
+ "Disable MIRProfileLoader before BlockPlacement">;
+defm : BoolField<"disable-lsr", "false",
+ "Disable Loop Strength Reduction Pass">;
+defm : BoolField<"disable-machine-cse", "false",
+ "Disable Machine Common Subexpression Elimination">;
+defm : BoolField<"disable-machine-dce", "false",
+ "Disable Machine Dead Code Elimination">;
+defm : BoolField<"disable-machine-licm", "false",
+ "Disable Machine LICM">;
+defm : BoolField<"disable-machine-sink", "false",
+ "Disable Machine Sinking">;
+defm : BoolField<"disable-partial-libcall-inlining", "false",
+ "Disable Partial Libcall Inlining">;
+defm : BoolField<"disable-post-ra", "false",
+ "Disable Post Regalloc Scheduler">;
+defm : BoolField<"disable-postra-machine-licm", "false",
+ "Disable Machine LICM">;
+defm : BoolField<"disable-postra-machine-sink", "false",
+ "Disable PostRA Machine Sinking">;
+// Disable MIRProfileLoader before RegAlloc. This is for debugging and tuning
+// purpose.
+defm : BoolField<"disable-ra-fsprofile-loader", "false",
+ "Disable MIRProfileLoader before RegAlloc">;
+defm : BoolField<"disable-replace-with-vec-lib", "false",
+ "Disable replace with vector math call pass">;
+defm : BoolField<"disable-select-optimize", "true",
+ "Disable the select-optimization pass from running">;
+defm : BoolField<"disable-ssc", "false",
+ "Disable Stack Slot Coloring">;
+defm : BoolField<"disable-tail-duplicate", "false",
+ "Disable tail duplication">;
+defm : BoolField<"enable-block-placement-stats", "false",
+ "Collect probability-driven block placement stats">;
+defm : BoolField<"enable-gc-empty-basic-blocks", "false",
+ "Enable garbage-collecting empty basic blocks">;
+defm : BoolField<"enable-global-merge-func", "false",
+ "Enable global merge functions that are based on hash function">;
+defm : BoolField<"enable-implicit-null-checks", "false",
+ "Fold null checks into faulting memory operations">;
+defm : OptionalBoolField<"enable-ipra",
+ "Enable interprocedural register allocation to reduce load/store at procedure calls">;
+defm : BoolField<"enable-split-machine-functions", "false",
+ "Split out cold blocks from machine functions based on profile information">;
+// -fast-isel selects FastISel at any optimization level, and -fast-isel=0
+// disables it at -O0, where it is used unless GlobalISel is enabled.
+defm : OptionalBoolField<"fast-isel",
+ "Enable the \"fast\" instruction selector">;
+let MetaVarName = "<filename>" in
+defm : ValueField<"fs-profile-file", "StringRef", "",
+ "Flow Sensitive profile file name">;
+let MetaVarName = "<filename>" in
+defm : ValueField<"fs-remapping-file", "StringRef", "",
+ "Flow Sensitive profile remapping file name">;
+defm : OptionalBoolField<"global-isel",
+ "Enable the \"global\" instruction selector">;
+defm : EnumField<"global-isel-abort", "std::optional<GlobalISelAbortMode>", "std::nullopt",
+ "0,1,2", ["GlobalISelAbortMode::Disable", "GlobalISelAbortMode::Enable",
+ "GlobalISelAbortMode::DisableWithDiag"],
+ "Enable abort calls when \"global\" instruction selection fails to lower/select an instruction">;
+// Temporary option to allow experimenting with MachineScheduler as a post-RA
+// scheduler. Targets can "properly" enable this with
+// substitutePass(&PostRASchedulerID, &PostMachineSchedulerID).
+// Targets can return true in targetSchedulesPostRAScheduling() and
+// insert a PostRA scheduling pass wherever it wants.
+defm : BoolField<"misched-postra", "false",
+ "Run MachineScheduler post regalloc (independent of preRA sched)">;
+// FIXME: remove this after switching to NPM or GlobalISel, whichever gets there
+// first...
+defm : BoolField<"print-after-isel", "false",
+ "Print machine instrs after ISel">;
+defm : BoolField<"print-isel-input", "false",
+ "Print LLVM IR input to isel pass">;
+defm : BoolField<"print-regusage", "false",
+ "Print register usage details collected for IPRA">;
+defm : BoolField<"split-static-data", "false",
+ "Split static data sections into hot and cold sections using profile information">;
+let MetaVarName = "<pass-name>" in
+defm : ValueField<"start-after", "StringRef", "",
+ "Resume compilation after a specific pass">;
+let MetaVarName = "<pass-name>" in
+defm : ValueField<"start-before", "StringRef", "",
+ "Resume compilation before a specific pass">;
+let MetaVarName = "<pass-name>" in
+defm : ValueField<"stop-after", "StringRef", "",
+ "Stop compilation after a specific pass">;
+let MetaVarName = "<pass-name>" in
+defm : ValueField<"stop-before", "StringRef", "",
+ "Stop compilation before a specific pass">;
+defm : OptionalBoolField<"verify-machineinstrs",
+ "Verify generated machine code">;
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index 0b96c77ff33ea..24f91d05d3bad 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/CodeGenPrepare.h"
+#include "CodeGenOptions.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@@ -137,147 +138,6 @@ STATISTIC(NumDbgValueMoved, "Number of debug value instructions moved");
STATISTIC(NumSelectsExpanded, "Number of selects turned into branches");
STATISTIC(NumStoreExtractExposed, "Number of store(extractelement) exposed");
-static cl::opt<bool> DisableBranchOpts(
- "disable-cgp-branch-opts", cl::Hidden, cl::init(false),
- cl::desc("Disable branch optimizations in CodeGenPrepare"));
-
-static cl::opt<bool>
- DisableGCOpts("disable-cgp-gc-opts", cl::Hidden, cl::init(false),
- cl::desc("Disable GC optimizations in CodeGenPrepare"));
-
-static cl::opt<bool>
- DisableSelectToBranch("disable-cgp-select2branch", cl::Hidden,
- cl::init(false),
- cl::desc("Disable select to branch conversion."));
-
-static cl::opt<bool>
- AddrSinkUsingGEPs("addr-sink-using-gep", cl::Hidden, cl::init(true),
- cl::desc("Address sinking in CGP using GEPs."));
-
-static cl::opt<bool>
- EnableAndCmpSinking("enable-andcmp-sinking", cl::Hidden, cl::init(true),
- cl::desc("Enable sinking and/cmp into branches."));
-
-static cl::opt<bool> DisableStoreExtract(
- "disable-cgp-store-extract", cl::Hidden, cl::init(false),
- cl::desc("Disable store(extract) optimizations in CodeGenPrepare"));
-
-static cl::opt<bool> StressStoreExtract(
- "stress-cgp-store-extract", cl::Hidden, cl::init(false),
- cl::desc("Stress test store(extract) optimizations in CodeGenPrepare"));
-
-static cl::opt<bool> DisableExtLdPromotion(
- "disable-cgp-ext-ld-promotion", cl::Hidden, cl::init(false),
- cl::desc("Disable ext(promotable(ld)) -> promoted(ext(ld)) optimization in "
- "CodeGenPrepare"));
-
-static cl::opt<bool> StressExtLdPromotion(
- "stress-cgp-ext-ld-promotion", cl::Hidden, cl::init(false),
- cl::desc("Stress test ext(promotable(ld)) -> promoted(ext(ld)) "
- "optimization in CodeGenPrepare"));
-
-static cl::opt<bool> DisablePreheaderProtect(
- "disable-preheader-prot", cl::Hidden, cl::init(false),
- cl::desc("Disable protection against removing loop preheaders"));
-
-static cl::opt<bool> ProfileGuidedSectionPrefix(
- "profile-guided-section-prefix", cl::Hidden, cl::init(true),
- cl::desc("Use profile info to add section prefix for hot/cold functions"));
-
-static cl::opt<bool> ProfileUnknownInSpecialSection(
- "profile-unknown-in-special-section", cl::Hidden,
- cl::desc("In profiling mode like sampleFDO, if a function doesn't have "
- "profile, we cannot tell the function is cold for sure because "
- "it may be a function newly added without ever being sampled. "
- "With the flag enabled, compiler can put such profile unknown "
- "functions into a special section, so runtime system can choose "
- "to handle it in a different way than .text section, to save "
- "RAM for example. "));
-
-static cl::opt<bool> BBSectionsGuidedSectionPrefix(
- "bbsections-guided-section-prefix", cl::Hidden, cl::init(true),
- cl::desc("Use the basic-block-sections profile to determine the text "
- "section prefix for hot functions. Functions with "
- "basic-block-sections profile will be placed in `.text.hot` "
- "regardless of their FDO profile info. Other functions won't be "
- "impacted, i.e., their prefixes will be decided by FDO/sampleFDO "
- "profiles."));
-
-static cl::opt<uint64_t> FreqRatioToSkipMerge(
- "cgp-freq-ratio-to-skip-merge", cl::Hidden, cl::init(2),
- cl::desc("Skip merging empty blocks if (frequency of empty block) / "
- "(frequency of destination block) is greater than this ratio"));
-
-static cl::opt<bool> ForceSplitStore(
- "force-split-store", cl::Hidden, cl::init(false),
- cl::desc("Force store splitting no matter what the target query says."));
-
-static cl::opt<bool> EnableTypePromotionMerge(
- "cgp-type-promotion-merge", cl::Hidden,
- cl::desc("Enable merging of redundant sexts when one is dominating"
- " the other."),
- cl::init(true));
-
-static cl::opt<bool> DisableComplexAddrModes(
- "disable-complex-addr-modes", cl::Hidden, cl::init(false),
- cl::desc("Disables combining addressing modes with different parts "
- "in optimizeMemoryInst."));
-
-static cl::opt<bool>
- AddrSinkNewPhis("addr-sink-new-phis", cl::Hidden, cl::init(false),
- cl::desc("Allow creation of Phis in Address sinking."));
-
-static cl::opt<bool> AddrSinkNewSelects(
- "addr-sink-new-select", cl::Hidden, cl::init(true),
- cl::desc("Allow creation of selects in Address sinking."));
-
-static cl::opt<bool> AddrSinkCombineBaseReg(
- "addr-sink-combine-base-reg", cl::Hidden, cl::init(true),
- cl::desc("Allow combining of BaseReg field in Address sinking."));
-
-static cl::opt<bool> AddrSinkCombineBaseGV(
- "addr-sink-combine-base-gv", cl::Hidden, cl::init(true),
- cl::desc("Allow combining of BaseGV field in Address sinking."));
-
-static cl::opt<bool> AddrSinkCombineBaseOffs(
- "addr-sink-combine-base-offs", cl::Hidden, cl::init(true),
- cl::desc("Allow combining of BaseOffs field in Address sinking."));
-
-static cl::opt<bool> AddrSinkCombineScaledReg(
- "addr-sink-combine-scaled-reg", cl::Hidden, cl::init(true),
- cl::desc("Allow combining of ScaledReg field in Address sinking."));
-
-static cl::opt<bool>
- EnableGEPOffsetSplit("cgp-split-large-offset-gep", cl::Hidden,
- cl::init(true),
- cl::desc("Enable splitting large offset of GEP."));
-
-static cl::opt<bool> EnableICMP_EQToICMP_ST(
- "cgp-icmp-eq2icmp-st", cl::Hidden, cl::init(false),
- cl::desc("Enable ICMP_EQ to ICMP_S(L|G)T conversion."));
-
-static cl::opt<bool>
- VerifyBFIUpdates("cgp-verify-bfi-updates", cl::Hidden, cl::init(false),
- cl::desc("Enable BFI update verification for "
- "CodeGenPrepare."));
-
-static cl::opt<bool>
- OptimizePhiTypes("cgp-optimize-phi-types", cl::Hidden, cl::init(true),
- cl::desc("Enable converting phi types in CodeGenPrepare"));
-
-static cl::opt<unsigned>
- HugeFuncThresholdInCGPP("cgpp-huge-func", cl::init(10000), cl::Hidden,
- cl::desc("Least BB number of huge function."));
-
-static cl::opt<unsigned>
- MaxAddressUsersToScan("cgp-max-address-users-to-scan", cl::init(100),
- cl::Hidden,
- cl::desc("Max number of address users to look at"));
-
-static cl::opt<bool>
- DisableDeletePHIs("disable-cgp-delete-phis", cl::Hidden, cl::init(false),
- cl::desc("Disable elimination of dead PHI nodes."));
-
namespace {
enum ExtType {
@@ -308,6 +168,7 @@ class TypePromotionTransaction;
class CodeGenPrepare {
friend class CodeGenPrepareLegacyPass;
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
const TargetMachine *TM = nullptr;
const TargetSubtargetInfo *SubtargetInfo = nullptr;
const TargetLowering *TLI = nullptr;
@@ -588,10 +449,10 @@ bool CodeGenPrepare::_run(Function &F) {
OptSize = F.hasOptSize();
// Use the basic-block-sections profile to promote hot functions to .text.hot
// if requested.
- if (BBSectionsGuidedSectionPrefix && BBSectionsProfileReader &&
+ if (Opts.bbsections_guided_section_prefix && BBSectionsProfileReader &&
BBSectionsProfileReader->isFunctionHot(F.getName())) {
(void)F.setSectionPrefix("hot");
- } else if (ProfileGuidedSectionPrefix) {
+ } else if (Opts.profile_guided_section_prefix) {
// The hot attribute overwrites profile count based hotness while profile
// counts based hotness overwrite the cold attribute.
// This is a conservative behabvior.
@@ -604,8 +465,8 @@ bool CodeGenPrepare::_run(Function &F) {
else if (PSI->isFunctionColdInCallGraph(&F, *BFI) ||
F.hasFnAttribute(Attribute::Cold))
(void)F.setSectionPrefix("unlikely");
- else if (ProfileUnknownInSpecialSection && PSI->hasPartialSampleProfile() &&
- PSI->isFunctionHotnessUnknown(F))
+ else if (Opts.profile_unknown_in_special_section &&
+ PSI->hasPartialSampleProfile() && PSI->isFunctionHotnessUnknown(F))
(void)F.setSectionPrefix("unknown");
}
@@ -642,7 +503,7 @@ bool CodeGenPrepare::_run(Function &F) {
if (ResetLI)
resetLoopInfo();
- if (!DisableBranchOpts)
+ if (!Opts.disable_cgp_branch_opts)
EverMadeChange |= splitBranchCondition(F);
// Split some critical edges where one of the sources is an indirect branch,
@@ -664,7 +525,7 @@ bool CodeGenPrepare::_run(Function &F) {
// If we are optimzing huge function, we need to consider the build time.
// Because the basic algorithm's complex is near O(N!).
- IsHugeFunc = F.size() > HugeFuncThresholdInCGPP;
+ IsHugeFunc = F.size() > Opts.cgpp_huge_func;
bool MadeChange = true;
bool FuncIterated = false;
@@ -708,7 +569,7 @@ bool CodeGenPrepare::_run(Function &F) {
// We have iterated all the BB in the (only work for huge) function.
FuncIterated = IsHugeFunc;
- if (EnableTypePromotionMerge && !ValToSExtendedUses.empty())
+ if (Opts.cgp_type_promotion_merge && !ValToSExtendedUses.empty())
MadeChange |= mergeSExts(F);
if (!LargeOffsetGEPMap.empty())
MadeChange |= splitLargeGEPOffsets();
@@ -744,7 +605,7 @@ bool CodeGenPrepare::_run(Function &F) {
// LoopInfo is not needed anymore and ConstantFoldTerminator can break it.
LI = nullptr;
- if (!DisableBranchOpts) {
+ if (!Opts.disable_cgp_branch_opts) {
MadeChange = false;
// Use a set vector to get deterministic iteration order. The order the
// blocks are removed may affect whether or not PHI nodes in successors
@@ -785,7 +646,7 @@ bool CodeGenPrepare::_run(Function &F) {
EverMadeChange |= MadeChange;
}
- if (!DisableGCOpts) {
+ if (!Opts.disable_cgp_gc_opts) {
SmallVector<GCStatepointInst *, 2> Statepoints;
for (BasicBlock &BB : F)
for (Instruction &I : BB)
@@ -801,7 +662,7 @@ bool CodeGenPrepare::_run(Function &F) {
EverMadeChange |= placePseudoProbes(F);
#ifndef NDEBUG
- if (VerifyBFIUpdates)
+ if (Opts.cgp_verify_bfi_updates)
verifyBFIUpdates(F);
#endif
@@ -952,7 +813,7 @@ bool CodeGenPrepare::eliminateMostlyEmptyBlocks(Function &F, bool &ResetLI) {
// Note that this intentionally skips the entry block.
for (auto &Block : llvm::drop_begin(F)) {
// Delete phi nodes that could block deleting other empty blocks.
- if (!DisableDeletePHIs)
+ if (!Opts.disable_cgp_delete_phis)
MadeChange |= DeleteDeadPHIs(&Block, TLInfo, nullptr, &KnownNonDeadPHIs);
}
@@ -978,7 +839,7 @@ bool CodeGenPrepare::isMergingEmptyBlockProfitable(BasicBlock *BB,
// Loop preheaders can be good locations to spill registers. If the
// preheader is deleted and we create a critical edge, registers may be
// spilled in the loop body instead.
- if (!DisablePreheaderProtect && isPreheader &&
+ if (!Opts.disable_preheader_prot && isPreheader &&
!(BB->getSinglePredecessor() &&
BB->getSinglePredecessor()->getSingleSuccessor()))
return false;
@@ -1051,7 +912,8 @@ bool CodeGenPrepare::isMergingEmptyBlockProfitable(BasicBlock *BB,
DestBB == findDestBlockOfMergeableEmptyBlock(SameValueBB))
BBFreq += BFI->getBlockFreq(SameValueBB);
- std::optional<BlockFrequency> Limit = BBFreq.mul(FreqRatioToSkipMerge);
+ std::optional<BlockFrequency> Limit =
+ BBFreq.mul(Opts.cgp_freq_ratio_to_skip_merge);
return !Limit || PredFreq <= *Limit;
}
@@ -2013,9 +1875,9 @@ static bool sinkCmpExpression(CmpInst *Cmp, const TargetLowering &TLI,
/// comparison.
///
/// Return true if any changes are made.
-static bool foldICmpWithDominatingICmp(CmpInst *Cmp,
- const TargetLowering &TLI) {
- if (!EnableICMP_EQToICMP_ST && TLI.isEqualityCmpFoldedWithSignedCmp())
+static bool foldICmpWithDominatingICmp(CmpInst *Cmp, const TargetLowering &TLI,
+ bool EnableICmpEqToICmpSt) {
+ if (!EnableICmpEqToICmpSt && TLI.isEqualityCmpFoldedWithSignedCmp())
return false;
ICmpInst::Predicate Pred = Cmp->getPredicate();
@@ -2319,7 +2181,7 @@ bool CodeGenPrepare::optimizeCmp(CmpInst *Cmp, ModifyDT &ModifiedDT) {
if (unfoldPowerOf2Test(Cmp))
return true;
- if (foldICmpWithDominatingICmp(Cmp, *TLI))
+ if (foldICmpWithDominatingICmp(Cmp, *TLI, Opts.cgp_icmp_eq2icmp_st))
return true;
if (swapICmpOperandsToExposeCSEOpportunities(Cmp))
@@ -3159,7 +3021,7 @@ bool CodeGenPrepare::dupRetToEnableTailCallOpts(BasicBlock *BB,
// Duplicate the return into TailCallBB.
(void)FoldReturnIntoUncondBranch(RetI, BB, TailCallBB, DTU);
- assert(!VerifyBFIUpdates ||
+ assert(!Opts.cgp_verify_bfi_updates ||
BFI->getBlockFreq(BB) >= BFI->getBlockFreq(TailCallBB));
BFI->setBlockFreq(BB,
(BFI->getBlockFreq(BB) - BFI->getBlockFreq(TailCallBB)));
@@ -3891,6 +3753,7 @@ class AddressingModeMatcher {
ProfileSummaryInfo *PSI;
BlockFrequencyInfo *BFI;
+ const CodeGenOptions &Opts;
AddressingModeMatcher(
SmallVectorImpl<Instruction *> &AMI, const TargetLowering &TLI,
@@ -3900,12 +3763,13 @@ class AddressingModeMatcher {
const SetOfInstrs &InsertedInsts, InstrToOrigTy &PromotedInsts,
TypePromotionTransaction &TPT,
std::pair<AssertingVH<GetElementPtrInst>, int64_t> &LargeOffsetGEP,
- bool OptSize, ProfileSummaryInfo *PSI, BlockFrequencyInfo *BFI)
- : AddrModeInsts(AMI), TLI(TLI), TRI(TRI),
- DL(MI->getDataLayout()), LI(LI), getDTFn(getDTFn),
- AccessTy(AT), AddrSpace(AS), MemoryInst(MI), AddrMode(AM),
- InsertedInsts(InsertedInsts), PromotedInsts(PromotedInsts), TPT(TPT),
- LargeOffsetGEP(LargeOffsetGEP), OptSize(OptSize), PSI(PSI), BFI(BFI) {
+ bool OptSize, ProfileSummaryInfo *PSI, BlockFrequencyInfo *BFI,
+ const CodeGenOptions &Opts)
+ : AddrModeInsts(AMI), TLI(TLI), TRI(TRI), DL(MI->getDataLayout()), LI(LI),
+ getDTFn(getDTFn), AccessTy(AT), AddrSpace(AS), MemoryInst(MI),
+ AddrMode(AM), InsertedInsts(InsertedInsts),
+ PromotedInsts(PromotedInsts), TPT(TPT), LargeOffsetGEP(LargeOffsetGEP),
+ OptSize(OptSize), PSI(PSI), BFI(BFI), Opts(Opts) {
IgnoreProfitability = false;
}
@@ -3925,13 +3789,14 @@ class AddressingModeMatcher {
const TargetRegisterInfo &TRI, const SetOfInstrs &InsertedInsts,
InstrToOrigTy &PromotedInsts, TypePromotionTransaction &TPT,
std::pair<AssertingVH<GetElementPtrInst>, int64_t> &LargeOffsetGEP,
- bool OptSize, ProfileSummaryInfo *PSI, BlockFrequencyInfo *BFI) {
+ bool OptSize, ProfileSummaryInfo *PSI, BlockFrequencyInfo *BFI,
+ const CodeGenOptions &Opts) {
ExtAddrMode Result;
- bool Success = AddressingModeMatcher(AddrModeInsts, TLI, TRI, LI, getDTFn,
- AccessTy, AS, MemoryInst, Result,
- InsertedInsts, PromotedInsts, TPT,
- LargeOffsetGEP, OptSize, PSI, BFI)
+ bool Success = AddressingModeMatcher(
+ AddrModeInsts, TLI, TRI, LI, getDTFn, AccessTy, AS,
+ MemoryInst, Result, InsertedInsts, PromotedInsts, TPT,
+ LargeOffsetGEP, OptSize, PSI, BFI, Opts)
.matchAddr(V, 0);
(void)Success;
assert(Success && "Couldn't select *anything*?");
@@ -4171,6 +4036,7 @@ class AddressingModeCombiner {
Type *CommonType = nullptr;
const DataLayout &DL;
+ const CodeGenOptions &Opts;
/// Original Address.
Value *Original;
@@ -4179,8 +4045,9 @@ class AddressingModeCombiner {
Value *CommonValue = nullptr;
public:
- AddressingModeCombiner(const DataLayout &DL, Value *OriginalValue)
- : DL(DL), Original(OriginalValue) {}
+ AddressingModeCombiner(const DataLayout &DL, const CodeGenOptions &Opts,
+ Value *OriginalValue)
+ : DL(DL), Opts(Opts), Original(OriginalValue) {}
~AddressingModeCombiner() { eraseCommonValueIfDead(); }
@@ -4352,14 +4219,14 @@ class AddressingModeCombiner {
// Second Step, fill new nodes by merged values and simplify if possible.
FillPlaceholders(Map, TraverseOrder, ST);
- if (!AddrSinkNewSelects && ST.countNewSelectNodes() > 0) {
+ if (!Opts.addr_sink_new_select && ST.countNewSelectNodes() > 0) {
ST.destroyNewNodes(CommonType);
return nullptr;
}
// Now we'd like to match New Phi nodes to existed ones.
unsigned PhiNotMatchedCount = 0;
- if (!MatchPhiSet(ST, AddrSinkNewPhis, PhiNotMatchedCount)) {
+ if (!MatchPhiSet(ST, Opts.addr_sink_new_phis, PhiNotMatchedCount)) {
ST.destroyNewNodes(CommonType);
return nullptr;
}
@@ -4552,19 +4419,19 @@ class AddressingModeCombiner {
}
bool addrModeCombiningAllowed() {
- if (DisableComplexAddrModes)
+ if (Opts.disable_complex_addr_modes)
return false;
switch (DifferentField) {
default:
return false;
case ExtAddrMode::BaseRegField:
- return AddrSinkCombineBaseReg;
+ return Opts.addr_sink_combine_base_reg;
case ExtAddrMode::BaseGVField:
- return AddrSinkCombineBaseGV;
+ return Opts.addr_sink_combine_base_gv;
case ExtAddrMode::BaseOffsField:
- return AddrSinkCombineBaseOffs;
+ return Opts.addr_sink_combine_base_offs;
case ExtAddrMode::ScaledRegField:
- return AddrSinkCombineScaledReg;
+ return Opts.addr_sink_combine_scaled_reg;
}
}
};
@@ -5332,26 +5199,26 @@ bool AddressingModeMatcher::matchOperationAddr(User *AddrInst, unsigned Opcode,
}
AddrMode.BaseOffs -= ConstantOffset;
- if (EnableGEPOffsetSplit && isa<GetElementPtrInst>(AddrInst) &&
+ if (Opts.cgp_split_large_offset_gep && isa<GetElementPtrInst>(AddrInst) &&
TLI.shouldConsiderGEPOffsetSplit() && Depth == 0 &&
ConstantOffset > 0) {
- // Record GEPs with non-zero offsets as candidates for splitting in
- // the event that the offset cannot fit into the r+i addressing mode.
- // Simple and common case that only one GEP is used in calculating the
- // address for the memory access.
- Value *Base = AddrInst->getOperand(0);
- auto *BaseI = dyn_cast<Instruction>(Base);
- auto *GEP = cast<GetElementPtrInst>(AddrInst);
- if (isa<Argument>(Base) || isa<GlobalValue>(Base) ||
- (BaseI && !isa<CastInst>(BaseI) &&
- !isa<GetElementPtrInst>(BaseI))) {
- // Make sure the parent block allows inserting non-PHI instructions
- // before the terminator.
- BasicBlock *Parent = BaseI ? BaseI->getParent()
- : &GEP->getFunction()->getEntryBlock();
- if (!Parent->getTerminator()->isEHPad())
+ // Record GEPs with non-zero offsets as candidates for splitting in
+ // the event that the offset cannot fit into the r+i addressing mode.
+ // Simple and common case that only one GEP is used in calculating the
+ // address for the memory access.
+ Value *Base = AddrInst->getOperand(0);
+ auto *BaseI = dyn_cast<Instruction>(Base);
+ auto *GEP = cast<GetElementPtrInst>(AddrInst);
+ if (isa<Argument>(Base) || isa<GlobalValue>(Base) ||
+ (BaseI && !isa<CastInst>(BaseI) &&
+ !isa<GetElementPtrInst>(BaseI))) {
+ // Make sure the parent block allows inserting non-PHI instructions
+ // before the terminator.
+ BasicBlock *Parent =
+ BaseI ? BaseI->getParent() : &GEP->getFunction()->getEntryBlock();
+ if (!Parent->getTerminator()->isEHPad())
LargeOffsetGEP = std::make_pair(GEP, ConstantOffset);
- }
+ }
}
return false;
@@ -5594,7 +5461,7 @@ static bool FindAllMemoryUses(
Instruction *I, SmallVectorImpl<std::pair<Use *, Type *>> &MemoryUses,
SmallPtrSetImpl<Instruction *> &ConsideredInsts, const TargetLowering &TLI,
const TargetRegisterInfo &TRI, bool OptSize, ProfileSummaryInfo *PSI,
- BlockFrequencyInfo *BFI, unsigned &SeenInsts) {
+ BlockFrequencyInfo *BFI, unsigned &SeenInsts, unsigned MaxUsersToScan) {
// If we already considered this instruction, we're done.
if (!ConsideredInsts.insert(I).second)
return false;
@@ -5607,7 +5474,7 @@ static bool FindAllMemoryUses(
for (Use &U : I->uses()) {
// Conservatively return true if we're seeing a large number or a deep chain
// of users. This avoids excessive compilation times in pathological cases.
- if (SeenInsts++ >= MaxAddressUsersToScan)
+ if (SeenInsts++ >= MaxUsersToScan)
return true;
Instruction *UserI = cast<Instruction>(U.getUser());
@@ -5669,7 +5536,7 @@ static bool FindAllMemoryUses(
}
if (FindAllMemoryUses(UserI, MemoryUses, ConsideredInsts, TLI, TRI, OptSize,
- PSI, BFI, SeenInsts))
+ PSI, BFI, SeenInsts, MaxUsersToScan))
return true;
}
@@ -5679,14 +5546,13 @@ static bool FindAllMemoryUses(
static bool FindAllMemoryUses(
Instruction *I, SmallVectorImpl<std::pair<Use *, Type *>> &MemoryUses,
const TargetLowering &TLI, const TargetRegisterInfo &TRI, bool OptSize,
- ProfileSummaryInfo *PSI, BlockFrequencyInfo *BFI) {
+ ProfileSummaryInfo *PSI, BlockFrequencyInfo *BFI, unsigned MaxUsersToScan) {
unsigned SeenInsts = 0;
SmallPtrSet<Instruction *, 16> ConsideredInsts;
return FindAllMemoryUses(I, MemoryUses, ConsideredInsts, TLI, TRI, OptSize,
- PSI, BFI, SeenInsts);
+ PSI, BFI, SeenInsts, MaxUsersToScan);
}
-
/// Return true if Val is already known to be live at the use site that we're
/// folding it into. If so, there is no cost to include it in the addressing
/// mode. KnownLive1 and KnownLive2 are two values that we know are live at the
@@ -5769,7 +5635,8 @@ bool AddressingModeMatcher::isProfitableToFoldIntoAddressingMode(
// for another (at worst.) In this context, folding an addressing mode into
// the use is just a particularly nice way of sinking it.
SmallVector<std::pair<Use *, Type *>, 16> MemoryUses;
- if (FindAllMemoryUses(I, MemoryUses, TLI, TRI, OptSize, PSI, BFI))
+ if (FindAllMemoryUses(I, MemoryUses, TLI, TRI, OptSize, PSI, BFI,
+ Opts.cgp_max_address_users_to_scan))
return false; // Has a non-memory, non-foldable use!
// Now that we know that all uses of this instruction are part of a chain of
@@ -5799,7 +5666,7 @@ bool AddressingModeMatcher::isProfitableToFoldIntoAddressingMode(
AddressingModeMatcher Matcher(MatchedAddrModeInsts, TLI, TRI, LI, getDTFn,
AddressAccessTy, AS, UserI, Result,
InsertedInsts, PromotedInsts, TPT,
- LargeOffsetGEP, OptSize, PSI, BFI);
+ LargeOffsetGEP, OptSize, PSI, BFI, Opts);
Matcher.IgnoreProfitability = true;
bool Success = Matcher.matchAddr(Address, 0);
(void)Success;
@@ -5891,7 +5758,7 @@ bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr,
// the graph are compatible.
bool PhiOrSelectSeen = false;
SmallVector<Instruction *, 16> AddrModeInsts;
- AddressingModeCombiner AddrModes(*DL, Addr);
+ AddressingModeCombiner AddrModes(*DL, Opts, Addr);
TypePromotionTransaction TPT(RemovedInsts);
TypePromotionTransaction::ConstRestorationPt LastKnownGood =
TPT.getRestorationPoint();
@@ -5937,7 +5804,7 @@ bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr,
ExtAddrMode NewAddrMode = AddressingModeMatcher::Match(
V, AccessTy, AddrSpace, MemoryInst, AddrModeInsts, *TLI, *LI, getDTFn,
*TRI, InsertedInsts, PromotedInsts, TPT, LargeOffsetGEP, OptSize, PSI,
- BFI);
+ BFI, Opts);
GetElementPtrInst *GEP = LargeOffsetGEP.first;
if (GEP && !NewGEPBases.count(GEP)) {
@@ -6021,8 +5888,9 @@ bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr,
} else
SunkAddr = Builder.CreatePointerCast(SunkAddr, Addr->getType());
}
- } else if (AddrSinkUsingGEPs || (!AddrSinkUsingGEPs.getNumOccurrences() &&
- SubtargetInfo->addrSinkUsingGEPs())) {
+ } else if (valueOr(Opts.addr_sink_using_gep, true) ||
+ (Opts.addr_sink_using_gep == BoolOrDefault::Default &&
+ SubtargetInfo->addrSinkUsingGEPs())) {
// By default, we use the GEP-based method when AA is used later. This
// prevents new inttoptr/ptrtoint pairs from degrading AA capabilities.
LLVM_DEBUG(dbgs() << "CGP: SINKING nonlocal addrmode: " << AddrMode
@@ -6720,7 +6588,7 @@ bool CodeGenPrepare::tryToPromoteExts(
// this check inside the for loop is to catch the case where an extension
// is directly fed by a load because in such case the extension can be moved
// up without any promotion on its operands.
- if (!TLI->enableExtLdPromotion() || DisableExtLdPromotion)
+ if (!TLI->enableExtLdPromotion() || Opts.disable_cgp_ext_ld_promotion)
return false;
// Get the action to perform the promotion.
@@ -6758,7 +6626,7 @@ bool CodeGenPrepare::tryToPromoteExts(
// conservatively ceiling it to 0.
TotalCreatedInstsCost =
std::max((long long)0, (TotalCreatedInstsCost - ExtCost));
- if (!StressExtLdPromotion &&
+ if (!Opts.stress_cgp_ext_ld_promotion &&
(TotalCreatedInstsCost > 1 ||
!isPromotedInstructionLegal(*TLI, *DL, PromotedVal) ||
(ExtCost == 0 && NewExts.size() > 1))) {
@@ -6779,7 +6647,8 @@ bool CodeGenPrepare::tryToPromoteExts(
// If we have reached to a load, we need this extra profitability check
// as it could potentially be merged into an ext(load).
if (isa<LoadInst>(ExtOperand) &&
- !(StressExtLdPromotion || NewCreatedInstsCost <= ExtCost ||
+ !(Opts.stress_cgp_ext_ld_promotion ||
+ NewCreatedInstsCost <= ExtCost ||
(ExtOperand->hasOneUse() || hasSameExtUse(ExtOperand, *TLI))))
continue;
@@ -7142,7 +7011,7 @@ bool CodeGenPrepare::optimizePhiType(
}
bool CodeGenPrepare::optimizePhiTypes(Function &F) {
- if (!OptimizePhiTypes)
+ if (!Opts.cgp_optimize_phi_types)
return false;
bool Changed = false;
@@ -7740,7 +7609,7 @@ bool CodeGenPrepare::optimizeFunnelShift(IntrinsicInst *Fsh) {
/// If we have a SelectInst that will likely profit from branch prediction,
/// turn it into a branch.
bool CodeGenPrepare::optimizeSelectInst(SelectInst *SI) {
- if (DisableSelectToBranch)
+ if (Opts.disable_cgp_select2branch)
return false;
// If the SelectOptimize pass is enabled, selects have already been optimized.
@@ -8206,6 +8075,8 @@ class VectorPromoteHelper {
/// Cost of combining a store and an extract.
unsigned StoreExtractCombineCost;
+ bool StressStoreExtract;
+
/// Instruction that will be combined with the transition.
Instruction *CombineInst = nullptr;
@@ -8371,9 +8242,10 @@ class VectorPromoteHelper {
public:
VectorPromoteHelper(const DataLayout &DL, const TargetLowering &TLI,
const TargetTransformInfo &TTI, Instruction *Transition,
- unsigned CombineCost)
+ unsigned CombineCost, bool StressStoreExtract)
: DL(DL), TLI(TLI), TTI(TTI), Transition(Transition),
- StoreExtractCombineCost(CombineCost) {
+ StoreExtractCombineCost(CombineCost),
+ StressStoreExtract(StressStoreExtract) {
assert(Transition && "Do not know how to promote null");
}
@@ -8494,8 +8366,8 @@ void VectorPromoteHelper::promoteImpl(Instruction *ToBePromoted) {
/// has this feature and this is profitable.
bool CodeGenPrepare::optimizeExtractElementInst(Instruction *Inst) {
unsigned CombineCost = std::numeric_limits<unsigned>::max();
- if (DisableStoreExtract ||
- (!StressStoreExtract &&
+ if (Opts.disable_cgp_store_extract ||
+ (!Opts.stress_cgp_store_extract &&
!TLI->canCombineStoreAndExtract(Inst->getOperand(0)->getType(),
Inst->getOperand(1), CombineCost)))
return false;
@@ -8509,7 +8381,8 @@ bool CodeGenPrepare::optimizeExtractElementInst(Instruction *Inst) {
// we do not do that for now.
BasicBlock *Parent = Inst->getParent();
LLVM_DEBUG(dbgs() << "Found an interesting transition: " << *Inst << '\n');
- VectorPromoteHelper VPH(*DL, *TLI, *TTI, Inst, CombineCost);
+ VectorPromoteHelper VPH(*DL, *TLI, *TTI, Inst, CombineCost,
+ Opts.stress_cgp_store_extract);
// If the transition has more than one use, assume this is not going to be
// beneficial.
while (Inst->hasOneUse()) {
@@ -8578,7 +8451,8 @@ bool CodeGenPrepare::optimizeExtractElementInst(Instruction *Inst) {
/// multiple BBs. The logic in DAG Combine is kept to catch case generated
/// during code expansion.
static bool splitMergedValStore(StoreInst &SI, const DataLayout &DL,
- const TargetLowering &TLI) {
+ const TargetLowering &TLI,
+ bool ForceSplitStore) {
// Handle simple but common cases only.
Type *StoreType = SI.getValueOperand()->getType();
@@ -9002,7 +8876,7 @@ bool CodeGenPrepare::optimizeInst(Instruction *I, ModifyDT &ModifiedDT) {
}
if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
- if (splitMergedValStore(*SI, *DL, *TLI))
+ if (splitMergedValStore(*SI, *DL, *TLI, Opts.force_split_store))
return true;
SI->setMetadata(LLVMContext::MD_invariant_group, nullptr);
unsigned AS = SI->getPointerAddressSpace();
@@ -9023,7 +8897,8 @@ bool CodeGenPrepare::optimizeInst(Instruction *I, ModifyDT &ModifiedDT) {
BinaryOperator *BinOp = dyn_cast<BinaryOperator>(I);
- if (BinOp && BinOp->getOpcode() == Instruction::And && EnableAndCmpSinking &&
+ if (BinOp && BinOp->getOpcode() == Instruction::And &&
+ Opts.enable_andcmp_sinking &&
sinkAndCmp0Expression(BinOp, *TLI, InsertedInsts))
return true;
diff --git a/llvm/lib/CodeGen/RegisterUsageInfo.cpp b/llvm/lib/CodeGen/RegisterUsageInfo.cpp
index d139bd430fb20..bf2ee0fc57b83 100644
--- a/llvm/lib/CodeGen/RegisterUsageInfo.cpp
+++ b/llvm/lib/CodeGen/RegisterUsageInfo.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/RegisterUsageInfo.h"
+#include "CodeGenOptions.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
@@ -22,7 +23,6 @@
#include "llvm/IR/PassManager.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
-#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include <cstdint>
@@ -31,9 +31,6 @@
using namespace llvm;
-// Defined in TargetPassConfig.cpp
-extern cl::opt<bool> PrintRegUsage;
-
INITIALIZE_PASS(PhysicalRegisterUsageInfoWrapperLegacy, "reg-usage-info",
"Register Usage Information Storage", false, true)
@@ -49,7 +46,7 @@ bool PhysicalRegisterUsageInfo::doInitialization(Module &M) {
}
bool PhysicalRegisterUsageInfo::doFinalization(Module &M) {
- if (PrintRegUsage)
+ if (CodeGenOptions::Global.print_regusage)
print(errs());
RegMasks.shrink_and_clear();
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp
index 9683d988e8084..d4d0b90591c27 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -12,6 +12,7 @@
//===---------------------------------------------------------------------===//
#include "llvm/CodeGen/TargetPassConfig.h"
+#include "CodeGenOptions.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -57,51 +58,6 @@
using namespace llvm;
-static cl::opt<bool>
- EnableIPRA("enable-ipra", cl::init(false), cl::Hidden,
- cl::desc("Enable interprocedural register allocation "
- "to reduce load/store at procedure calls."));
-static cl::opt<bool> DisablePostRASched("disable-post-ra", cl::Hidden,
- cl::desc("Disable Post Regalloc Scheduler"));
-static cl::opt<bool> DisableBranchFold("disable-branch-fold", cl::Hidden,
- cl::desc("Disable branch folding"));
-static cl::opt<bool> DisableTailDuplicate("disable-tail-duplicate", cl::Hidden,
- cl::desc("Disable tail duplication"));
-static cl::opt<bool> DisableEarlyTailDup("disable-early-taildup", cl::Hidden,
- cl::desc("Disable pre-register allocation tail duplication"));
-static cl::opt<bool> DisableBlockPlacement("disable-block-placement",
- cl::Hidden, cl::desc("Disable probability-driven block placement"));
-static cl::opt<bool> EnableBlockPlacementStats("enable-block-placement-stats",
- cl::Hidden, cl::desc("Collect probability-driven block placement stats"));
-static cl::opt<bool> DisableSSC("disable-ssc", cl::Hidden,
- cl::desc("Disable Stack Slot Coloring"));
-static cl::opt<bool> DisableMachineDCE("disable-machine-dce", cl::Hidden,
- cl::desc("Disable Machine Dead Code Elimination"));
-static cl::opt<bool> DisableEarlyIfConversion("disable-early-ifcvt", cl::Hidden,
- cl::desc("Disable Early If-conversion"));
-static cl::opt<bool> DisableMachineLICM("disable-machine-licm", cl::Hidden,
- cl::desc("Disable Machine LICM"));
-static cl::opt<bool> DisableMachineCSE("disable-machine-cse", cl::Hidden,
- cl::desc("Disable Machine Common Subexpression Elimination"));
-static cl::opt<bool> DisablePostRAMachineLICM("disable-postra-machine-licm",
- cl::Hidden,
- cl::desc("Disable Machine LICM"));
-static cl::opt<bool> DisableMachineSink("disable-machine-sink", cl::Hidden,
- cl::desc("Disable Machine Sinking"));
-static cl::opt<bool> DisablePostRAMachineSink("disable-postra-machine-sink",
- cl::Hidden,
- cl::desc("Disable PostRA Machine Sinking"));
-static cl::opt<bool> DisableLSR("disable-lsr", cl::Hidden,
- cl::desc("Disable Loop Strength Reduction Pass"));
-static cl::opt<bool> DisableConstantHoisting("disable-constant-hoisting",
- cl::Hidden, cl::desc("Disable ConstantHoisting"));
-static cl::opt<bool> DisableCGP("disable-cgp", cl::Hidden,
- cl::desc("Disable Codegen Prepare"));
-
-static cl::opt<bool>
- TriggerCrash("codegen-pipeline-trigger-crash", cl::init(false), cl::Hidden,
- cl::desc("Trigger crash in codegen pipeline"));
-
namespace {
class TriggerCrashFunctionLegacyPass : public FunctionPass {
public:
@@ -117,37 +73,6 @@ class TriggerCrashFunctionLegacyPass : public FunctionPass {
char TriggerCrashFunctionLegacyPass::ID = 0;
-static cl::opt<bool> DisableCopyProp("disable-copyprop", cl::Hidden,
- cl::desc("Disable Copy Propagation pass"));
-static cl::opt<bool> DisablePartialLibcallInlining("disable-partial-libcall-inlining",
- cl::Hidden, cl::desc("Disable Partial Libcall Inlining"));
-static cl::opt<bool> DisableAtExitBasedGlobalDtorLowering(
- "disable-atexit-based-global-dtor-lowering", cl::Hidden,
- cl::desc("For MachO, disable atexit()-based global destructor lowering"));
-static cl::opt<bool> EnableImplicitNullChecks(
- "enable-implicit-null-checks",
- cl::desc("Fold null checks into faulting memory operations"),
- cl::init(false), cl::Hidden);
-static cl::opt<bool>
- PrintISelInput("print-isel-input", cl::Hidden,
- cl::desc("Print LLVM IR input to isel pass"));
-cl::opt<bool>
- PrintRegUsage("print-regusage", cl::Hidden,
- cl::desc("Print register usage details collected for IPRA"));
-static cl::opt<cl::boolOrDefault>
- VerifyMachineCode("verify-machineinstrs", cl::Hidden,
- cl::desc("Verify generated machine code"));
-static cl::opt<cl::boolOrDefault>
- DebugifyAndStripAll("debugify-and-strip-all-safe", cl::Hidden,
- cl::desc("Debugify MIR before and Strip debug after "
- "each pass except those known to be unsafe "
- "when debug info is present"));
-static cl::opt<cl::boolOrDefault> DebugifyCheckAndStripAll(
- "debugify-check-and-strip-all-safe", cl::Hidden,
- cl::desc(
- "Debugify MIR before, by checking and stripping the debug info after, "
- "each pass except those known to be unsafe when debug info is "
- "present"));
// Enable or disable the MachineOutliner.
static cl::opt<RunOutliner> EnableMachineOutliner(
"enable-machine-outliner", cl::desc("Enable the machine outliner"),
@@ -164,73 +89,6 @@ static cl::opt<RunOutliner> EnableMachineOutliner(
clEnumValN(RunOutliner::NeverOutline, "never", "Disable all outlining"),
// Sentinel value for unspecified option.
clEnumValN(RunOutliner::AlwaysOutline, "", "")));
-static cl::opt<bool> EnableGlobalMergeFunc(
- "enable-global-merge-func", cl::Hidden,
- cl::desc("Enable global merge functions that are based on hash function"));
-// Disable the pass to fix unwind information. Whether the pass is included in
-// the pipeline is controlled via the target options, this option serves as
-// manual override.
-static cl::opt<bool> DisableCFIFixup("disable-cfi-fixup", cl::Hidden,
- cl::desc("Disable the CFI fixup pass"));
-// Enable or disable FastISel. Both options are needed, because
-// FastISel is enabled by default with -fast, and we wish to be
-// able to enable or disable fast-isel independently from -O0.
-static cl::opt<cl::boolOrDefault>
-EnableFastISelOption("fast-isel", cl::Hidden,
- cl::desc("Enable the \"fast\" instruction selector"));
-
-static cl::opt<cl::boolOrDefault> EnableGlobalISelOption(
- "global-isel", cl::Hidden,
- cl::desc("Enable the \"global\" instruction selector"));
-
-// FIXME: remove this after switching to NPM or GlobalISel, whichever gets there
-// first...
-static cl::opt<bool>
- PrintAfterISel("print-after-isel", cl::init(false), cl::Hidden,
- cl::desc("Print machine instrs after ISel"));
-
-static cl::opt<GlobalISelAbortMode> EnableGlobalISelAbort(
- "global-isel-abort", cl::Hidden,
- cl::desc("Enable abort calls when \"global\" instruction selection "
- "fails to lower/select an instruction"),
- cl::values(
- clEnumValN(GlobalISelAbortMode::Disable, "0", "Disable the abort"),
- clEnumValN(GlobalISelAbortMode::Enable, "1", "Enable the abort"),
- clEnumValN(GlobalISelAbortMode::DisableWithDiag, "2",
- "Disable the abort but emit a diagnostic on failure")));
-
-// Disable MIRProfileLoader before RegAlloc. This is for for debugging and
-// tuning purpose.
-static cl::opt<bool> DisableRAFSProfileLoader(
- "disable-ra-fsprofile-loader", cl::init(false), cl::Hidden,
- cl::desc("Disable MIRProfileLoader before RegAlloc"));
-// Disable MIRProfileLoader before BloackPlacement. This is for for debugging
-// and tuning purpose.
-static cl::opt<bool> DisableLayoutFSProfileLoader(
- "disable-layout-fsprofile-loader", cl::init(false), cl::Hidden,
- cl::desc("Disable MIRProfileLoader before BlockPlacement"));
-// Specify FSProfile file name.
-static cl::opt<std::string>
- FSProfileFile("fs-profile-file", cl::init(""), cl::value_desc("filename"),
- cl::desc("Flow Sensitive profile file name."), cl::Hidden);
-// Specify Remapping file for FSProfile.
-static cl::opt<std::string> FSRemappingFile(
- "fs-remapping-file", cl::init(""), cl::value_desc("filename"),
- cl::desc("Flow Sensitive profile remapping file name."), cl::Hidden);
-
-// Temporary option to allow experimenting with MachineScheduler as a post-RA
-// scheduler. Targets can "properly" enable this with
-// substitutePass(&PostRASchedulerID, &PostMachineSchedulerID).
-// Targets can return true in targetSchedulesPostRAScheduling() and
-// insert a PostRA scheduling pass wherever it wants.
-static cl::opt<bool> MISchedPostRA(
- "misched-postra", cl::Hidden,
- cl::desc(
- "Run MachineScheduler post regalloc (independent of preRA sched)"));
-
-static cl::opt<bool> DisableReplaceWithVecLib(
- "disable-replace-with-vec-lib", cl::Hidden,
- cl::desc("Disable replace with vector math call pass"));
/// Option names for limiting the codegen pipeline.
/// Those are used in error reporting and we didn't want
@@ -240,59 +98,6 @@ static const char StartBeforeOptName[] = "start-before";
static const char StopAfterOptName[] = "stop-after";
static const char StopBeforeOptName[] = "stop-before";
-static cl::opt<std::string>
- StartAfterOpt(StringRef(StartAfterOptName),
- cl::desc("Resume compilation after a specific pass"),
- cl::value_desc("pass-name"), cl::init(""), cl::Hidden);
-
-static cl::opt<std::string>
- StartBeforeOpt(StringRef(StartBeforeOptName),
- cl::desc("Resume compilation before a specific pass"),
- cl::value_desc("pass-name"), cl::init(""), cl::Hidden);
-
-static cl::opt<std::string>
- StopAfterOpt(StringRef(StopAfterOptName),
- cl::desc("Stop compilation after a specific pass"),
- cl::value_desc("pass-name"), cl::init(""), cl::Hidden);
-
-static cl::opt<std::string>
- StopBeforeOpt(StringRef(StopBeforeOptName),
- cl::desc("Stop compilation before a specific pass"),
- cl::value_desc("pass-name"), cl::init(""), cl::Hidden);
-
-/// Enable the machine function splitter pass.
-static cl::opt<bool> EnableMachineFunctionSplitter(
- "enable-split-machine-functions", cl::Hidden,
- cl::desc("Split out cold blocks from machine functions based on profile "
- "information."));
-
-/// Disable the expand reductions pass for testing.
-static cl::opt<bool> DisableExpandReductions(
- "disable-expand-reductions", cl::init(false), cl::Hidden,
- cl::desc("Disable the expand reduction intrinsics pass from running"));
-
-/// Disable the select optimization pass.
-static cl::opt<bool> DisableSelectOptimize(
- "disable-select-optimize", cl::init(true), cl::Hidden,
- cl::desc("Disable the select-optimization pass from running"));
-
-/// Enable garbage-collecting empty basic blocks.
-static cl::opt<bool> EnableGCEmptyBlocks(
- "enable-gc-empty-basic-blocks", cl::init(false), cl::Hidden,
- cl::desc("Enable garbage-collecting empty basic blocks"));
-
-static cl::opt<bool>
- SplitStaticData("split-static-data", cl::Hidden, cl::init(false),
- cl::desc("Split static data sections into hot and cold "
- "sections using profile information"));
-
-/// Enable matching and inference when using propeller.
-static cl::opt<bool> BasicBlockSectionMatchInfer(
- "basic-block-section-match-infer",
- cl::desc(
- "Enable matching and inference when generating basic block sections"),
- cl::init(false));
-
/// Allow standard passes to be disabled by command line options. This supports
/// simple binary flags that either suppress the pass or do nothing.
/// i.e. -disable-mypass=false has no effect.
@@ -318,47 +123,48 @@ static IdentifyingPassPtr applyDisable(IdentifyingPassPtr PassID,
/// on where in the pipeline that pass is added.
static IdentifyingPassPtr overridePass(AnalysisID StandardID,
IdentifyingPassPtr TargetID) {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
if (StandardID == &PostRASchedulerID)
- return applyDisable(TargetID, DisablePostRASched);
+ return applyDisable(TargetID, Opts.disable_post_ra);
if (StandardID == &BranchFolderPassID)
- return applyDisable(TargetID, DisableBranchFold);
+ return applyDisable(TargetID, Opts.disable_branch_fold);
if (StandardID == &TailDuplicateLegacyID)
- return applyDisable(TargetID, DisableTailDuplicate);
+ return applyDisable(TargetID, Opts.disable_tail_duplicate);
if (StandardID == &EarlyTailDuplicateLegacyID)
- return applyDisable(TargetID, DisableEarlyTailDup);
+ return applyDisable(TargetID, Opts.disable_early_taildup);
if (StandardID == &MachineBlockPlacementID)
- return applyDisable(TargetID, DisableBlockPlacement);
+ return applyDisable(TargetID, Opts.disable_block_placement);
if (StandardID == &StackSlotColoringID)
- return applyDisable(TargetID, DisableSSC);
+ return applyDisable(TargetID, Opts.disable_ssc);
if (StandardID == &DeadMachineInstructionElimID)
- return applyDisable(TargetID, DisableMachineDCE);
+ return applyDisable(TargetID, Opts.disable_machine_dce);
if (StandardID == &EarlyIfConverterLegacyID)
- return applyDisable(TargetID, DisableEarlyIfConversion);
+ return applyDisable(TargetID, Opts.disable_early_ifcvt);
if (StandardID == &EarlyMachineLICMID)
- return applyDisable(TargetID, DisableMachineLICM);
+ return applyDisable(TargetID, Opts.disable_machine_licm);
if (StandardID == &MachineCSELegacyID)
- return applyDisable(TargetID, DisableMachineCSE);
+ return applyDisable(TargetID, Opts.disable_machine_cse);
if (StandardID == &MachineLICMID)
- return applyDisable(TargetID, DisablePostRAMachineLICM);
+ return applyDisable(TargetID, Opts.disable_postra_machine_licm);
if (StandardID == &MachineSinkingLegacyID)
- return applyDisable(TargetID, DisableMachineSink);
+ return applyDisable(TargetID, Opts.disable_machine_sink);
if (StandardID == &PostRAMachineSinkingID)
- return applyDisable(TargetID, DisablePostRAMachineSink);
+ return applyDisable(TargetID, Opts.disable_postra_machine_sink);
if (StandardID == &MachineCopyPropagationID)
- return applyDisable(TargetID, DisableCopyProp);
+ return applyDisable(TargetID, Opts.disable_copyprop);
return TargetID;
}
@@ -366,8 +172,9 @@ static IdentifyingPassPtr overridePass(AnalysisID StandardID,
// Find the FSProfile file name. The internal option takes the precedence
// before getting from TargetMachine.
static std::string getFSProfileFile(const TargetMachine *TM) {
- if (!FSProfileFile.empty())
- return FSProfileFile.getValue();
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
+ if (!Opts.fs_profile_file.empty())
+ return Opts.fs_profile_file.str();
const std::optional<PGOOptions> &PGOOpt = TM->getPGOOption();
if (PGOOpt == std::nullopt || PGOOpt->Action != PGOOptions::SampleUse)
return std::string();
@@ -377,8 +184,9 @@ static std::string getFSProfileFile(const TargetMachine *TM) {
// Find the Profile remapping file name. The internal option takes the
// precedence before getting from TargetMachine.
static std::string getFSRemappingFile(const TargetMachine *TM) {
- if (!FSRemappingFile.empty())
- return FSRemappingFile.getValue();
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
+ if (!Opts.fs_remapping_file.empty())
+ return Opts.fs_remapping_file.str();
const std::optional<PGOOptions> &PGOOpt = TM->getPGOOption();
if (PGOOpt == std::nullopt || PGOOpt->Action != PGOOptions::SampleUse)
return std::string();
@@ -469,21 +277,22 @@ getPassNameAndInstanceNum(StringRef PassName) {
}
void TargetPassConfig::setStartStopPasses() {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
StringRef StartBeforeName;
std::tie(StartBeforeName, StartBeforeInstanceNum) =
- getPassNameAndInstanceNum(StartBeforeOpt);
+ getPassNameAndInstanceNum(Opts.start_before);
StringRef StartAfterName;
std::tie(StartAfterName, StartAfterInstanceNum) =
- getPassNameAndInstanceNum(StartAfterOpt);
+ getPassNameAndInstanceNum(Opts.start_after);
StringRef StopBeforeName;
- std::tie(StopBeforeName, StopBeforeInstanceNum)
- = getPassNameAndInstanceNum(StopBeforeOpt);
+ std::tie(StopBeforeName, StopBeforeInstanceNum) =
+ getPassNameAndInstanceNum(Opts.stop_before);
StringRef StopAfterName;
- std::tie(StopAfterName, StopAfterInstanceNum)
- = getPassNameAndInstanceNum(StopAfterOpt);
+ std::tie(StopAfterName, StopAfterInstanceNum) =
+ getPassNameAndInstanceNum(Opts.stop_after);
StartBefore = getPassIDFromName(StartBeforeName);
StartAfter = getPassIDFromName(StartAfterName);
@@ -498,44 +307,46 @@ void TargetPassConfig::setStartStopPasses() {
Started = (StartAfter == nullptr) && (StartBefore == nullptr);
}
+static cl::boolOrDefault toBoolOrDefault(BoolOrDefault B) {
+ if (B == BoolOrDefault::Default)
+ return cl::boolOrDefault::BOU_UNSET;
+ return B == BoolOrDefault::True ? cl::boolOrDefault::BOU_TRUE
+ : cl::boolOrDefault::BOU_FALSE;
+}
+
CGPassBuilderOption llvm::getCGPassBuilderOption() {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
CGPassBuilderOption Opt;
-
-#define SET_OPTION_IF_PRESENT(Option) \
- if (Option.getNumOccurrences()) \
- Opt.Option = Option;
-
- SET_OPTION_IF_PRESENT(EnableGlobalISelAbort)
- SET_OPTION_IF_PRESENT(EnableIPRA)
-
-#define SET_OPTION(Option) Opt.Option = Option;
-
- SET_OPTION(EnableFastISelOption)
- SET_OPTION(EnableGlobalISelOption)
- SET_OPTION(VerifyMachineCode)
- SET_OPTION(DisableAtExitBasedGlobalDtorLowering)
- SET_OPTION(DisableExpandReductions)
- SET_OPTION(PrintAfterISel)
- SET_OPTION(FSProfileFile)
- SET_OPTION(EnableGCEmptyBlocks)
- SET_OPTION(EnableBlockPlacementStats)
- SET_OPTION(EnableGlobalMergeFunc)
- SET_OPTION(EnableImplicitNullChecks)
- SET_OPTION(EnableMachineOutliner)
- SET_OPTION(MISchedPostRA)
- SET_OPTION(DisableLSR)
- SET_OPTION(DisableConstantHoisting)
- SET_OPTION(DisableCGP)
- SET_OPTION(DisablePartialLibcallInlining)
- SET_OPTION(DisableSelectOptimize)
- SET_OPTION(PrintISelInput)
- SET_OPTION(PrintRegUsage)
- SET_OPTION(DebugifyAndStripAll)
- SET_OPTION(DebugifyCheckAndStripAll)
- SET_OPTION(DisableRAFSProfileLoader)
- SET_OPTION(DisableCFIFixup)
- SET_OPTION(EnableMachineFunctionSplitter)
-
+ Opt.EnableGlobalISelAbort = Opts.global_isel_abort;
+ if (Opts.enable_ipra != BoolOrDefault::Default)
+ Opt.EnableIPRA = Opts.enable_ipra == BoolOrDefault::True;
+ Opt.EnableFastISelOption = toBoolOrDefault(Opts.fast_isel);
+ Opt.EnableGlobalISelOption = toBoolOrDefault(Opts.global_isel);
+ Opt.VerifyMachineCode = toBoolOrDefault(Opts.verify_machineinstrs);
+ Opt.DisableAtExitBasedGlobalDtorLowering =
+ Opts.disable_atexit_based_global_dtor_lowering;
+ Opt.DisableExpandReductions = Opts.disable_expand_reductions;
+ Opt.PrintAfterISel = Opts.print_after_isel;
+ Opt.FSProfileFile = Opts.fs_profile_file.str();
+ Opt.EnableGCEmptyBlocks = Opts.enable_gc_empty_basic_blocks;
+ Opt.EnableBlockPlacementStats = Opts.enable_block_placement_stats;
+ Opt.EnableGlobalMergeFunc = Opts.enable_global_merge_func;
+ Opt.EnableImplicitNullChecks = Opts.enable_implicit_null_checks;
+ Opt.EnableMachineOutliner = EnableMachineOutliner;
+ Opt.MISchedPostRA = Opts.misched_postra;
+ Opt.DisableLSR = Opts.disable_lsr;
+ Opt.DisableConstantHoisting = Opts.disable_constant_hoisting;
+ Opt.DisableCGP = Opts.disable_cgp;
+ Opt.DisablePartialLibcallInlining = Opts.disable_partial_libcall_inlining;
+ Opt.DisableSelectOptimize = Opts.disable_select_optimize;
+ Opt.PrintISelInput = Opts.print_isel_input;
+ Opt.PrintRegUsage = Opts.print_regusage;
+ Opt.DebugifyAndStripAll = toBoolOrDefault(Opts.debugify_and_strip_all_safe);
+ Opt.DebugifyCheckAndStripAll =
+ toBoolOrDefault(Opts.debugify_check_and_strip_all_safe);
+ Opt.DisableRAFSProfileLoader = Opts.disable_ra_fsprofile_loader;
+ Opt.DisableCFIFixup = Opts.disable_cfi_fixup;
+ Opt.EnableMachineFunctionSplitter = Opts.enable_split_machine_functions;
return Opt;
}
@@ -544,24 +355,25 @@ void llvm::registerCodeGenCallback(PassInstrumentationCallbacks &PIC,
// Register a callback for disabling passes.
PIC.registerShouldRunOptionalPassCallback([](StringRef P, IRUnitRef) {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
#define DISABLE_PASS(Option, Name) \
if (Option && P.contains(#Name)) \
return false;
- DISABLE_PASS(DisableBlockPlacement, MachineBlockPlacementPass)
- DISABLE_PASS(DisableBranchFold, BranchFolderPass)
- DISABLE_PASS(DisableCopyProp, MachineCopyPropagationPass)
- DISABLE_PASS(DisableEarlyIfConversion, EarlyIfConverterLegacyPass)
- DISABLE_PASS(DisableEarlyTailDup, EarlyTailDuplicatePass)
- DISABLE_PASS(DisableMachineCSE, MachineCSELegacyPass)
- DISABLE_PASS(DisableMachineDCE, DeadMachineInstructionElimPass)
- DISABLE_PASS(DisableMachineLICM, EarlyMachineLICMPass)
- DISABLE_PASS(DisableMachineSink, MachineSinkingPass)
- DISABLE_PASS(DisablePostRAMachineLICM, MachineLICMPass)
- DISABLE_PASS(DisablePostRAMachineSink, PostRAMachineSinkingPass)
- DISABLE_PASS(DisablePostRASched, PostRASchedulerPass)
- DISABLE_PASS(DisableSSC, StackSlotColoringPass)
- DISABLE_PASS(DisableTailDuplicate, TailDuplicatePass)
+ DISABLE_PASS(Opts.disable_block_placement, MachineBlockPlacementPass)
+ DISABLE_PASS(Opts.disable_branch_fold, BranchFolderPass)
+ DISABLE_PASS(Opts.disable_copyprop, MachineCopyPropagationPass)
+ DISABLE_PASS(Opts.disable_early_ifcvt, EarlyIfConverterLegacyPass)
+ DISABLE_PASS(Opts.disable_early_taildup, EarlyTailDuplicatePass)
+ DISABLE_PASS(Opts.disable_machine_cse, MachineCSELegacyPass)
+ DISABLE_PASS(Opts.disable_machine_dce, DeadMachineInstructionElimPass)
+ DISABLE_PASS(Opts.disable_machine_licm, EarlyMachineLICMPass)
+ DISABLE_PASS(Opts.disable_machine_sink, MachineSinkingPass)
+ DISABLE_PASS(Opts.disable_postra_machine_licm, MachineLICMPass)
+ DISABLE_PASS(Opts.disable_postra_machine_sink, PostRAMachineSinkingPass)
+ DISABLE_PASS(Opts.disable_post_ra, PostRASchedulerPass)
+ DISABLE_PASS(Opts.disable_ssc, StackSlotColoringPass)
+ DISABLE_PASS(Opts.disable_tail_duplicate, TailDuplicatePass)
return true;
});
@@ -569,14 +381,15 @@ void llvm::registerCodeGenCallback(PassInstrumentationCallbacks &PIC,
Expected<TargetPassConfig::StartStopInfo>
TargetPassConfig::getStartStopInfo(PassInstrumentationCallbacks &PIC) {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
auto [StartBefore, StartBeforeInstanceNum] =
- getPassNameAndInstanceNum(StartBeforeOpt);
+ getPassNameAndInstanceNum(Opts.start_before);
auto [StartAfter, StartAfterInstanceNum] =
- getPassNameAndInstanceNum(StartAfterOpt);
+ getPassNameAndInstanceNum(Opts.start_after);
auto [StopBefore, StopBeforeInstanceNum] =
- getPassNameAndInstanceNum(StopBeforeOpt);
+ getPassNameAndInstanceNum(Opts.stop_before);
auto [StopAfter, StopAfterInstanceNum] =
- getPassNameAndInstanceNum(StopAfterOpt);
+ getPassNameAndInstanceNum(Opts.stop_after);
if (!StartBefore.empty() && !StartAfter.empty())
return make_error<StringError>(
@@ -605,6 +418,7 @@ TargetPassConfig::getStartStopInfo(PassInstrumentationCallbacks &PIC) {
// registers all common codegen passes.
TargetPassConfig::TargetPassConfig(TargetMachine &TM, PassManagerBase &PM)
: ImmutablePass(ID), PM(&PM), TM(&TM) {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
Impl = new PassConfigImpl();
PassRegistry &PR = *PassRegistry::getPassRegistry();
@@ -618,8 +432,8 @@ TargetPassConfig::TargetPassConfig(TargetMachine &TM, PassManagerBase &PM)
initializeBasicAAWrapperPassPass(PR);
initializeAAResultsWrapperPassPass(PR);
- if (EnableIPRA.getNumOccurrences()) {
- TM.Options.EnableIPRA = EnableIPRA;
+ if (Opts.enable_ipra != BoolOrDefault::Default) {
+ TM.Options.EnableIPRA = Opts.enable_ipra == BoolOrDefault::True;
} else {
// If not explicitly specified, use target default.
TM.Options.EnableIPRA |= TM.useIPRA();
@@ -628,8 +442,8 @@ TargetPassConfig::TargetPassConfig(TargetMachine &TM, PassManagerBase &PM)
if (TM.Options.EnableIPRA)
setRequiresCodeGenSCCOrder();
- if (EnableGlobalISelAbort.getNumOccurrences())
- TM.Options.GlobalISelAbort = EnableGlobalISelAbort;
+ if (Opts.global_isel_abort)
+ TM.Options.GlobalISelAbort = *Opts.global_isel_abort;
setStartStopPasses();
}
@@ -666,25 +480,28 @@ TargetPassConfig::TargetPassConfig()
}
bool TargetPassConfig::willCompleteCodeGenPipeline() {
- return StopBeforeOpt.empty() && StopAfterOpt.empty();
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
+ return Opts.stop_before.empty() && Opts.stop_after.empty();
}
bool TargetPassConfig::hasLimitedCodeGenPipeline() {
- return !StartBeforeOpt.empty() || !StartAfterOpt.empty() ||
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
+ return !Opts.start_before.empty() || !Opts.start_after.empty() ||
!willCompleteCodeGenPipeline();
}
std::string TargetPassConfig::getLimitedCodeGenPipelineReason() {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
if (!hasLimitedCodeGenPipeline())
return std::string();
std::string Res;
- static cl::opt<std::string> *PassNames[] = {&StartAfterOpt, &StartBeforeOpt,
- &StopAfterOpt, &StopBeforeOpt};
+ StringRef PassNames[] = {Opts.start_after, Opts.start_before, Opts.stop_after,
+ Opts.stop_before};
static const char *OptNames[] = {StartAfterOptName, StartBeforeOptName,
StopAfterOptName, StopBeforeOptName};
bool IsFirst = true;
for (int Idx = 0; Idx < 4; ++Idx)
- if (!PassNames[Idx]->empty()) {
+ if (!PassNames[Idx].empty()) {
if (!IsFirst)
Res += " and ";
IsFirst = false;
@@ -797,14 +614,15 @@ void TargetPassConfig::printAndVerify(const std::string &Banner) {
}
void TargetPassConfig::addPrintPass(const std::string &Banner) {
- if (PrintAfterISel)
+ if (CodeGenOptions::Global.print_after_isel)
PM->add(createMachineFunctionPrinterPass(dbgs(), Banner));
}
void TargetPassConfig::addVerifyPass(const std::string &Banner) {
- bool Verify = VerifyMachineCode == cl::boolOrDefault::BOU_TRUE;
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
+ bool Verify = valueOr(Opts.verify_machineinstrs, false);
#ifdef EXPENSIVE_CHECKS
- if (VerifyMachineCode == cl::boolOrDefault::BOU_UNSET)
+ if (Opts.verify_machineinstrs == BoolOrDefault::Default)
Verify = TM->isMachineVerifierClean();
#endif
if (Verify)
@@ -824,18 +642,20 @@ void TargetPassConfig::addCheckDebugPass() {
}
void TargetPassConfig::addMachinePrePasses(bool AllowDebugify) {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
if (AllowDebugify && DebugifyIsSafe &&
- (DebugifyAndStripAll == cl::boolOrDefault::BOU_TRUE ||
- DebugifyCheckAndStripAll == cl::boolOrDefault::BOU_TRUE))
+ (valueOr(Opts.debugify_and_strip_all_safe, false) ||
+ valueOr(Opts.debugify_check_and_strip_all_safe, false)))
addDebugifyPass();
}
void TargetPassConfig::addMachinePostPasses(const std::string &Banner) {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
if (DebugifyIsSafe) {
- if (DebugifyCheckAndStripAll == cl::boolOrDefault::BOU_TRUE) {
+ if (valueOr(Opts.debugify_check_and_strip_all_safe, false)) {
addCheckDebugPass();
addStripDebugPass();
- } else if (DebugifyAndStripAll == cl::boolOrDefault::BOU_TRUE)
+ } else if (valueOr(Opts.debugify_and_strip_all_safe, false))
addStripDebugPass();
}
addVerifyPass(Banner);
@@ -844,6 +664,7 @@ void TargetPassConfig::addMachinePostPasses(const std::string &Banner) {
/// Add common target configurable passes that perform LLVM IR to IR transforms
/// following machine independent optimization.
void TargetPassConfig::addIRPasses() {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
// Before running any passes, run the verifier to determine if the input
// coming from the front-end and/or optimizer is valid.
if (!DisableVerify)
@@ -859,7 +680,7 @@ void TargetPassConfig::addIRPasses() {
addPass(createBasicAAWrapperPass());
// Run loop strength reduction before anything else.
- if (!DisableLSR) {
+ if (!Opts.disable_lsr) {
addPass(createCanonicalizeFreezeInLoopsPass());
addPass(createLoopStrengthReducePass());
if (EnableLoopTermFold)
@@ -875,20 +696,22 @@ void TargetPassConfig::addIRPasses() {
// For MachO, lower @llvm.global_dtors into @llvm.global_ctors with
// __cxa_atexit() calls to avoid emitting the deprecated __mod_term_func.
if (TM->getTargetTriple().isOSBinFormatMachO() &&
- !DisableAtExitBasedGlobalDtorLowering)
+ !Opts.disable_atexit_based_global_dtor_lowering)
addPass(createLowerGlobalDtorsLegacyPass());
// Make sure that no unreachable blocks are instruction selected.
addPass(createUnreachableBlockEliminationPass());
// Prepare expensive constants for SelectionDAG.
- if (getOptLevel() != CodeGenOptLevel::None && !DisableConstantHoisting)
+ if (getOptLevel() != CodeGenOptLevel::None && !Opts.disable_constant_hoisting)
addPass(createConstantHoistingPass());
- if (getOptLevel() != CodeGenOptLevel::None && !DisableReplaceWithVecLib)
+ if (getOptLevel() != CodeGenOptLevel::None &&
+ !Opts.disable_replace_with_vec_lib)
addPass(createReplaceWithVeclibLegacyPass());
- if (getOptLevel() != CodeGenOptLevel::None && !DisablePartialLibcallInlining)
+ if (getOptLevel() != CodeGenOptLevel::None &&
+ !Opts.disable_partial_libcall_inlining)
addPass(createPartiallyInlineLibCallsPass());
// Instrument function entry after all inlining.
@@ -901,14 +724,14 @@ void TargetPassConfig::addIRPasses() {
// Expand reduction intrinsics into shuffle sequences if the target wants to.
// Allow disabling it for testing purposes.
- if (!DisableExpandReductions)
+ if (!Opts.disable_expand_reductions)
addPass(createExpandReductionsPass());
// Convert conditional moves to conditional jumps when profitable.
- if (getOptLevel() != CodeGenOptLevel::None && !DisableSelectOptimize)
+ if (getOptLevel() != CodeGenOptLevel::None && !Opts.disable_select_optimize)
addPass(createSelectOptimizePass());
- if (EnableGlobalMergeFunc)
+ if (Opts.enable_global_merge_func)
addPass(createGlobalMergeFuncPass());
if (TM->getTargetTriple().isOSWindows())
@@ -966,7 +789,8 @@ void TargetPassConfig::addPassesToHandleExceptions() {
/// Add pass to prepare the LLVM IR for code generation. This should be done
/// before exception handling preparation passes.
void TargetPassConfig::addCodeGenPrepare() {
- if (getOptLevel() != CodeGenOptLevel::None && !DisableCGP)
+ if (getOptLevel() != CodeGenOptLevel::None &&
+ !CodeGenOptions::Global.disable_cgp)
addPass(createCodeGenPrepareLegacyPass());
}
@@ -986,7 +810,7 @@ void TargetPassConfig::addISelPrepare() {
addPass(createSafeStackPass());
addPass(createStackProtectorPass());
- if (PrintISelInput)
+ if (CodeGenOptions::Global.print_isel_input)
addPass(createPrintFunctionPass(
dbgs(), "\n\n*** Final LLVM Code input to ISel ***\n"));
@@ -997,18 +821,18 @@ void TargetPassConfig::addISelPrepare() {
}
bool TargetPassConfig::addCoreISelPasses() {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
// Enable FastISel with -fast-isel, but allow that to be overridden.
- TM->setO0WantsFastISel(EnableFastISelOption != cl::boolOrDefault::BOU_FALSE);
+ TM->setO0WantsFastISel(valueOr(Opts.fast_isel, true));
// Determine an instruction selector.
enum class SelectorType { SelectionDAG, FastISel, GlobalISel };
SelectorType Selector;
- if (EnableFastISelOption == cl::boolOrDefault::BOU_TRUE)
+ if (valueOr(Opts.fast_isel, false))
Selector = SelectorType::FastISel;
- else if (EnableGlobalISelOption == cl::boolOrDefault::BOU_TRUE ||
- (TM->Options.EnableGlobalISel &&
- EnableGlobalISelOption != cl::boolOrDefault::BOU_FALSE))
+ else if (valueOr(Opts.global_isel, false) ||
+ (TM->Options.EnableGlobalISel && valueOr(Opts.global_isel, true)))
Selector = SelectorType::GlobalISel;
else if (TM->getOptLevel() == CodeGenOptLevel::None &&
TM->getO0WantsFastISel())
@@ -1097,7 +921,7 @@ bool TargetPassConfig::addISelPasses() {
addPass(createExpandIRInstsPass(getOptLevel()));
addIRPasses();
- if (TriggerCrash)
+ if (CodeGenOptions::Global.codegen_pipeline_trigger_crash)
addPass(new TriggerCrashFunctionLegacyPass());
addCodeGenPrepare();
@@ -1133,6 +957,7 @@ static cl::opt<RegisterRegAlloc::FunctionPassCtor, false,
/// TODO: We could use a single addPre/Post(ID) hook to allow pass injection
/// before/after any target-independent pass. But it's currently overkill.
void TargetPassConfig::addMachinePasses() {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
AddingMachinePasses = true;
// Add passes that optimize machine instructions in SSA form.
@@ -1161,7 +986,7 @@ void TargetPassConfig::addMachinePasses() {
addPass(createMIRAddFSDiscriminatorsPass(
sampleprof::FSDiscriminatorPass::Pass1));
const std::string ProfileFile = getFSProfileFile(TM);
- if (!ProfileFile.empty() && !DisableRAFSProfileLoader)
+ if (!ProfileFile.empty() && !Opts.disable_ra_fsprofile_loader)
addPass(createMIRProfileLoaderPass(ProfileFile, getFSRemappingFile(TM),
sampleprof::FSDiscriminatorPass::Pass1,
nullptr));
@@ -1202,7 +1027,7 @@ void TargetPassConfig::addMachinePasses() {
// Run pre-sched2 passes.
addPreSched2();
- if (EnableImplicitNullChecks)
+ if (Opts.enable_implicit_null_checks)
addPass(&ImplicitNullChecksID);
// Second pass scheduler.
@@ -1210,7 +1035,7 @@ void TargetPassConfig::addMachinePasses() {
// point.
if (getOptLevel() != CodeGenOptLevel::None &&
!TM->targetSchedulesPostRAScheduling()) {
- if (MISchedPostRA)
+ if (Opts.misched_postra)
addPass(&PostMachineSchedulerID);
else
addPass(&PostRASchedulerID);
@@ -1253,7 +1078,7 @@ void TargetPassConfig::addMachinePasses() {
addPass(createMachineOutlinerPass(EnableMachineOutliner));
}
- if (EnableGCEmptyBlocks)
+ if (Opts.enable_gc_empty_basic_blocks)
addPass(llvm::createGCEmptyBasicBlocksLegacyPass());
if (EnableFSDiscriminator)
@@ -1261,7 +1086,7 @@ void TargetPassConfig::addMachinePasses() {
sampleprof::FSDiscriminatorPass::PassLast));
if (TM->Options.EnableMachineFunctionSplitter ||
- EnableMachineFunctionSplitter || SplitStaticData ||
+ Opts.enable_split_machine_functions || Opts.split_static_data ||
TM->Options.EnableStaticDataPartitioning) {
const std::string ProfileFile = getFSProfileFile(TM);
if (!ProfileFile.empty()) {
@@ -1285,10 +1110,10 @@ void TargetPassConfig::addMachinePasses() {
// basic-block-sections optimizations (`=all`, or `=list=` with function
// included in the list profile) will get that optimization instead.
if (TM->Options.EnableMachineFunctionSplitter ||
- EnableMachineFunctionSplitter)
+ Opts.enable_split_machine_functions)
addPass(createMachineFunctionSplitterPass());
- if (SplitStaticData || TM->Options.EnableStaticDataPartitioning) {
+ if (Opts.split_static_data || TM->Options.EnableStaticDataPartitioning) {
// The static data splitter pass is a machine function pass. and
// static data annotator pass is a module-wide pass. See the file comment
// in StaticDataAnnotator.cpp for the motivation.
@@ -1299,12 +1124,12 @@ void TargetPassConfig::addMachinePasses() {
// address map (or both).
if (TM->getBBSectionsType() != llvm::BasicBlockSection::None ||
TM->Options.BBAddrMap) {
- if (shouldEmitBBHash() || BasicBlockSectionMatchInfer)
+ if (shouldEmitBBHash() || Opts.basic_block_section_match_infer)
addPass(llvm::createMachineBlockHashInfoPass());
if (TM->getBBSectionsType() == llvm::BasicBlockSection::List) {
addPass(llvm::createBasicBlockSectionsProfileReaderWrapperPass(
TM->getBBSectionsFuncListBuf()));
- if (BasicBlockSectionMatchInfer)
+ if (Opts.basic_block_section_match_infer)
addPass(llvm::createBasicBlockMatchingAndInferencePass());
else {
addPass(llvm::createBasicBlockPathCloningPass());
@@ -1316,7 +1141,7 @@ void TargetPassConfig::addMachinePasses() {
addPostBBSections();
- if (!DisableCFIFixup && TM->Options.EnableCFIFixup)
+ if (!Opts.disable_cfi_fixup && TM->Options.EnableCFIFixup)
addPass(createCFIFixupLegacy());
PM->add(createStackFrameLayoutAnalysisPass());
@@ -1575,18 +1400,19 @@ bool TargetPassConfig::addGCPasses() {
/// Add standard basic block placement passes.
void TargetPassConfig::addBlockPlacement() {
+ const CodeGenOptions &Opts = CodeGenOptions::Global;
if (EnableFSDiscriminator) {
addPass(createMIRAddFSDiscriminatorsPass(
sampleprof::FSDiscriminatorPass::Pass2));
const std::string ProfileFile = getFSProfileFile(TM);
- if (!ProfileFile.empty() && !DisableLayoutFSProfileLoader)
+ if (!ProfileFile.empty() && !Opts.disable_layout_fsprofile_loader)
addPass(createMIRProfileLoaderPass(ProfileFile, getFSRemappingFile(TM),
sampleprof::FSDiscriminatorPass::Pass2,
nullptr));
}
if (addPass(&MachineBlockPlacementID)) {
// Run a separate pass to collect block placement statistics.
- if (EnableBlockPlacementStats)
+ if (Opts.enable_block_placement_stats)
addPass(&MachineBlockPlacementStatsID);
}
}
diff --git a/llvm/utils/gn/secondary/llvm/lib/CodeGen/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/CodeGen/BUILD.gn
index cc1463cbe9e3a..dfcb12d75a465 100644
--- a/llvm/utils/gn/secondary/llvm/lib/CodeGen/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/CodeGen/BUILD.gn
@@ -1,3 +1,10 @@
+import("//llvm/utils/TableGen/tablegen.gni")
+
+tablegen("CodeGenOptions") {
+ visibility = [ ":CodeGen" ]
+ args = [ "-gen-opt-parser-defs" ]
+}
+
static_library("CodeGen") {
output_name = "LLVMCodeGen"
public_deps = [
@@ -5,6 +12,7 @@ static_library("CodeGen") {
"//llvm/include/llvm/Config:llvm-config",
]
deps = [
+ ":CodeGenOptions",
"//llvm/include/llvm/CodeGen:GenVT",
"//llvm/lib/Analysis",
"//llvm/lib/Bitcode/Reader",
@@ -13,6 +21,7 @@ static_library("CodeGen") {
"//llvm/lib/CodeGenTypes",
"//llvm/lib/IR",
"//llvm/lib/MC",
+ "//llvm/lib/Option",
"//llvm/lib/ProfileData",
"//llvm/lib/Support",
"//llvm/lib/Target",
@@ -42,6 +51,7 @@ static_library("CodeGen") {
"CallingConvLower.cpp",
"CodeGen.cpp",
"CodeGenCommonISel.cpp",
+ "CodeGenOptions.cpp",
"CodeGenPrepare.cpp",
"CodeGenTargetMachineImpl.cpp",
"CommandFlags.cpp",
diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
index df9cbbf9a29ae..826ac64b62006 100644
--- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
@@ -2454,6 +2454,15 @@ cc_library(
],
)
+gentbl_cc_library(
+ name = "CodeGenOptionsTableGen",
+ strip_include_prefix = "lib/CodeGen",
+ tbl_outs = {"lib/CodeGen/CodeGenOptions.inc": ["-gen-opt-parser-defs"]},
+ tblgen = ":llvm-min-tblgen",
+ td_file = "lib/CodeGen/CodeGenOptions.td",
+ deps = [":OptParserTdFiles"],
+)
+
cc_library(
name = "CodeGen",
srcs = glob(
@@ -2485,6 +2494,7 @@ cc_library(
":BitWriter",
":CFGuard",
":CGData",
+ ":CodeGenOptionsTableGen",
":CodeGenTypes",
":Core",
":DebugInfoCodeView",
@@ -2497,6 +2507,7 @@ cc_library(
":MCParser",
":ObjCARC",
":Object",
+ ":Option",
":ProfileData",
":Remarks",
":Scalar",
More information about the llvm-branch-commits
mailing list