llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-llvm-transforms Author: Peter Collingbourne (pcc) <details> <summary>Changes</summary> This pass figures out whether inlining has exposed a constant address to a lowered type test, and remove the test if so and the address is known to pass the test. Unfortunately this pass ends up needing to reverse engineer what LowerTypeTests did; this is currently inherent to the design of ThinLTO importing where LowerTypeTests needs to run at the start. TODO: Add tests. --- Full diff: https://github.com/llvm/llvm-project/pull/141327.diff 4 Files Affected: - (modified) llvm/include/llvm/Transforms/IPO/LowerTypeTests.h (+5) - (modified) llvm/lib/Passes/PassBuilderPipelines.cpp (+2) - (modified) llvm/lib/Passes/PassRegistry.def (+1) - (modified) llvm/lib/Transforms/IPO/LowerTypeTests.cpp (+61) ``````````diff diff --git a/llvm/include/llvm/Transforms/IPO/LowerTypeTests.h b/llvm/include/llvm/Transforms/IPO/LowerTypeTests.h index 02adcd8bfd45d..40f2d2c4fadf7 100644 --- a/llvm/include/llvm/Transforms/IPO/LowerTypeTests.h +++ b/llvm/include/llvm/Transforms/IPO/LowerTypeTests.h @@ -223,6 +223,11 @@ class LowerTypeTestsPass : public PassInfoMixin<LowerTypeTestsPass> { PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; +class SimplifyTypeTestsPass : public PassInfoMixin<SimplifyTypeTestsPass> { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + } // end namespace llvm #endif // LLVM_TRANSFORMS_IPO_LOWERTYPETESTS_H diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index f3654600c5abb..e3adceed7d70a 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -1464,6 +1464,8 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, if (!LTOPreLink) MPM.addPass(EliminateAvailableExternallyPass()); + MPM.addPass(SimplifyTypeTestsPass()); + // Do RPO function attribute inference across the module to forward-propagate // attributes where applicable. // FIXME: Is this really an optimization rather than a canonicalization? diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 94dabe290213d..35ad73738d71d 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -100,6 +100,7 @@ MODULE_PASS("jmc-instrumenter", JMCInstrumenterPass()) MODULE_PASS("lower-emutls", LowerEmuTLSPass()) MODULE_PASS("lower-global-dtors", LowerGlobalDtorsPass()) MODULE_PASS("lower-ifunc", LowerIFuncPass()) +MODULE_PASS("simplify-type-tests", SimplifyTypeTestsPass()) MODULE_PASS("lowertypetests", LowerTypeTestsPass()) MODULE_PASS("fatlto-cleanup", FatLtoCleanup()) MODULE_PASS("pgo-force-function-attrs", PGOForceFunctionAttrsPass(PGOOpt ? PGOOpt->ColdOptType : PGOOptions::ColdFuncOpt::Default)) diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp index 428c4641a7f56..344ac9f5a8f95 100644 --- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -2456,3 +2456,64 @@ PreservedAnalyses LowerTypeTestsPass::run(Module &M, return PreservedAnalyses::all(); return PreservedAnalyses::none(); } + +PreservedAnalyses SimplifyTypeTestsPass::run(Module &M, + ModuleAnalysisManager &AM) { + bool Changed = false; + // Figure out whether inlining has exposed a constant address to a lowered + // type test, and remove the test if so and the address is known to pass the + // test. Unfortunately this pass ends up needing to reverse engineer what + // LowerTypeTests did; this is currently inherent to the design of ThinLTO + // importing where LowerTypeTests needs to run at the start. + for (auto &GV : M.globals()) { + if (!GV.getName().starts_with("__typeid_") || + !GV.getName().ends_with("_global_addr")) + continue; + auto *MD = MDString::get(M.getContext(), + GV.getName().substr(9, GV.getName().size() - 21)); + auto MaySimplify = [&](Value *Op) { + auto *PtrAsInt = dyn_cast<ConstantExpr>(Op); + if (!PtrAsInt || PtrAsInt->getOpcode() != Instruction::PtrToInt) + return false; + auto *Ptr = PtrAsInt->getOperand(0); + if (auto *GV = dyn_cast<GlobalValue>(Ptr)) + if (auto *CFIGV = M.getNamedValue((GV->getName() + ".cfi").str())) + Ptr = CFIGV; + return isKnownTypeIdMember(MD, M.getDataLayout(), Ptr, 0); + }; + for (User *U : GV.users()) { + auto *CE = dyn_cast<ConstantExpr>(U); + if (!CE || CE->getOpcode() != Instruction::PtrToInt) + continue; + for (Use &U : make_early_inc_range(CE->uses())) { + auto *CE = dyn_cast<ConstantExpr>(U.getUser()); + if (U.getOperandNo() == 1 && CE && + CE->getOpcode() == Instruction::Sub && + MaySimplify(CE->getOperand(0))) { + // This is a computation of PtrOffset as generated by + // LowerTypeTestsModule::lowerTypeTestCall above. If + // isKnownTypeIdMember passes we just pretend it evaluated to 0. This + // should cause later passes to remove the range and alignment checks. + // The bitset checks won't be removed but those are uncommon. + CE->replaceAllUsesWith(ConstantInt::get(CE->getType(), 0)); + Changed = true; + } + auto *CI = dyn_cast<ICmpInst>(U.getUser()); + if (U.getOperandNo() == 1 && CI && + CI->getPredicate() == CmpInst::ICMP_EQ && + MaySimplify(CI->getOperand(0))) { + // This is an equality comparison (TypeTestResolution::Single case in + // lowerTypeTestCall). In this case we just replace the comparison + // with true. + CI->replaceAllUsesWith(ConstantInt::getTrue(M.getContext())); + CI->eraseFromParent(); + Changed = true; + } + } + } + } + + if (!Changed) + return PreservedAnalyses::all(); + return PreservedAnalyses::none(); +} `````````` </details> https://github.com/llvm/llvm-project/pull/141327 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits