// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
using namespace llvm;
static int kGCAddressSpace = 1;
bool IsManaged(AllocaInst* AI) {
auto* T = AI->getType();
// If it looks like a Handle, it probably is a Handle. This brittle way of
// checking for managed on-stack values returns true if a single element
// struct has a GC address-spaced pointer field.
if (T->getElementType()->isStructTy()) {
auto* ST = dyn_cast<StructType>(&*T->getElementType());
if (ST->getNumElements() == 1 && ST->getElementType(0)->isPointerTy()) {
if (ST->getElementType(0)->getPointerAddressSpace() == kGCAddressSpace)
return true;
}
}
return false;
}
namespace {
struct IdentifySafepoints : public FunctionPass {
static char ID;
IdentifySafepoints() : FunctionPass(ID) {}
bool runOnFunction(Function& F) override {
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
if (auto* AI = dyn_cast_or_null<AllocaInst>(&*I)) {
if (IsManaged(AI)) {
F.addFnAttr("statepoint");
return false;
}
}
}
return false;
}
};
char IdentifySafepoints::ID;
} // namespace
static RegisterPass<IdentifySafepoints> X("-identify-safepoints",
"Identify Safepoints",
false /* Only looks at CFG */,
true /* Analysis Pass */);
static RegisterStandardPasses Y(PassManagerBuilder::EP_EarlyAsPossible,
[](const PassManagerBuilder& Builder,
legacy::PassManagerBase& PM) {
PM.add(new IdentifySafepoints());
});