|
19 | 19 | #include "llvm/ADT/DenseMap.h" |
20 | 20 | #include "llvm/ADT/EquivalenceClasses.h" |
21 | 21 | #include "llvm/ADT/PointerUnion.h" |
| 22 | +#include "llvm/ADT/STLExtras.h" |
22 | 23 | #include "llvm/ADT/SetVector.h" |
23 | 24 | #include "llvm/ADT/SmallVector.h" |
24 | 25 | #include "llvm/ADT/Statistic.h" |
25 | 26 | #include "llvm/ADT/StringRef.h" |
26 | 27 | #include "llvm/ADT/TinyPtrVector.h" |
| 28 | +#include "llvm/Analysis/LoopInfo.h" |
| 29 | +#include "llvm/Analysis/PostDominators.h" |
27 | 30 | #include "llvm/Analysis/TargetTransformInfo.h" |
28 | 31 | #include "llvm/Analysis/TypeMetadataUtils.h" |
29 | 32 | #include "llvm/Analysis/ValueTracking.h" |
@@ -779,9 +782,8 @@ Value *LowerTypeTestsModule::lowerTypeTestCall(Metadata *TypeId, CallInst *CI, |
779 | 782 | // result, causing the comparison to fail if they are nonzero. The rotate |
780 | 783 | // also conveniently gives us a bit offset to use during the load from |
781 | 784 | // the bitset. |
782 | | - Value *BitOffset = B.CreateIntrinsic( |
783 | | - IntPtrTy, Intrinsic::fshr, |
784 | | - {PtrOffset, PtrOffset, B.CreateZExt(TIL.AlignLog2, IntPtrTy)}); |
| 785 | + Value *BitOffset = B.CreateIntrinsic(IntPtrTy, Intrinsic::fshr, |
| 786 | + {PtrOffset, PtrOffset, TIL.AlignLog2}); |
785 | 787 |
|
786 | 788 | Value *OffsetInRange = B.CreateICmpULE(BitOffset, TIL.SizeM1); |
787 | 789 |
|
@@ -1033,7 +1035,7 @@ LowerTypeTestsModule::importTypeId(StringRef TypeId) { |
1033 | 1035 | if (TIL.TheKind == TypeTestResolution::ByteArray || |
1034 | 1036 | TIL.TheKind == TypeTestResolution::Inline || |
1035 | 1037 | TIL.TheKind == TypeTestResolution::AllOnes) { |
1036 | | - TIL.AlignLog2 = ImportConstant("align", TTRes.AlignLog2, 8, Int8Ty); |
| 1038 | + TIL.AlignLog2 = ImportConstant("align", TTRes.AlignLog2, 8, IntPtrTy); |
1037 | 1039 | TIL.SizeM1 = |
1038 | 1040 | ImportConstant("size_m1", TTRes.SizeM1, TTRes.SizeM1BitWidth, IntPtrTy); |
1039 | 1041 | } |
@@ -1154,7 +1156,7 @@ void LowerTypeTestsModule::lowerTypeTestCalls( |
1154 | 1156 | TypeIdLowering TIL; |
1155 | 1157 | TIL.OffsetedGlobal = ConstantExpr::getGetElementPtr( |
1156 | 1158 | Int8Ty, CombinedGlobalAddr, ConstantInt::get(IntPtrTy, BSI.ByteOffset)), |
1157 | | - TIL.AlignLog2 = ConstantInt::get(Int8Ty, BSI.AlignLog2); |
| 1159 | + TIL.AlignLog2 = ConstantInt::get(IntPtrTy, BSI.AlignLog2); |
1158 | 1160 | TIL.SizeM1 = ConstantInt::get(IntPtrTy, BSI.BitSize - 1); |
1159 | 1161 | if (BSI.isAllOnes()) { |
1160 | 1162 | TIL.TheKind = (BSI.BitSize == 1) ? TypeTestResolution::Single |
@@ -2472,3 +2474,93 @@ PreservedAnalyses LowerTypeTestsPass::run(Module &M, |
2472 | 2474 | return PreservedAnalyses::all(); |
2473 | 2475 | return PreservedAnalyses::none(); |
2474 | 2476 | } |
| 2477 | + |
| 2478 | +PreservedAnalyses SimplifyTypeTestsPass::run(Module &M, |
| 2479 | + ModuleAnalysisManager &AM) { |
| 2480 | + bool Changed = false; |
| 2481 | + // Figure out whether inlining has exposed a constant address to a lowered |
| 2482 | + // type test, and remove the test if so and the address is known to pass the |
| 2483 | + // test. Unfortunately this pass ends up needing to reverse engineer what |
| 2484 | + // LowerTypeTests did; this is currently inherent to the design of ThinLTO |
| 2485 | + // importing where LowerTypeTests needs to run at the start. |
| 2486 | + // |
| 2487 | + // We look for things like: |
| 2488 | + // |
| 2489 | + // sub (i64 ptrtoint (ptr @_Z2fpv to i64), i64 ptrtoint (ptr @__typeid__ZTSFvvE_global_addr to i64)) |
| 2490 | + // |
| 2491 | + // which gets replaced with 0 if _Z2fpv (more specifically _Z2fpv.cfi, the |
| 2492 | + // function referred to by the jump table) is a member of the type _ZTSFvv, as |
| 2493 | + // well as things like |
| 2494 | + // |
| 2495 | + // icmp eq ptr @_Z2fpv, @__typeid__ZTSFvvE_global_addr |
| 2496 | + // |
| 2497 | + // which gets replaced with true if _Z2fpv is a member. |
| 2498 | + for (auto &GV : M.globals()) { |
| 2499 | + if (!GV.getName().starts_with("__typeid_") || |
| 2500 | + !GV.getName().ends_with("_global_addr")) |
| 2501 | + continue; |
| 2502 | + // __typeid_foo_global_addr -> foo |
| 2503 | + auto *MD = MDString::get(M.getContext(), |
| 2504 | + GV.getName().substr(9, GV.getName().size() - 21)); |
| 2505 | + auto MaySimplifyPtr = [&](Value *Ptr) { |
| 2506 | + if (auto *GV = dyn_cast<GlobalValue>(Ptr)) |
| 2507 | + if (auto *CFIGV = M.getNamedValue((GV->getName() + ".cfi").str())) |
| 2508 | + Ptr = CFIGV; |
| 2509 | + return isKnownTypeIdMember(MD, M.getDataLayout(), Ptr, 0); |
| 2510 | + }; |
| 2511 | + auto MaySimplifyInt = [&](Value *Op) { |
| 2512 | + auto *PtrAsInt = dyn_cast<ConstantExpr>(Op); |
| 2513 | + if (!PtrAsInt || PtrAsInt->getOpcode() != Instruction::PtrToInt) |
| 2514 | + return false; |
| 2515 | + return MaySimplifyPtr(PtrAsInt->getOperand(0)); |
| 2516 | + }; |
| 2517 | + for (User *U : make_early_inc_range(GV.users())) { |
| 2518 | + if (auto *CI = dyn_cast<ICmpInst>(U)) { |
| 2519 | + if (CI->getPredicate() == CmpInst::ICMP_EQ && |
| 2520 | + MaySimplifyPtr(CI->getOperand(0))) { |
| 2521 | + // This is an equality comparison (TypeTestResolution::Single case in |
| 2522 | + // lowerTypeTestCall). In this case we just replace the comparison |
| 2523 | + // with true. |
| 2524 | + CI->replaceAllUsesWith(ConstantInt::getTrue(M.getContext())); |
| 2525 | + CI->eraseFromParent(); |
| 2526 | + Changed = true; |
| 2527 | + } |
| 2528 | + } |
| 2529 | + auto *CE = dyn_cast<ConstantExpr>(U); |
| 2530 | + if (!CE || CE->getOpcode() != Instruction::PtrToInt) |
| 2531 | + continue; |
| 2532 | + for (Use &U : make_early_inc_range(CE->uses())) { |
| 2533 | + auto *CE = dyn_cast<ConstantExpr>(U.getUser()); |
| 2534 | + if (U.getOperandNo() == 1 && CE && |
| 2535 | + CE->getOpcode() == Instruction::Sub && |
| 2536 | + MaySimplifyInt(CE->getOperand(0))) { |
| 2537 | + // This is a computation of PtrOffset as generated by |
| 2538 | + // LowerTypeTestsModule::lowerTypeTestCall above. If |
| 2539 | + // isKnownTypeIdMember passes we just pretend it evaluated to 0. This |
| 2540 | + // should cause later passes to remove the range and alignment checks. |
| 2541 | + // The bitset checks won't be removed but those are uncommon. |
| 2542 | + CE->replaceAllUsesWith(ConstantInt::get(CE->getType(), 0)); |
| 2543 | + Changed = true; |
| 2544 | + } |
| 2545 | + auto *CI = dyn_cast<ICmpInst>(U.getUser()); |
| 2546 | + if (U.getOperandNo() == 1 && CI && |
| 2547 | + CI->getPredicate() == CmpInst::ICMP_EQ && |
| 2548 | + MaySimplifyInt(CI->getOperand(0))) { |
| 2549 | + // This is an equality comparison. Unlike in the case above it |
| 2550 | + // remained as an integer compare. |
| 2551 | + CI->replaceAllUsesWith(ConstantInt::getTrue(M.getContext())); |
| 2552 | + CI->eraseFromParent(); |
| 2553 | + Changed = true; |
| 2554 | + } |
| 2555 | + } |
| 2556 | + } |
| 2557 | + } |
| 2558 | + |
| 2559 | + if (!Changed) |
| 2560 | + return PreservedAnalyses::all(); |
| 2561 | + PreservedAnalyses PA = PreservedAnalyses::none(); |
| 2562 | + PA.preserve<DominatorTreeAnalysis>(); |
| 2563 | + PA.preserve<PostDominatorTreeAnalysis>(); |
| 2564 | + PA.preserve<LoopAnalysis>(); |
| 2565 | + return PA; |
| 2566 | +} |
0 commit comments