Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -293,6 +293,7 @@ void initializeRegionPrinterPass(PassRegistry&); void initializeRegionViewerPass(PassRegistry&); void initializeRegisterCoalescerPass(PassRegistry&); +void initializeRemoveGCRelocatesPass(PassRegistry&); void initializeRenameIndependentSubregsPass(PassRegistry&); void initializeResetMachineFunctionPass(PassRegistry &); void initializeReversePostOrderFunctionAttrsLegacyPassPass(PassRegistry&); Index: include/llvm/Transforms/Scalar.h =================================================================== --- include/llvm/Transforms/Scalar.h +++ include/llvm/Transforms/Scalar.h @@ -471,6 +471,13 @@ //===----------------------------------------------------------------------===// // +// RemoveGCRelocates - Remove GC relocates that have been inserted by +// RewriteStatepointsForGC. The resulting IR is incorrect, but this is useful +// for analysis +FunctionPass *createRemoveGCRelocatesPass(); + +//===----------------------------------------------------------------------===// +// // Float2Int - Demote floats to ints where possible. // FunctionPass *createFloat2IntPass(); Index: lib/Transforms/Utils/CMakeLists.txt =================================================================== --- lib/Transforms/Utils/CMakeLists.txt +++ lib/Transforms/Utils/CMakeLists.txt @@ -34,6 +34,7 @@ ModuleUtils.cpp NameAnonGlobals.cpp PromoteMemoryToRegister.cpp + RemoveGCRelocates.cpp SSAUpdater.cpp SanitizerStats.cpp SimplifyCFG.cpp Index: lib/Transforms/Utils/RemoveGCRelocates.cpp =================================================================== --- /dev/null +++ lib/Transforms/Utils/RemoveGCRelocates.cpp @@ -0,0 +1,107 @@ +//===- InstructionNamer.cpp - Give anonymous instructions names -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a little utility pass that removes the gc.relocates inserted by +// RewriteStatepointsForGC. Note that the generated IR would be incorrect, +// but this is useful as a single pass in itself, for analysis of IR, without +// the GC.relocates. The statepoint and gc.result instrinsics would still be +// present. +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Statepoint.h" +#include "llvm/IR/Type.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { +struct RemoveGCRelocates : public FunctionPass { + static char ID; // Pass identification, replacement for typeid + RemoveGCRelocates() : FunctionPass(ID) { + initializeRemoveGCRelocatesPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &Info) const override { + Info.setPreservesAll(); + } + + bool runOnFunction(Function &F) override; + +private: + SmallVector GCRelocates; +}; +char RemoveGCRelocates::ID = 0; +} + +bool RemoveGCRelocates::runOnFunction(Function &F) { + + // Nothing to do for declarations. + if (F.isDeclaration() || F.empty()) + return false; + GCRelocates.clear(); + for (Instruction &I : instructions(F)) { + ImmutableCallSite GCRel = ImmutableCallSite(&I); + if (!isGCRelocate(GCRel)) + continue; + GCRelocates.push_back(&I); + } + bool Changed = false; + // All gc.relocates are bound to a single statepoint token. The order of + // visiting gc.relocates for deletion does not matter. + for (Instruction *GCRel : GCRelocates) { + + // TODO: Handle gc.relocates in landing pads (these are not bound to the + // statepoint token). + if (!isStatepoint(GCRel->getOperand(0))) + continue; + ConstantInt *LiveIdx = cast(GCRel->getOperand(2)); + Instruction *Statepoint = dyn_cast(GCRel->getOperand(0)); + if (!Statepoint) + continue; + Value *OrigPtr = Statepoint->getOperand(LiveIdx->getZExtValue()); + + Instruction *ToBeReplaced = GCRel; + // All gc_relocates are i8 addrspace(1)* typed, and may be bitcasted to + // the correct type of the original pointer (if they are not the same). + // TODO: Handle gc.relocates that are of different type from original + // pointer, but all uses are the gc.relocate of i8 addrspace(1)* type. + if (GCRel->getType() != OrigPtr->getType()) { + if (GCRel->hasOneUse() && isa(GCRel->user_back())) + ToBeReplaced = GCRel->user_back(); + else + continue; + } + assert(ToBeReplaced->getType() == OrigPtr->getType() && + "Should have same types!"); + // Replace all uses and delete the relocate (and bitcast'ed version, if + // necessary). + ToBeReplaced->replaceAllUsesWith(OrigPtr); + if (GCRel != ToBeReplaced) { + ToBeReplaced->eraseFromParent(); + // Only the bitcast of the gc.relocate was deleted above, we also need + // to delete the gc.relocate itself. + GCRel->eraseFromParent(); + } else + ToBeReplaced->eraseFromParent(); + Changed = true; + } + return Changed; +} + +INITIALIZE_PASS(RemoveGCRelocates, "remove-gc-relocates", + "Remove gc.relocates inserted through RewriteStatepointsForGC", + true, false) +FunctionPass *llvm::createRemoveGCRelocatesPass() { + return new RemoveGCRelocates(); +} Index: lib/Transforms/Utils/Utils.cpp =================================================================== --- lib/Transforms/Utils/Utils.cpp +++ lib/Transforms/Utils/Utils.cpp @@ -35,6 +35,7 @@ initializeMetaRenamerPass(Registry); initializeMemorySSAWrapperPassPass(Registry); initializeMemorySSAPrinterLegacyPassPass(Registry); + initializeRemoveGCRelocatesPass(Registry); } /// LLVMInitializeTransformUtils - C binding for initializeTransformUtilsPasses.