JumpInstrTables.cpp [plain text]
#define DEBUG_TYPE "jt"
#include "llvm/CodeGen/JumpInstrTables.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/JumpInstrTableInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <vector>
using namespace llvm;
char JumpInstrTables::ID = 0;
INITIALIZE_PASS_BEGIN(JumpInstrTables, "jump-instr-tables",
"Jump-Instruction Tables", true, true)
INITIALIZE_PASS_DEPENDENCY(JumpInstrTableInfo);
INITIALIZE_PASS_END(JumpInstrTables, "jump-instr-tables",
"Jump-Instruction Tables", true, true)
STATISTIC(NumJumpTables, "Number of indirect call tables generated");
STATISTIC(NumFuncsInJumpTables, "Number of functions in the jump tables");
ModulePass *llvm::createJumpInstrTablesPass() {
return new JumpInstrTables(JumpTable::Single);
}
ModulePass *llvm::createJumpInstrTablesPass(JumpTable::JumpTableType JTT) {
return new JumpInstrTables(JTT);
}
namespace {
static const char jump_func_prefix[] = "__llvm_jump_instr_table_";
static const char jump_section_prefix[] = ".jump.instr.table.text.";
bool isIndirectCall(CallSite &CS) {
if (CS.getCalledFunction())
return false;
const Value *V = CS.getCalledValue();
if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
return !(CE->isCast() && isa<Function>(CE->getOperand(0)));
}
return true;
}
bool replaceGlobalValueIndirectUse(GlobalValue *GV, Value *V, Use *U) {
User *Us = U->getUser();
if (!Us)
return false;
if (Instruction *I = dyn_cast<Instruction>(Us)) {
CallSite CS(I);
if (CS && (isIndirectCall(CS) || CS.isCallee(U))) {
return false;
}
U->set(V);
} else if (Constant *C = dyn_cast<Constant>(Us)) {
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Us)) {
if (CE->getOpcode() == Instruction::BitCast) {
if (CE->user_begin() != CE->user_end()) {
User *ParentUs = *CE->user_begin();
if (CallInst *CI = dyn_cast<CallInst>(ParentUs)) {
CallSite CS(CI);
Use &CEU = *CE->use_begin();
if (CS.isCallee(&CEU)) {
return false;
}
}
}
}
}
if (!isa<GlobalAlias>(C))
C->replaceUsesOfWithOnConstant(GV, V, U);
} else {
assert(false && "The Use of a Function symbol is neither an instruction nor"
" a constant");
}
return true;
}
void replaceValueWithFunction(GlobalValue *GV, Function *F) {
for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I != E;) {
Use &U = *I++;
if (U.get() == GV)
replaceGlobalValueIndirectUse(GV, F, &U);
}
return;
}
}
JumpInstrTables::JumpInstrTables()
: ModulePass(ID), Metadata(), JITI(nullptr), TableCount(0),
JTType(JumpTable::Single) {
initializeJumpInstrTablesPass(*PassRegistry::getPassRegistry());
}
JumpInstrTables::JumpInstrTables(JumpTable::JumpTableType JTT)
: ModulePass(ID), Metadata(), JITI(nullptr), TableCount(0), JTType(JTT) {
initializeJumpInstrTablesPass(*PassRegistry::getPassRegistry());
}
JumpInstrTables::~JumpInstrTables() {}
void JumpInstrTables::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<JumpInstrTableInfo>();
}
Function *JumpInstrTables::insertEntry(Module &M, Function *Target) {
FunctionType *OrigFunTy = Target->getFunctionType();
FunctionType *FunTy = transformType(OrigFunTy);
JumpMap::iterator it = Metadata.find(FunTy);
if (Metadata.end() == it) {
struct TableMeta Meta;
Meta.TableNum = TableCount;
Meta.Count = 0;
Metadata[FunTy] = Meta;
it = Metadata.find(FunTy);
++NumJumpTables;
++TableCount;
}
it->second.Count++;
std::string NewName(jump_func_prefix);
NewName += (Twine(it->second.TableNum) + "_" + Twine(it->second.Count)).str();
Function *JumpFun =
Function::Create(OrigFunTy, GlobalValue::ExternalLinkage, NewName, &M);
JumpFun->setSection((jump_section_prefix + Twine(it->second.TableNum)).str());
JITI->insertEntry(FunTy, Target, JumpFun);
++NumFuncsInJumpTables;
return JumpFun;
}
bool JumpInstrTables::hasTable(FunctionType *FunTy) {
FunctionType *TransTy = transformType(FunTy);
return Metadata.end() != Metadata.find(TransTy);
}
FunctionType *JumpInstrTables::transformType(FunctionType *FunTy) {
Type *VoidPtrTy = Type::getInt8PtrTy(FunTy->getContext());
Type *RetTy = VoidPtrTy;
bool IsVarArg = FunTy->isVarArg();
std::vector<Type *> ParamTys(FunTy->getNumParams());
FunctionType::param_iterator PI, PE;
int i = 0;
std::vector<Type *> EmptyParams;
Type *Int32Ty = Type::getInt32Ty(FunTy->getContext());
FunctionType *VoidFnTy = FunctionType::get(
Type::getVoidTy(FunTy->getContext()), EmptyParams, false);
switch (JTType) {
case JumpTable::Single:
return FunctionType::get(RetTy, EmptyParams, false);
case JumpTable::Arity:
for (PI = FunTy->param_begin(), PE = FunTy->param_end(); PI != PE;
PI++, i++) {
ParamTys[i] = VoidPtrTy;
}
return FunctionType::get(RetTy, ParamTys, IsVarArg);
case JumpTable::Simplified:
for (PI = FunTy->param_begin(), PE = FunTy->param_end(); PI != PE;
++PI, ++i) {
assert((isa<IntegerType>(*PI) || isa<FunctionType>(*PI) ||
isa<CompositeType>(*PI)) &&
"This type is not an Integer or a Composite or a Function");
if (isa<CompositeType>(*PI)) {
ParamTys[i] = VoidPtrTy;
} else if (isa<FunctionType>(*PI)) {
ParamTys[i] = VoidFnTy;
} else if (isa<IntegerType>(*PI)) {
ParamTys[i] = Int32Ty;
}
}
return FunctionType::get(RetTy, ParamTys, IsVarArg);
case JumpTable::Full:
return FunTy;
}
return nullptr;
}
bool JumpInstrTables::runOnModule(Module &M) {
JITI = &getAnalysis<JumpInstrTableInfo>();
DenseMap<Function *, Function *> Functions;
for (Function &F : M) {
if (F.hasFnAttribute(Attribute::JumpTable)) {
assert(F.hasUnnamedAddr() &&
"Attribute 'jumptable' requires 'unnamed_addr'");
Functions[&F] = nullptr;
}
}
for (auto &KV : Functions) {
Function *F = KV.first;
KV.second = insertEntry(M, F);
}
DenseMap<GlobalAlias *, Function *> Aliases;
for (GlobalAlias &GA : M.aliases()) {
Constant *Aliasee = GA.getAliasee();
if (Function *F = dyn_cast<Function>(Aliasee)) {
auto it = Functions.find(F);
if (it != Functions.end()) {
Aliases[&GA] = it->second;
}
}
}
for (auto &KV : Functions)
replaceValueWithFunction(KV.first, KV.second);
for (auto &KV : Aliases)
replaceValueWithFunction(KV.first, KV.second);
return !Functions.empty();
}