blob: 956d82e7f3bc29bedb9c3f0009a3e352cb0fd833 [file] [log] [blame] [edit]
//===- PromoteIntegers.cpp - Promote illegal integers for PNaCl ABI -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// A limited set of transformations to promote illegal-sized int types.
//
//===----------------------------------------------------------------------===//
//
// Legal sizes are currently 1, 8, and large power-of-two sizes. Operations on
// illegal integers are changed to operate on the next-higher legal size.
//
// It maintains no invariants about the upper bits (above the size of the
// original type); therefore before operations which can be affected by the
// value of these bits (e.g. cmp, select, lshr), the upper bits of the operands
// are cleared.
//
// Limitations:
// 1) It can't change function signatures or global variables
// 2) Doesn't handle arrays or structs with illegal types
// 3) Doesn't handle constant expressions (it also doesn't produce them, so it
// can run after ExpandConstantExpr)
//
//===----------------------------------------------------------------------===//
#include "SimplifiedFuncTypeMap.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/NaCl.h"
using namespace llvm;
static Type *getPromotedType(Type *Ty);
namespace {
class TypeMap : public SimplifiedFuncTypeMap {
protected:
MappingResult getSimpleFuncType(LLVMContext &Ctx, StructMap &Tentatives,
FunctionType *OldFnTy) override {
ParamTypeVector NewArgTypes;
auto Ret = getPromotedArgType(Ctx, OldFnTy->getReturnType(), Tentatives);
bool Changed = Ret.isChanged();
for (auto &ArgTy : OldFnTy->params()) {
auto NewArgTy = getPromotedArgType(Ctx, ArgTy, Tentatives);
NewArgTypes.push_back(NewArgTy);
Changed |= NewArgTy.isChanged();
}
auto *NewFctType = FunctionType::get(Ret, NewArgTypes, OldFnTy->isVarArg());
return {NewFctType, Changed};
}
private:
MappingResult getPromotedArgType(LLVMContext &Ctx, Type *Ty,
StructMap &Tentatives) {
if (Ty->isIntegerTy()) {
auto *NTy = getPromotedType(Ty);
return {NTy, NTy != Ty};
}
return getSimpleAggregateTypeInternal(Ctx, Ty, Tentatives);
}
};
class PromoteIntegers : public ModulePass {
public:
static char ID;
PromoteIntegers() : ModulePass(ID) {
initializePromoteIntegersPass(*PassRegistry::getPassRegistry());
}
bool runOnModule(Module &M) override;
private:
typedef DenseMap<const llvm::Function *, DISubprogram> DebugMap;
TypeMap TypeMapper;
bool ensureCompliantSignature(LLVMContext &Ctx, Function *OldFct, Module &M,
DebugMap &DISubprogramMap);
};
} // anonymous namespace
char PromoteIntegers::ID = 0;
INITIALIZE_PASS(PromoteIntegers, "nacl-promote-ints",
"Promote integer types which are illegal in PNaCl", false,
false)
static bool isLegalSize(unsigned Size) {
return Size == 1 || (Size >= 8 && isPowerOf2_32(Size));
}
static Type *getPromotedIntType(IntegerType *Ty) {
auto Width = Ty->getBitWidth();
if (isLegalSize(Width))
return Ty;
assert(Width < (1ull << (sizeof(Width) * CHAR_BIT - 1)) &&
"width can't be rounded to the next power of two");
return IntegerType::get(Ty->getContext(),
Width < 8 ? 8 : NextPowerOf2(Width));
}
// Return a legal integer type, promoting to a larger size if necessary.
static Type *getPromotedType(Type *Ty) {
assert(isa<IntegerType>(Ty) && "Trying to convert a non-integer type");
return getPromotedIntType(cast<IntegerType>(Ty));
}
// Return true if Val is an int which should be converted.
static bool shouldConvert(Value *Val) {
if (auto *ITy = dyn_cast<IntegerType>(Val->getType()))
return !isLegalSize(ITy->getBitWidth());
return false;
}
// Return a constant which has been promoted to a legal size.
static Value *convertConstant(Constant *C, bool SignExt) {
assert(shouldConvert(C));
Type *ProTy = getPromotedType(C->getType());
// ConstantExpr of a Constant yields a Constant, not a ConstantExpr.
return SignExt ? ConstantExpr::getSExt(C, ProTy)
: ConstantExpr::getZExt(C, ProTy);
}
namespace {
// Holds the state for converting/replacing values. Conversion is done in one
// pass, with each value requiring conversion possibly having two stages. When
// an instruction needs to be replaced (i.e. it has illegal operands or result)
// a new instruction is created, and the pass calls getConverted to get its
// operands. If the original operand has already been converted, the new value
// is returned. Otherwise, a placeholder is created and used in the new
// instruction. After a new instruction is created to replace an illegal one,
// recordConverted is called to register the replacement. All users are updated,
// and if there is a placeholder, its users are also updated.
//
// recordConverted also queues the old value for deletion.
//
// This strategy avoids the need for recursion or worklists for conversion.
class ConversionState {
public:
// Return the promoted value for Val. If Val has not yet been converted,
// return a placeholder, which will be converted later.
Value *getConverted(Value *Val) {
if (!shouldConvert(Val))
return Val;
if (isa<GlobalVariable>(Val))
report_fatal_error("Can't convert illegal GlobalVariables");
if (RewrittenMap.count(Val))
return RewrittenMap[Val];
// Directly convert constants.
if (auto *C = dyn_cast<Constant>(Val))
return convertConstant(C, /*SignExt=*/false);
// No converted value available yet, so create a placeholder.
auto *P = new Argument(getPromotedType(Val->getType()));
RewrittenMap[Val] = P;
Placeholders[Val] = P;
return P;
}
// Replace the uses of From with To, replace the uses of any
// placeholders for From, and optionally give From's name to To.
// Also mark To for deletion.
void recordConverted(Instruction *From, Value *To, bool TakeName = true) {
ToErase.push_back(From);
if (!shouldConvert(From)) {
// From does not produce an illegal value, update its users in place.
From->replaceAllUsesWith(To);
} else {
// From produces an illegal value, so its users will be replaced. When
// replacements are created they will use values returned by getConverted.
if (Placeholders.count(From)) {
// Users of the placeholder can be updated in place.
Placeholders[From]->replaceAllUsesWith(To);
Placeholders.erase(From);
}
RewrittenMap[From] = To;
}
if (TakeName) {
To->takeName(From);
}
}
void eraseReplacedInstructions() {
for (Instruction *E : ToErase)
E->dropAllReferences();
for (Instruction *E : ToErase)
E->eraseFromParent();
}
private:
// Maps illegal values to their new converted values (or placeholders
// if no new value is available yet)
DenseMap<Value *, Value *> RewrittenMap;
// Maps illegal values with no conversion available yet to their placeholders
DenseMap<Value *, Value *> Placeholders;
// Illegal values which have already been converted, will be erased.
SmallVector<Instruction *, 8> ToErase;
};
} // anonymous namespace
// Create a BitCast instruction from the original Value being cast. These
// instructions aren't replaced by convertInstruction because they are pointer
// types (which are always valid), but their uses eventually lead to an invalid
// type.
static Value *CreateBitCast(IRBuilder<> *IRB, Value *From, Type *ToTy,
const Twine &Name) {
if (auto *BC = dyn_cast<BitCastInst>(From))
return CreateBitCast(IRB, BC->getOperand(0), ToTy, Name);
return IRB->CreateBitCast(From, ToTy, Name);
}
// Split an illegal load into multiple legal loads and return the resulting
// promoted value. The size of the load is assumed to be a multiple of 8.
//
// \param BaseAlign Alignment of the base load.
// \param Offset Offset from the base load.
static Value *splitLoad(DataLayout *DL, LoadInst *Inst, ConversionState &State,
unsigned BaseAlign, unsigned Offset) {
if (Inst->isVolatile() || Inst->isAtomic())
report_fatal_error("Can't split volatile/atomic loads");
if (DL->getTypeSizeInBits(Inst->getType()) % 8 != 0)
report_fatal_error("Loads must be a multiple of 8 bits");
auto *OrigPtr = State.getConverted(Inst->getPointerOperand());
// OrigPtr is a placeholder in recursive calls, and so has no name.
if (OrigPtr->getName().empty())
OrigPtr->setName(Inst->getPointerOperand()->getName());
unsigned Width = DL->getTypeSizeInBits(Inst->getType());
auto *NewType = getPromotedType(Inst->getType());
unsigned LoWidth = PowerOf2Floor(Width);
assert(isLegalSize(LoWidth));
auto *LoType = IntegerType::get(Inst->getContext(), LoWidth);
auto *HiType = IntegerType::get(Inst->getContext(), Width - LoWidth);
IRBuilder<> IRB(Inst);
auto *BCLo = CreateBitCast(&IRB, OrigPtr, LoType->getPointerTo(),
OrigPtr->getName() + ".loty");
auto *LoadLo = IRB.CreateAlignedLoad(BCLo, MinAlign(BaseAlign, Offset),
Inst->getName() + ".lo");
auto *LoExt = IRB.CreateZExt(LoadLo, NewType, LoadLo->getName() + ".ext");
auto *GEPHi = IRB.CreateConstGEP1_32(BCLo, 1, OrigPtr->getName() + ".hi");
auto *BCHi = CreateBitCast(&IRB, GEPHi, HiType->getPointerTo(),
OrigPtr->getName() + ".hity");
auto HiOffset = (Offset + LoWidth) / CHAR_BIT;
auto *LoadHi = IRB.CreateAlignedLoad(BCHi, MinAlign(BaseAlign, HiOffset),
Inst->getName() + ".hi");
auto *Hi = !isLegalSize(Width - LoWidth)
? splitLoad(DL, LoadHi, State, BaseAlign, HiOffset)
: LoadHi;
auto *HiExt = IRB.CreateZExt(Hi, NewType, Hi->getName() + ".ext");
auto *HiShift = IRB.CreateShl(HiExt, LoWidth, HiExt->getName() + ".sh");
auto *Result = IRB.CreateOr(LoExt, HiShift);
State.recordConverted(Inst, Result);
return Result;
}
static Value *splitStore(DataLayout *DL, StoreInst *Inst,
ConversionState &State, unsigned BaseAlign,
unsigned Offset) {
if (Inst->isVolatile() || Inst->isAtomic())
report_fatal_error("Can't split volatile/atomic stores");
if (DL->getTypeSizeInBits(Inst->getValueOperand()->getType()) % 8 != 0)
report_fatal_error("Stores must be a multiple of 8 bits");
auto *OrigPtr = State.getConverted(Inst->getPointerOperand());
// OrigPtr is now a placeholder in recursive calls, and so has no name.
if (OrigPtr->getName().empty())
OrigPtr->setName(Inst->getPointerOperand()->getName());
auto *OrigVal = State.getConverted(Inst->getValueOperand());
unsigned Width = DL->getTypeSizeInBits(Inst->getValueOperand()->getType());
unsigned LoWidth = PowerOf2Floor(Width);
assert(isLegalSize(LoWidth));
auto *LoType = IntegerType::get(Inst->getContext(), LoWidth);
auto *HiType = IntegerType::get(Inst->getContext(), Width - LoWidth);
IRBuilder<> IRB(Inst);
auto *BCLo = CreateBitCast(&IRB, OrigPtr, LoType->getPointerTo(),
OrigPtr->getName() + ".loty");
auto *LoTrunc = IRB.CreateTrunc(OrigVal, LoType, OrigVal->getName() + ".lo");
IRB.CreateAlignedStore(LoTrunc, BCLo, MinAlign(BaseAlign, Offset));
auto HiOffset = (Offset + LoWidth) / CHAR_BIT;
auto *HiLShr =
IRB.CreateLShr(OrigVal, LoWidth, OrigVal->getName() + ".hi.sh");
auto *GEPHi = IRB.CreateConstGEP1_32(BCLo, 1, OrigPtr->getName() + ".hi");
auto *HiTrunc = IRB.CreateTrunc(HiLShr, HiType, OrigVal->getName() + ".hi");
auto *BCHi = CreateBitCast(&IRB, GEPHi, HiType->getPointerTo(),
OrigPtr->getName() + ".hity");
auto *StoreHi =
IRB.CreateAlignedStore(HiTrunc, BCHi, MinAlign(BaseAlign, HiOffset));
Value *Hi = StoreHi;
if (!isLegalSize(Width - LoWidth)) {
// HiTrunc is still illegal, and is redundant with the truncate in the
// recursive call, so just get rid of it. If HiTrunc is a constant then the
// IRB will have just returned a shifted, truncated constant, which is
// already uniqued (and does not need to be RAUWed), and recordConverted
// expects constants.
if (!isa<Constant>(HiTrunc))
State.recordConverted(cast<Instruction>(HiTrunc), HiLShr,
/*TakeName=*/false);
Hi = splitStore(DL, StoreHi, State, BaseAlign, HiOffset);
}
State.recordConverted(Inst, Hi, /*TakeName=*/false);
return Hi;
}
// Return a converted value with the bits of the operand above the size of the
// original type cleared.
static Value *getClearConverted(Value *Operand, Instruction *InsertPt,
ConversionState &State) {
auto *OrigType = Operand->getType();
auto *OrigInst = dyn_cast<Instruction>(Operand);
Operand = State.getConverted(Operand);
// If the operand is a constant, it will have been created by
// ConversionState.getConverted, which zero-extends by default.
if (isa<Constant>(Operand))
return Operand;
Instruction *NewInst = BinaryOperator::Create(
Instruction::And, Operand,
ConstantInt::get(
getPromotedType(OrigType),
APInt::getLowBitsSet(getPromotedType(OrigType)->getIntegerBitWidth(),
OrigType->getIntegerBitWidth())),
Operand->getName() + ".clear", InsertPt);
if (OrigInst)
CopyDebug(NewInst, OrigInst);
return NewInst;
}
// Return a value with the bits of the operand above the size of the original
// type equal to the sign bit of the original operand. The new operand is
// assumed to have been legalized already.
// This is done by shifting the sign bit of the smaller value up to the MSB
// position in the larger size, and then arithmetic-shifting it back down.
static Value *getSignExtend(Value *Operand, Value *OrigOperand,
Instruction *InsertPt) {
// If OrigOperand was a constant, NewOperand will have been created by
// ConversionState.getConverted, which zero-extends by default. But that is
// wrong here, so replace it with a sign-extended constant.
if (Constant *C = dyn_cast<Constant>(OrigOperand))
return convertConstant(C, /*SignExt=*/true);
Type *OrigType = OrigOperand->getType();
ConstantInt *ShiftAmt =
ConstantInt::getSigned(cast<IntegerType>(getPromotedType(OrigType)),
getPromotedType(OrigType)->getIntegerBitWidth() -
OrigType->getIntegerBitWidth());
BinaryOperator *Shl =
BinaryOperator::Create(Instruction::Shl, Operand, ShiftAmt,
Operand->getName() + ".getsign", InsertPt);
if (Instruction *Inst = dyn_cast<Instruction>(OrigOperand))
CopyDebug(Shl, Inst);
return CopyDebug(BinaryOperator::Create(Instruction::AShr, Shl, ShiftAmt,
Operand->getName() + ".signed",
InsertPt),
Shl);
}
static void convertInstruction(DataLayout *DL, Instruction *Inst,
ConversionState &State) {
if (SExtInst *Sext = dyn_cast<SExtInst>(Inst)) {
Value *Op = Sext->getOperand(0);
Value *NewInst = nullptr;
// If the operand to be extended is illegal, we first need to fill its
// upper bits with its sign bit.
if (shouldConvert(Op)) {
NewInst = getSignExtend(State.getConverted(Op), Op, Sext);
}
// If the converted type of the operand is the same as the converted
// type of the result, we won't actually be changing the type of the
// variable, just its value.
if (getPromotedType(Op->getType()) != getPromotedType(Sext->getType())) {
NewInst = CopyDebug(
new SExtInst(NewInst ? NewInst : State.getConverted(Op),
getPromotedType(cast<IntegerType>(Sext->getType())),
Sext->getName() + ".sext", Sext),
Sext);
}
assert(NewInst && "Failed to convert sign extension");
State.recordConverted(Sext, NewInst);
} else if (ZExtInst *Zext = dyn_cast<ZExtInst>(Inst)) {
Value *Op = Zext->getOperand(0);
Value *NewInst = nullptr;
if (shouldConvert(Op)) {
NewInst = getClearConverted(Op, Zext, State);
}
// If the converted type of the operand is the same as the converted
// type of the result, we won't actually be changing the type of the
// variable, just its value.
if (getPromotedType(Op->getType()) != getPromotedType(Zext->getType())) {
NewInst = CopyDebug(
CastInst::CreateZExtOrBitCast(
NewInst ? NewInst : State.getConverted(Op),
getPromotedType(cast<IntegerType>(Zext->getType())), "", Zext),
Zext);
}
assert(NewInst);
State.recordConverted(Zext, NewInst);
} else if (TruncInst *Trunc = dyn_cast<TruncInst>(Inst)) {
Value *Op = Trunc->getOperand(0);
Value *NewInst;
// If the converted type of the operand is the same as the converted
// type of the result, we don't actually need to change the type of the
// variable, just its value. However, because we don't care about the values
// of the upper bits until they are consumed, truncation can be a no-op.
if (getPromotedType(Op->getType()) != getPromotedType(Trunc->getType())) {
NewInst = CopyDebug(
new TruncInst(State.getConverted(Op),
getPromotedType(cast<IntegerType>(Trunc->getType())),
State.getConverted(Op)->getName() + ".trunc", Trunc),
Trunc);
} else {
NewInst = State.getConverted(Op);
}
State.recordConverted(Trunc, NewInst);
} else if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
if (shouldConvert(Load)) {
unsigned BaseAlign = Load->getAlignment() == 0
? DL->getABITypeAlignment(Load->getType())
: Load->getAlignment();
splitLoad(DL, Load, State, BaseAlign, /*Offset=*/0);
}
} else if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
if (shouldConvert(Store->getValueOperand())) {
unsigned BaseAlign =
Store->getAlignment() == 0
? DL->getABITypeAlignment(Store->getValueOperand()->getType())
: Store->getAlignment();
splitStore(DL, Store, State, BaseAlign, /*Offset=*/0);
}
} else if (isa<InvokeInst>(Inst) || isa<CallInst>(Inst) ||
isa<LandingPadInst>(Inst)) {
for (unsigned I = 0; I < Inst->getNumOperands(); I++) {
auto *Arg = Inst->getOperand(I);
if (shouldConvert(Arg))
Inst->setOperand(I, State.getConverted(Arg));
}
if (shouldConvert(Inst)) {
Inst->mutateType(getPromotedType(Inst->getType()));
}
} else if (auto *Ret = dyn_cast<ReturnInst>(Inst)) {
auto *NewRet = ReturnInst::Create(
Ret->getContext(), State.getConverted(Ret->getReturnValue()), Inst);
State.recordConverted(Ret, NewRet);
} else if (auto *Resume = dyn_cast<ResumeInst>(Inst)) {
auto *NewRes =
ResumeInst::Create(State.getConverted(Resume->getValue()), Inst);
State.recordConverted(Ret, NewRes);
} else if (BinaryOperator *Binop = dyn_cast<BinaryOperator>(Inst)) {
Value *NewInst = nullptr;
switch (Binop->getOpcode()) {
case Instruction::AShr: {
// The AShr operand needs to be sign-extended to the promoted size
// before shifting. Because the sign-extension is implemented with
// with AShr, it can be combined with the original operation.
Value *Op = Binop->getOperand(0);
Value *ShiftAmount = nullptr;
APInt SignShiftAmt =
APInt(getPromotedType(Op->getType())->getIntegerBitWidth(),
getPromotedType(Op->getType())->getIntegerBitWidth() -
Op->getType()->getIntegerBitWidth());
NewInst = CopyDebug(
BinaryOperator::Create(
Instruction::Shl, State.getConverted(Op),
ConstantInt::get(getPromotedType(Op->getType()), SignShiftAmt),
State.getConverted(Op)->getName() + ".getsign", Binop),
Binop);
if (ConstantInt *C =
dyn_cast<ConstantInt>(State.getConverted(Binop->getOperand(1)))) {
ShiftAmount = ConstantInt::get(getPromotedType(Op->getType()),
SignShiftAmt + C->getValue());
} else {
// Clear the upper bits of the original shift amount, and add back the
// amount we shifted to get the sign bit.
ShiftAmount = getClearConverted(Binop->getOperand(1), Binop, State);
ShiftAmount =
CopyDebug(BinaryOperator::Create(
Instruction::Add, ShiftAmount,
ConstantInt::get(
getPromotedType(Binop->getOperand(1)->getType()),
SignShiftAmt),
State.getConverted(Op)->getName() + ".shamt", Binop),
Binop);
}
NewInst = CopyDebug(
BinaryOperator::Create(Instruction::AShr, NewInst, ShiftAmount,
Binop->getName() + ".result", Binop),
Binop);
break;
}
case Instruction::LShr:
case Instruction::Shl: {
// For LShr, clear the upper bits of the operand before shifting them
// down into the valid part of the value.
Value *Op = Binop->getOpcode() == Instruction::LShr
? getClearConverted(Binop->getOperand(0), Binop, State)
: State.getConverted(Binop->getOperand(0));
NewInst = BinaryOperator::Create(
Binop->getOpcode(), Op,
// Clear the upper bits of the shift amount.
getClearConverted(Binop->getOperand(1), Binop, State),
Binop->getName() + ".result", Binop);
break;
}
case Instruction::Add:
case Instruction::Sub:
case Instruction::Mul:
case Instruction::And:
case Instruction::Or:
case Instruction::Xor:
// These operations don't care about the state of the upper bits.
NewInst = CopyDebug(
BinaryOperator::Create(Binop->getOpcode(),
State.getConverted(Binop->getOperand(0)),
State.getConverted(Binop->getOperand(1)),
Binop->getName() + ".result", Binop),
Binop);
break;
case Instruction::UDiv:
case Instruction::URem:
NewInst =
CopyDebug(BinaryOperator::Create(
Binop->getOpcode(),
getClearConverted(Binop->getOperand(0), Binop, State),
getClearConverted(Binop->getOperand(1), Binop, State),
Binop->getName() + ".result", Binop),
Binop);
break;
case Instruction::SDiv:
case Instruction::SRem:
NewInst =
CopyDebug(BinaryOperator::Create(
Binop->getOpcode(),
getSignExtend(State.getConverted(Binop->getOperand(0)),
Binop->getOperand(0), Binop),
getSignExtend(State.getConverted(Binop->getOperand(1)),
Binop->getOperand(0), Binop),
Binop->getName() + ".result", Binop),
Binop);
break;
case Instruction::FAdd:
case Instruction::FSub:
case Instruction::FMul:
case Instruction::FDiv:
case Instruction::FRem:
case Instruction::BinaryOpsEnd:
// We should not see FP operators here.
errs() << *Inst << "\n";
llvm_unreachable("Cannot handle binary operator");
break;
}
if (isa<OverflowingBinaryOperator>(NewInst)) {
cast<BinaryOperator>(NewInst)
->setHasNoUnsignedWrap(Binop->hasNoUnsignedWrap());
cast<BinaryOperator>(NewInst)
->setHasNoSignedWrap(Binop->hasNoSignedWrap());
}
State.recordConverted(Binop, NewInst);
} else if (ICmpInst *Cmp = dyn_cast<ICmpInst>(Inst)) {
Value *Op0, *Op1;
// For signed compares, operands are sign-extended to their
// promoted type. For unsigned or equality compares, the upper bits are
// cleared.
if (Cmp->isSigned()) {
Op0 = getSignExtend(State.getConverted(Cmp->getOperand(0)),
Cmp->getOperand(0), Cmp);
Op1 = getSignExtend(State.getConverted(Cmp->getOperand(1)),
Cmp->getOperand(1), Cmp);
} else {
Op0 = getClearConverted(Cmp->getOperand(0), Cmp, State);
Op1 = getClearConverted(Cmp->getOperand(1), Cmp, State);
}
Instruction *NewInst =
CopyDebug(new ICmpInst(Cmp, Cmp->getPredicate(), Op0, Op1, ""), Cmp);
State.recordConverted(Cmp, NewInst);
} else if (SelectInst *Select = dyn_cast<SelectInst>(Inst)) {
Instruction *NewInst = CopyDebug(
SelectInst::Create(
Select->getCondition(), State.getConverted(Select->getTrueValue()),
State.getConverted(Select->getFalseValue()), "", Select),
Select);
State.recordConverted(Select, NewInst);
} else if (PHINode *Phi = dyn_cast<PHINode>(Inst)) {
PHINode *NewPhi = PHINode::Create(getPromotedType(Phi->getType()),
Phi->getNumIncomingValues(), "", Phi);
CopyDebug(NewPhi, Phi);
for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; ++I) {
NewPhi->addIncoming(State.getConverted(Phi->getIncomingValue(I)),
Phi->getIncomingBlock(I));
}
State.recordConverted(Phi, NewPhi);
} else if (SwitchInst *Switch = dyn_cast<SwitchInst>(Inst)) {
Value *Condition = getClearConverted(Switch->getCondition(), Switch, State);
SwitchInst *NewInst = SwitchInst::Create(
Condition, Switch->getDefaultDest(), Switch->getNumCases(), Switch);
CopyDebug(NewInst, Switch);
for (SwitchInst::CaseIt I = Switch->case_begin(), E = Switch->case_end();
I != E; ++I) {
NewInst->addCase(cast<ConstantInt>(convertConstant(I.getCaseValue(),
/*SignExt=*/false)),
I.getCaseSuccessor());
}
Switch->eraseFromParent();
} else {
errs() << *Inst << "\n";
llvm_unreachable("unhandled instruction");
}
}
static bool processFunction(Function &F, DataLayout &DL) {
ConversionState State;
bool Modified = false; // XXX Emscripten: Fixed use of an uninitialized variable.
for (auto FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
for (auto BBI = FI->begin(), BBE = FI->end(); BBI != BBE;) {
Instruction *Inst = BBI++;
// Only attempt to convert an instruction if its result or any of its
// operands are illegal.
bool ShouldConvert = shouldConvert(Inst);
for (auto OI = Inst->op_begin(), OE = Inst->op_end(); OI != OE; ++OI)
ShouldConvert |= shouldConvert(cast<Value>(OI));
if (ShouldConvert) {
convertInstruction(&DL, Inst, State);
Modified = true;
}
}
}
State.eraseReplacedInstructions();
if (Modified)
// Clean up bitcasts that were create with constexprs in them.
std::unique_ptr<FunctionPass>(createExpandConstantExprPass())
->runOnFunction(F);
return Modified;
}
bool PromoteIntegers::ensureCompliantSignature(
LLVMContext &Ctx, Function *OldFct, Module &M,
DenseMap<const llvm::Function *, DISubprogram> &DISubprogramMap) {
auto *NewFctType = cast<FunctionType>(
TypeMapper.getSimpleType(Ctx, OldFct->getFunctionType()));
if (NewFctType == OldFct->getFunctionType())
return false;
auto *NewFct = Function::Create(NewFctType, OldFct->getLinkage(), "", &M);
NewFct->takeName(OldFct);
NewFct->copyAttributesFrom(OldFct);
for (auto UseIter = OldFct->use_begin(), E = OldFct->use_end();
E != UseIter;) {
Use &FctUse = *(UseIter++);
// Types are not going to match after this.
FctUse.set(NewFct);
}
if (OldFct->empty())
return true;
NewFct->getBasicBlockList().splice(NewFct->begin(),
OldFct->getBasicBlockList());
IRBuilder<> Builder(NewFct->getEntryBlock().getFirstInsertionPt());
auto OldArgIter = OldFct->getArgumentList().begin();
for (auto &NewArg : NewFct->getArgumentList()) {
Argument *OldArg = OldArgIter++;
if (OldArg->getType() != NewArg.getType()) {
if (NewArg.getType()->isIntegerTy()) {
auto *Replacement = Builder.CreateTrunc(&NewArg, OldArg->getType());
Replacement->takeName(OldArg);
NewArg.setName(Replacement->getName() + ".exp");
OldArg->replaceAllUsesWith(Replacement);
} else {
// Blindly replace the type of the uses, this is some composite
// like a function type.
NewArg.takeName(OldArg);
for (auto UseIter = OldArg->use_begin(), E = OldArg->use_end();
E != UseIter;) {
Use &AUse = *(UseIter++);
AUse.set(&NewArg);
}
}
} else {
NewArg.takeName(OldArg);
OldArg->replaceAllUsesWith(&NewArg);
}
}
auto Found = DISubprogramMap.find(OldFct);
if (Found != DISubprogramMap.end())
Found->second->replaceFunction(NewFct);
return true;
}
bool PromoteIntegers::runOnModule(Module &M) {
DataLayout DL(&M);
LLVMContext &Ctx = M.getContext();
bool Modified = false;
auto DISubprogramMap = makeSubprogramMap(M);
// Change function signatures first.
for (auto I = M.begin(), E = M.end(); I != E;) {
Function *F = I++;
bool Changed = ensureCompliantSignature(Ctx, F, M, DISubprogramMap);
if (Changed)
F->eraseFromParent();
Modified |= Changed;
}
for (auto &F : M.getFunctionList())
Modified |= processFunction(F, DL);
return Modified;
}
ModulePass *llvm::createPromoteIntegersPass() { return new PromoteIntegers(); }