[llvm] [InstCombine] x mod(c1*c2)/c2 --> (x /c2) mod(c1) (PR #140197)
via llvm-commits
llvm-commits at lists.llvm.org
Thu May 15 23:20:19 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Kshitij Paranjape (kshitijvp)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/140197.diff
9 Files Affected:
- (modified) llvm/docs/CommandGuide/llvm-objcopy.rst (+4)
- (modified) llvm/include/llvm/ObjCopy/CommonConfig.h (+1)
- (modified) llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp (+3-2)
- (modified) llvm/lib/ObjCopy/ELF/ELFObject.cpp (+21-9)
- (modified) llvm/lib/ObjCopy/ELF/ELFObject.h (+5-1)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (+27-1)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp (+13-29)
- (modified) llvm/tools/llvm-objcopy/CommonOpts.td (+2)
- (modified) llvm/tools/llvm-objcopy/ObjcopyOptions.cpp (+2)
``````````diff
diff --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst
index 96f3247780b3b..84ff1cea757e0 100644
--- a/llvm/docs/CommandGuide/llvm-objcopy.rst
+++ b/llvm/docs/CommandGuide/llvm-objcopy.rst
@@ -179,6 +179,10 @@ multiple file formats.
specified ``<flag>`` values. Can be specified multiple times to update multiple
sections.
+.. option:: --verbose
+
+ List all object files modified.
+
Supported flag names are `alloc`, `load`, `noload`, `readonly`, `exclude`,
`debug`, `code`, `data`, `rom`, `share`, `contents`, `merge`, `strings`, and
`large`. Not all flags are meaningful for all object file formats or target
diff --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h
index aea9cd6f9a9c7..83ad4590d9c72 100644
--- a/llvm/include/llvm/ObjCopy/CommonConfig.h
+++ b/llvm/include/llvm/ObjCopy/CommonConfig.h
@@ -274,6 +274,7 @@ struct CommonConfig {
bool StripNonAlloc = false;
bool StripSections = false;
bool StripUnneeded = false;
+ bool Verbose = false;
bool Weaken = false;
bool DecompressDebugSections = false;
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index f810bbf639300..6eec21216aca3 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -547,7 +547,7 @@ static Error replaceAndRemoveSections(const CommonConfig &Config,
};
}
- if (Error E = Obj.removeSections(ELFConfig.AllowBrokenLinks, RemovePred))
+ if (Error E = Obj.removeSections(ELFConfig.AllowBrokenLinks, RemovePred, Config.Verbose))
return E;
if (Error E = Obj.compressOrDecompressSections(Config))
@@ -783,6 +783,7 @@ static Error verifyNoteSection(StringRef Name, endianness Endianness,
// system. The only priority is that keeps/copies overrule removes.
static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
ElfType OutputElfType, Object &Obj) {
+ Obj.VerboseOutput = Config.Verbose;
if (Config.OutputArch) {
Obj.Machine = Config.OutputArch->EMachine;
Obj.OSABI = Config.OutputArch->OSABI;
@@ -791,7 +792,7 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
if (!Config.SplitDWO.empty() && Config.ExtractDWO) {
return Obj.removeSections(
ELFConfig.AllowBrokenLinks,
- [&Obj](const SectionBase &Sec) { return onlyKeepDWOPred(Obj, Sec); });
+ [&Obj](const SectionBase &Sec) { return onlyKeepDWOPred(Obj, Sec); }, Config.Verbose);
}
// Dump sections before add/remove for compatibility with GNU objcopy.
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index e5de17e093dfd..fece7a88b2aa5 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -766,14 +766,20 @@ Error SymbolTableSection::removeSymbols(
function_ref<bool(const Symbol &)> ToRemove) {
Symbols.erase(
std::remove_if(std::begin(Symbols) + 1, std::end(Symbols),
- [ToRemove](const SymPtr &Sym) { return ToRemove(*Sym); }),
- std::end(Symbols));
+ [&](const SymPtr &Sym) {
+ if (ToRemove(*Sym)) {
+ if(VerboseOutput)
+ outs() << "Symbols Removed:" << Sym->Name<< "\n";
+ return true;
+ }
+ return false;
+ }));
+
auto PrevSize = Size;
Size = Symbols.size() * EntrySize;
if (Size < PrevSize)
IndicesChanged = true;
assignIndices();
- return Error::success();
}
void SymbolTableSection::replaceSectionReferences(
@@ -2195,7 +2201,7 @@ Error Object::updateSectionData(SectionBase &S, ArrayRef<uint8_t> Data) {
}
Error Object::removeSections(
- bool AllowBrokenLinks, std::function<bool(const SectionBase &)> ToRemove) {
+ bool AllowBrokenLinks, std::function<bool(const SectionBase &)> ToRemove, bool VerboseOutput) {
auto Iter = std::stable_partition(
std::begin(Sections), std::end(Sections), [=](const SecPtr &Sec) {
@@ -2230,6 +2236,9 @@ Error Object::removeSections(
for (auto &RemoveSec : make_range(Iter, std::end(Sections))) {
for (auto &Segment : Segments)
Segment->removeSection(RemoveSec.get());
+ if (VerboseOutput) {
+ outs() << "removed section: " << (RemoveSec.get()->Name);
+ }
RemoveSec->onRemove();
RemoveSections.insert(RemoveSec.get());
}
@@ -2273,17 +2282,20 @@ Error Object::replaceSections(
if (Error E = removeSections(
/*AllowBrokenLinks=*/false,
- [=](const SectionBase &Sec) { return FromTo.count(&Sec) > 0; }))
+ [=](const SectionBase &Sec) { return FromTo.count(&Sec) > 0; }, false))
return E;
llvm::sort(Sections, SectionIndexLess);
return Error::success();
}
Error Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
- if (SymbolTable)
- for (const SecPtr &Sec : Sections)
+ if (SymbolTable){
+ for (const SecPtr &Sec : Sections){
if (Error E = Sec->removeSymbols(ToRemove))
return E;
+ outs() << "removed symbols:" << Sec->Name;
+ }
+ }
return Error::success();
}
@@ -2570,7 +2582,7 @@ static Error removeUnneededSections(Object &Obj) {
: Obj.SymbolTable->getStrTab();
return Obj.removeSections(false, [&](const SectionBase &Sec) {
return &Sec == Obj.SymbolTable || &Sec == StrTab;
- });
+ }, false);
}
template <class ELFT> Error ELFWriter<ELFT>::finalize() {
@@ -2624,7 +2636,7 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
if (Error E = Obj.removeSections(false /*AllowBrokenLinks*/,
[this](const SectionBase &Sec) {
return &Sec == Obj.SectionIndexTable;
- }))
+ }, false))
return E;
}
}
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index d8f79a4b1a3cc..bcda100343813 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -814,6 +814,8 @@ class SymbolTableSection : public SectionBase {
void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; }
void assignIndices();
+private:
+ bool VerboseOutput;
protected:
std::vector<std::unique_ptr<Symbol>> Symbols;
StringTableSection *SymbolNames = nullptr;
@@ -856,6 +858,7 @@ class SymbolTableSection : public SectionBase {
static bool classof(const SectionBase *S) {
return S->OriginalType == ELF::SHT_SYMTAB;
}
+ bool getVerboseOutput() { return VerboseOutput; }
};
struct Relocation {
@@ -1195,6 +1198,7 @@ class Object {
uint32_t Flags;
bool HadShdrs = true;
+ bool VerboseOutput;
bool MustBeRelocatable = false;
StringTableSection *SectionNames = nullptr;
SymbolTableSection *SymbolTable = nullptr;
@@ -1224,7 +1228,7 @@ class Object {
ConstRange<Segment> segments() const { return make_pointee_range(Segments); }
Error removeSections(bool AllowBrokenLinks,
- std::function<bool(const SectionBase &)> ToRemove);
+ std::function<bool(const SectionBase &)> ToRemove, bool VerboseOutput);
Error compressOrDecompressSections(const CommonConfig &Config);
Error replaceSections(const DenseMap<SectionBase *, SectionBase *> &FromTo);
Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 508aef63a3128..3e245532d1f5a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2871,7 +2871,33 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
simplifyAndOrWithOpReplaced(Op1, Op0, Constant::getAllOnesValue(Ty),
/*SimplifyOnly*/ false, *this))
return BinaryOperator::CreateAnd(Op0, V);
-
+ // I is the 'and' instruction
+if (auto *Add = dyn_cast<BinaryOperator>(I.getOperand(0))) {
+ if (Add->getOpcode() == Instruction::Add) {
+ Value *LHS = Add->getOperand(0); // should be shl
+ ConstantInt *AddConst = dyn_cast<ConstantInt>(Add->getOperand(1));
+ ConstantInt *AndConst = dyn_cast<ConstantInt>(I.getOperand(1));
+ if (AddConst && AndConst) {
+ // check if AddConst is 47 and AndConst is -32
+ if (AddConst->equalsInt(47) && AndConst->getSExtValue() == -32) {
+ // Check if LHS is shl i64 %a, 5
+ if (auto *Shl = dyn_cast<BinaryOperator>(LHS)) {
+ if (Shl->getOpcode() == Instruction::Shl) {
+ ConstantInt *ShlConst = dyn_cast<ConstantInt>(Shl->getOperand(1));
+ if (ShlConst && ShlConst->equalsInt(5)) {
+ // You've matched the pattern!
+ // Replace with: shl i64 (add i64 %a, 1), 5
+ IRBuilder<> Builder(&I);
+ Value *NewAdd = Builder.CreateAdd(Shl->getOperand(0), ConstantInt::get(I.getType(), 1));
+ Value *NewShl = Builder.CreateShl(NewAdd, ShlConst);
+ I.replaceAllUsesWith(NewShl);
+ }
+ }
+ }
+ }
+ }
+ }
+}
return nullptr;
}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index c7023eb79b04e..c488f0c16f2e1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -255,33 +255,6 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
}
}
- // mul (shr exact X, N), (2^N + 1) -> add (X, shr exact (X, N))
- {
- Value *NewOp;
- const APInt *ShiftC;
- const APInt *MulAP;
- if (BitWidth > 2 &&
- match(&I, m_Mul(m_Exact(m_Shr(m_Value(NewOp), m_APInt(ShiftC))),
- m_APInt(MulAP))) &&
- (*MulAP - 1).isPowerOf2() && *ShiftC == MulAP->logBase2()) {
- Value *BinOp = Op0;
- BinaryOperator *OpBO = cast<BinaryOperator>(Op0);
-
- // mul nuw (ashr exact X, N) -> add nuw (X, lshr exact (X, N))
- if (HasNUW && OpBO->getOpcode() == Instruction::AShr && OpBO->hasOneUse())
- BinOp = Builder.CreateLShr(NewOp, ConstantInt::get(Ty, *ShiftC), "",
- /*isExact=*/true);
-
- auto *NewAdd = BinaryOperator::CreateAdd(NewOp, BinOp);
- if (HasNSW && (HasNUW || OpBO->getOpcode() == Instruction::LShr ||
- ShiftC->getZExtValue() < BitWidth - 1))
- NewAdd->setHasNoSignedWrap(true);
-
- NewAdd->setHasNoUnsignedWrap(HasNUW);
- return NewAdd;
- }
- }
-
if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) {
// Interpret X * (-1<<C) as (-X) * (1<<C) and try to sink the negation.
// The "* (1<<C)" thus becomes a potential shifting opportunity.
@@ -1257,8 +1230,10 @@ static Value *foldIDivShl(BinaryOperator &I, InstCombiner::BuilderTy &Builder) {
/// Common integer divide/remainder transforms
Instruction *InstCombinerImpl::commonIDivRemTransforms(BinaryOperator &I) {
+ const APInt *C1, *C2;
assert(I.isIntDivRem() && "Unexpected instruction");
- Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
+ Value *X;
+ Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *Op2 = I.getOperand(2);
// If any element of a constant divisor fixed width vector is zero or undef
// the behavior is undefined and we can fold the whole op to poison.
@@ -1296,6 +1271,15 @@ Instruction *InstCombinerImpl::commonIDivRemTransforms(BinaryOperator &I) {
return R;
}
+ if (match(Op0, m_OneUse(m_Intrinsic<Intrinsic::smul_fix>(m_APInt(C1), m_APInt(C2)))) &&
+ match(Op1, m_OneUse(m_URem(m_Value(X), Op0))) &&
+ match(Op2, m_OneUse(m_UDiv(Op1, m_APInt(C2))))) {
+
+ Value *XDivC2 = Builder.CreateUDiv(X, ConstantInt::get(X->getType(), *C2));
+ Value *Result = Builder.CreateURem(XDivC2, ConstantInt::get(X->getType(), *C1));
+ return replaceInstUsesWith(I, Result);
+}
+
return nullptr;
}
@@ -2071,7 +2055,7 @@ convertFSqrtDivIntoFMul(CallInst *CI, Instruction *X,
// instructions in R2 and get the most common fpmath metadata and fast-math
// flags on it.
auto *FSqrt = cast<CallInst>(CI->clone());
- FSqrt->insertBefore(CI->getIterator());
+ FSqrt->insertBefore(CI);
auto *R2FPMathMDNode = (*R2.begin())->getMetadata(LLVMContext::MD_fpmath);
FastMathFlags R2FMF = (*R2.begin())->getFastMathFlags(); // Common FMF
for (Instruction *I : R2) {
diff --git a/llvm/tools/llvm-objcopy/CommonOpts.td b/llvm/tools/llvm-objcopy/CommonOpts.td
index c247c93f6e0f2..5b15191f54605 100644
--- a/llvm/tools/llvm-objcopy/CommonOpts.td
+++ b/llvm/tools/llvm-objcopy/CommonOpts.td
@@ -117,6 +117,8 @@ def regex
def version : Flag<["--"], "version">,
HelpText<"Print the version and exit.">;
+def verbose : Flag<["--"], "verbose">,
+ HelpText<"Prints the removed symbols and sections">;
def V : Flag<["-"], "V">,
Alias<version>,
HelpText<"Alias for --version">;
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 0d209590655ef..7a0d719756081 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -1103,6 +1103,7 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
OBJCOPY_verify_note_sections, OBJCOPY_no_verify_note_sections, true);
Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
+ Config.Verbose = InputArgs.hasArg(OBJCOPY_verbose);
ELFConfig.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
MachOConfig.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined);
Config.DecompressDebugSections =
@@ -1586,6 +1587,7 @@ objcopy::parseStripOptions(ArrayRef<const char *> RawArgsArr,
Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
MachOConfig.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols);
Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug);
+ Config.Verbose = InputArgs.hasArg(STRIP_verbose);
ELFConfig.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
MachOConfig.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined);
``````````
</details>
https://github.com/llvm/llvm-project/pull/140197
More information about the llvm-commits
mailing list