1 //===- StripGCRelocates.cpp - Remove gc.relocates inserted by RewriteStatePoints===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This is a little utility pass that removes the gc.relocates inserted by 10 // RewriteStatepointsForGC. Note that the generated IR is incorrect, 11 // but this is useful as a single pass in itself, for analysis of IR, without 12 // the GC.relocates. The statepoint and gc.result intrinsics would still be 13 // present. 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/Transforms/Utils/StripGCRelocates.h" 17 #include "llvm/IR/Function.h" 18 #include "llvm/IR/InstIterator.h" 19 #include "llvm/IR/Instructions.h" 20 #include "llvm/IR/Statepoint.h" 21 #include "llvm/InitializePasses.h" 22 #include "llvm/Pass.h" 23 24 using namespace llvm; 25 26 static bool stripGCRelocates(Function &F) { 27 // Nothing to do for declarations. 28 if (F.isDeclaration()) 29 return false; 30 SmallVector<GCRelocateInst *, 20> GCRelocates; 31 // TODO: We currently do not handle gc.relocates that are in landing pads, 32 // i.e. not bound to a single statepoint token. 33 for (Instruction &I : instructions(F)) { 34 if (auto *GCR = dyn_cast<GCRelocateInst>(&I)) 35 if (isa<GCStatepointInst>(GCR->getOperand(0))) 36 GCRelocates.push_back(GCR); 37 } 38 // All gc.relocates are bound to a single statepoint token. The order of 39 // visiting gc.relocates for deletion does not matter. 40 for (GCRelocateInst *GCRel : GCRelocates) { 41 Value *OrigPtr = GCRel->getDerivedPtr(); 42 Value *ReplaceGCRel = OrigPtr; 43 44 // All gc_relocates are i8 addrspace(1)* typed, we need a bitcast from i8 45 // addrspace(1)* to the type of the OrigPtr, if the are not the same. 46 if (GCRel->getType() != OrigPtr->getType()) 47 ReplaceGCRel = new BitCastInst(OrigPtr, GCRel->getType(), "cast", GCRel); 48 49 // Replace all uses of gc.relocate and delete the gc.relocate 50 // There maybe unncessary bitcasts back to the OrigPtr type, an instcombine 51 // pass would clear this up. 52 GCRel->replaceAllUsesWith(ReplaceGCRel); 53 GCRel->eraseFromParent(); 54 } 55 return !GCRelocates.empty(); 56 } 57 58 PreservedAnalyses StripGCRelocates::run(Function &F, 59 FunctionAnalysisManager &AM) { 60 if (!stripGCRelocates(F)) 61 return PreservedAnalyses::all(); 62 63 // Removing gc.relocate preserves the CFG, but most other analysis probably 64 // need to re-run. 65 PreservedAnalyses PA; 66 PA.preserveSet<CFGAnalyses>(); 67 return PA; 68 } 69 70 namespace { 71 struct StripGCRelocatesLegacy : public FunctionPass { 72 static char ID; // Pass identification, replacement for typeid 73 StripGCRelocatesLegacy() : FunctionPass(ID) { 74 initializeStripGCRelocatesLegacyPass(*PassRegistry::getPassRegistry()); 75 } 76 77 void getAnalysisUsage(AnalysisUsage &Info) const override {} 78 79 bool runOnFunction(Function &F) override { return ::stripGCRelocates(F); } 80 }; 81 char StripGCRelocatesLegacy::ID = 0; 82 } // namespace 83 84 INITIALIZE_PASS(StripGCRelocatesLegacy, "strip-gc-relocates", 85 "Strip gc.relocates inserted through RewriteStatepointsForGC", 86 true, false) 87