10b57cec5SDimitry Andric //===- StripGCRelocates.cpp - Remove gc.relocates inserted by RewriteStatePoints===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This is a little utility pass that removes the gc.relocates inserted by
100b57cec5SDimitry Andric // RewriteStatepointsForGC. Note that the generated IR is incorrect,
110b57cec5SDimitry Andric // but this is useful as a single pass in itself, for analysis of IR, without
120b57cec5SDimitry Andric // the GC.relocates. The statepoint and gc.result instrinsics would still be
130b57cec5SDimitry Andric // present.
140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
150b57cec5SDimitry Andric
16*af732203SDimitry Andric #include "llvm/Transforms/Utils/StripGCRelocates.h"
170b57cec5SDimitry Andric #include "llvm/IR/Function.h"
180b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h"
190b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
200b57cec5SDimitry Andric #include "llvm/IR/Statepoint.h"
210b57cec5SDimitry Andric #include "llvm/IR/Type.h"
22480093f4SDimitry Andric #include "llvm/InitializePasses.h"
230b57cec5SDimitry Andric #include "llvm/Pass.h"
240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric
stripGCRelocates(Function & F)28*af732203SDimitry Andric static bool stripGCRelocates(Function &F) {
290b57cec5SDimitry Andric // Nothing to do for declarations.
300b57cec5SDimitry Andric if (F.isDeclaration())
310b57cec5SDimitry Andric return false;
320b57cec5SDimitry Andric SmallVector<GCRelocateInst *, 20> GCRelocates;
330b57cec5SDimitry Andric // TODO: We currently do not handle gc.relocates that are in landing pads,
340b57cec5SDimitry Andric // i.e. not bound to a single statepoint token.
350b57cec5SDimitry Andric for (Instruction &I : instructions(F)) {
360b57cec5SDimitry Andric if (auto *GCR = dyn_cast<GCRelocateInst>(&I))
375ffd83dbSDimitry Andric if (isa<GCStatepointInst>(GCR->getOperand(0)))
380b57cec5SDimitry Andric GCRelocates.push_back(GCR);
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric // All gc.relocates are bound to a single statepoint token. The order of
410b57cec5SDimitry Andric // visiting gc.relocates for deletion does not matter.
420b57cec5SDimitry Andric for (GCRelocateInst *GCRel : GCRelocates) {
430b57cec5SDimitry Andric Value *OrigPtr = GCRel->getDerivedPtr();
440b57cec5SDimitry Andric Value *ReplaceGCRel = OrigPtr;
450b57cec5SDimitry Andric
460b57cec5SDimitry Andric // All gc_relocates are i8 addrspace(1)* typed, we need a bitcast from i8
470b57cec5SDimitry Andric // addrspace(1)* to the type of the OrigPtr, if the are not the same.
480b57cec5SDimitry Andric if (GCRel->getType() != OrigPtr->getType())
490b57cec5SDimitry Andric ReplaceGCRel = new BitCastInst(OrigPtr, GCRel->getType(), "cast", GCRel);
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric // Replace all uses of gc.relocate and delete the gc.relocate
520b57cec5SDimitry Andric // There maybe unncessary bitcasts back to the OrigPtr type, an instcombine
530b57cec5SDimitry Andric // pass would clear this up.
540b57cec5SDimitry Andric GCRel->replaceAllUsesWith(ReplaceGCRel);
550b57cec5SDimitry Andric GCRel->eraseFromParent();
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric return !GCRelocates.empty();
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
run(Function & F,FunctionAnalysisManager & AM)60*af732203SDimitry Andric PreservedAnalyses StripGCRelocates::run(Function &F,
61*af732203SDimitry Andric FunctionAnalysisManager &AM) {
62*af732203SDimitry Andric if (!stripGCRelocates(F))
63*af732203SDimitry Andric return PreservedAnalyses::all();
64*af732203SDimitry Andric
65*af732203SDimitry Andric // Removing gc.relocate preserves the CFG, but most other analysis probably
66*af732203SDimitry Andric // need to re-run.
67*af732203SDimitry Andric PreservedAnalyses PA;
68*af732203SDimitry Andric PA.preserveSet<CFGAnalyses>();
69*af732203SDimitry Andric return PA;
70*af732203SDimitry Andric }
71*af732203SDimitry Andric
72*af732203SDimitry Andric namespace {
73*af732203SDimitry Andric struct StripGCRelocatesLegacy : public FunctionPass {
74*af732203SDimitry Andric static char ID; // Pass identification, replacement for typeid
StripGCRelocatesLegacy__anondbaf39600111::StripGCRelocatesLegacy75*af732203SDimitry Andric StripGCRelocatesLegacy() : FunctionPass(ID) {
76*af732203SDimitry Andric initializeStripGCRelocatesLegacyPass(*PassRegistry::getPassRegistry());
77*af732203SDimitry Andric }
78*af732203SDimitry Andric
getAnalysisUsage__anondbaf39600111::StripGCRelocatesLegacy79*af732203SDimitry Andric void getAnalysisUsage(AnalysisUsage &Info) const override {}
80*af732203SDimitry Andric
runOnFunction__anondbaf39600111::StripGCRelocatesLegacy81*af732203SDimitry Andric bool runOnFunction(Function &F) override { return ::stripGCRelocates(F); }
82*af732203SDimitry Andric };
83*af732203SDimitry Andric char StripGCRelocatesLegacy::ID = 0;
84*af732203SDimitry Andric } // namespace
85*af732203SDimitry Andric
86*af732203SDimitry Andric INITIALIZE_PASS(StripGCRelocatesLegacy, "strip-gc-relocates",
870b57cec5SDimitry Andric "Strip gc.relocates inserted through RewriteStatepointsForGC",
880b57cec5SDimitry Andric true, false)
89