Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Unified Diff: lib/Transforms/NaCl/ExpandLargeIntegers.cpp

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/Transforms/NaCl/ExpandIndirectBr.cpp ('k') | lib/Transforms/NaCl/ExpandShuffleVector.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/Transforms/NaCl/ExpandLargeIntegers.cpp
diff --git a/lib/Transforms/NaCl/ExpandLargeIntegers.cpp b/lib/Transforms/NaCl/ExpandLargeIntegers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9fb3a13d28016845f3774b689701ac94eb1252ba
--- /dev/null
+++ b/lib/Transforms/NaCl/ExpandLargeIntegers.cpp
@@ -0,0 +1,616 @@
+//===- ExpandLargeIntegers.cpp - Expand 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 expand illegal-sized int types.
+//
+//===----------------------------------------------------------------------===//
+//
+// Legal sizes for the purposes of expansion are anything 64 bits or less.
+// Operations on large integers are split into operations on smaller-sized
+// integers. The low parts should always be powers of 2, but the high parts may
+// not be. A subsequent pass can promote those. For now this pass only intends
+// to support the uses generated by clang, which is basically just for large
+// bitfields.
+//
+// Limitations:
+// 1) It can't change function signatures or global variables.
+// 3) Doesn't support mul, div/rem, switch.
+// 4) Doesn't handle arrays or structs (or GEPs) with illegal types.
+// 5) Doesn't handle constant expressions (it also doesn't produce them, so it
+// can run after ExpandConstantExpr).
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/NaCl.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "nacl-expand-ints"
+
+// Break instructions up into no larger than 64-bit chunks.
+static const unsigned kChunkBits = 64;
+static const unsigned kChunkBytes = kChunkBits / CHAR_BIT;
+
+namespace {
+class ExpandLargeIntegers : public FunctionPass {
+public:
+ static char ID;
+ ExpandLargeIntegers() : FunctionPass(ID) {
+ initializeExpandLargeIntegersPass(*PassRegistry::getPassRegistry());
+ }
+ bool runOnFunction(Function &F) override;
+};
+
+template <typename T> struct LoHiPair {
+ T Lo, Hi;
+ LoHiPair() : Lo(), Hi() {}
+ LoHiPair(T Lo, T Hi) : Lo(Lo), Hi(Hi) {}
+};
+template <typename T> struct LoHiBitTriple {
+ T Lo, Hi, Bit;
+ LoHiBitTriple() : Lo(), Hi(), Bit() {}
+ LoHiBitTriple(T Lo, T Hi, T Bit) : Lo(Lo), Hi(Hi), Bit(Bit) {}
+};
+typedef LoHiPair<IntegerType *> TypePair;
+typedef LoHiPair<Value *> ValuePair;
+typedef LoHiPair<unsigned> AlignPair;
+typedef LoHiBitTriple<Value *> ValueTriple;
+
+// Information needed to patch a phi node which forward-references a value.
+struct ForwardPHI {
+ Value *Val;
+ PHINode *Lo, *Hi;
+ unsigned ValueNumber;
+ ForwardPHI(Value *Val, PHINode *Lo, PHINode *Hi, unsigned ValueNumber)
+ : Val(Val), Lo(Lo), Hi(Hi), ValueNumber(ValueNumber) {}
+};
+}
+
+char ExpandLargeIntegers::ID = 0;
+INITIALIZE_PASS(ExpandLargeIntegers, "nacl-expand-ints",
+ "Expand integer types that are illegal in PNaCl", false, false)
+
+#define DIE_IF(COND, VAL, MSG) \
+ do { \
+ if (COND) { \
+ errs() << "Unsupported: " << *(VAL) << '\n'; \
+ report_fatal_error( \
+ MSG " not yet supported for integer types larger than 64 bits"); \
+ } \
+ } while (0)
+
+static bool isLegalBitSize(unsigned Bits) {
+ assert(Bits && "Can't have zero-size integers");
+ return Bits <= kChunkBits;
+}
+
+static TypePair getExpandedIntTypes(Type *Ty) {
+ unsigned BitWidth = Ty->getIntegerBitWidth();
+ assert(!isLegalBitSize(BitWidth));
+ return {IntegerType::get(Ty->getContext(), kChunkBits),
+ IntegerType::get(Ty->getContext(), BitWidth - kChunkBits)};
+}
+
+// Return true if Val is an int which should be converted.
+static bool shouldConvert(const Value *Val) {
+ Type *Ty = Val->getType();
+ if (IntegerType *ITy = dyn_cast<IntegerType>(Ty))
+ return !isLegalBitSize(ITy->getBitWidth());
+ return false;
+}
+
+// Return a pair of constants expanded from C.
+static ValuePair expandConstant(Constant *C) {
+ assert(shouldConvert(C));
+ TypePair ExpandedTypes = getExpandedIntTypes(C->getType());
+ if (isa<UndefValue>(C)) {
+ return {UndefValue::get(ExpandedTypes.Lo),
+ UndefValue::get(ExpandedTypes.Hi)};
+ } else if (ConstantInt *CInt = dyn_cast<ConstantInt>(C)) {
+ Constant *ShiftAmt = ConstantInt::get(
+ CInt->getType(), ExpandedTypes.Lo->getBitWidth(), false);
+ return {ConstantExpr::getTrunc(CInt, ExpandedTypes.Lo),
+ ConstantExpr::getTrunc(ConstantExpr::getLShr(CInt, ShiftAmt),
+ ExpandedTypes.Hi)};
+ }
+ DIE_IF(true, C, "Constant value");
+}
+
+template <typename T>
+static AlignPair getAlign(const DataLayout &DL, T *I, Type *PrefAlignTy) {
+ unsigned LoAlign = I->getAlignment();
+ if (LoAlign == 0)
+ LoAlign = DL.getPrefTypeAlignment(PrefAlignTy);
+ unsigned HiAlign = MinAlign(LoAlign, kChunkBytes);
+ return {LoAlign, HiAlign};
+}
+
+static ValuePair createBit(IRBuilder<> *IRB, const BinaryOperator *Binop,
+ const ValuePair &Lhs, const ValuePair &Rhs,
+ const TypePair &Tys, const StringRef &Name) {
+ auto Op = Binop->getOpcode();
+ Value *Lo = IRB->CreateBinOp(Op, Lhs.Lo, Rhs.Lo, Twine(Name, ".lo"));
+ Value *Hi = IRB->CreateBinOp(Op, Lhs.Hi, Rhs.Hi, Twine(Name, ".hi"));
+ return {Lo, Hi};
+}
+
+static ValuePair createShl(IRBuilder<> *IRB, const BinaryOperator *Binop,
+ const ValuePair &Lhs, const ValuePair &Rhs,
+ const TypePair &Tys, const StringRef &Name) {
+ ConstantInt *ShlAmount = dyn_cast<ConstantInt>(Rhs.Lo);
+ // TODO(dschuff): Expansion of variable-sized shifts isn't supported
+ // because the behavior depends on whether the shift amount is less than
+ // the size of the low part of the expanded type, and I haven't yet
+ // figured out a way to do it for variable-sized shifts without splitting
+ // the basic block. I don't believe it's actually necessary for
+ // bitfields. Likewise for LShr below.
+ DIE_IF(!ShlAmount, Binop, "Expansion of variable-sized shifts");
+ unsigned ShiftAmount = ShlAmount->getZExtValue();
+ if (ShiftAmount >= Binop->getType()->getIntegerBitWidth())
+ ShiftAmount = 0; // Undefined behavior.
+ unsigned HiBits = Tys.Hi->getIntegerBitWidth();
+ // |<------------Hi---------->|<-------Lo------>|
+ // | | |
+ // +--------+--------+--------+--------+--------+
+ // |abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQ|
+ // +--------+--------+--------+--------+--------+
+ // Possible shifts:
+ // |efghijklmnopqrstuvwxyzABCD|EFGHIJKLMNOPQ0000| Some Lo into Hi.
+ // |vwxyzABCDEFGHIJKLMNOPQ0000|00000000000000000| Lo is 0, keep some Hi.
+ // |DEFGHIJKLMNOPQ000000000000|00000000000000000| Lo is 0, no Hi left.
+ Value *Lo, *Hi;
+ if (ShiftAmount < kChunkBits) {
+ Lo = IRB->CreateShl(Lhs.Lo, ShiftAmount, Twine(Name, ".lo"));
+ Hi =
+ IRB->CreateZExtOrTrunc(IRB->CreateLShr(Lhs.Lo, kChunkBits - ShiftAmount,
+ Twine(Name, ".lo.shr")),
+ Tys.Hi, Twine(Name, ".lo.ext"));
+ } else {
+ Lo = ConstantInt::get(Tys.Lo, 0);
+ Hi = IRB->CreateShl(
+ IRB->CreateZExtOrTrunc(Lhs.Lo, Tys.Hi, Twine(Name, ".lo.ext")),
+ ShiftAmount - kChunkBits, Twine(Name, ".lo.shl"));
+ }
+ if (ShiftAmount < HiBits)
+ Hi = IRB->CreateOr(
+ Hi, IRB->CreateShl(Lhs.Hi, ShiftAmount, Twine(Name, ".hi.shl")),
+ Twine(Name, ".or"));
+ return {Lo, Hi};
+}
+
+static ValuePair createShr(IRBuilder<> *IRB, const BinaryOperator *Binop,
+ const ValuePair &Lhs, const ValuePair &Rhs,
+ const TypePair &Tys, const StringRef &Name) {
+ auto Op = Binop->getOpcode();
+ ConstantInt *ShrAmount = dyn_cast<ConstantInt>(Rhs.Lo);
+ // TODO(dschuff): Expansion of variable-sized shifts isn't supported
+ // because the behavior depends on whether the shift amount is less than
+ // the size of the low part of the expanded type, and I haven't yet
+ // figured out a way to do it for variable-sized shifts without splitting
+ // the basic block. I don't believe it's actually necessary for bitfields.
+ DIE_IF(!ShrAmount, Binop, "Expansion of variable-sized shifts");
+ bool IsArith = Op == Instruction::AShr;
+ unsigned ShiftAmount = ShrAmount->getZExtValue();
+ if (ShiftAmount >= Binop->getType()->getIntegerBitWidth())
+ ShiftAmount = 0; // Undefined behavior.
+ unsigned HiBitWidth = Tys.Hi->getIntegerBitWidth();
+ // |<--Hi-->|<-------Lo------>|
+ // | | |
+ // +--------+--------+--------+
+ // |abcdefgh|ABCDEFGHIJKLMNOPQ|
+ // +--------+--------+--------+
+ // Possible shifts (0 is sign when doing AShr):
+ // |0000abcd|defgABCDEFGHIJKLM| Some Hi into Lo.
+ // |00000000|00abcdefgABCDEFGH| Hi is 0, keep some Lo.
+ // |00000000|000000000000abcde| Hi is 0, no Lo left.
+ Value *Lo, *Hi;
+ if (ShiftAmount < kChunkBits) {
+ Lo = IRB->CreateShl(
+ IsArith
+ ? IRB->CreateSExtOrTrunc(Lhs.Hi, Tys.Lo, Twine(Name, ".hi.ext"))
+ : IRB->CreateZExtOrTrunc(Lhs.Hi, Tys.Lo, Twine(Name, ".hi.ext")),
+ kChunkBits - ShiftAmount, Twine(Name, ".hi.shl"));
+ Lo = IRB->CreateOr(
+ Lo, IRB->CreateLShr(Lhs.Lo, ShiftAmount, Twine(Name, ".lo.shr")),
+ Twine(Name, ".lo"));
+ } else {
+ Lo = IRB->CreateBinOp(Op, Lhs.Hi,
+ ConstantInt::get(Tys.Hi, ShiftAmount - kChunkBits),
+ Twine(Name, ".hi.shr"));
+ Lo = IsArith ? IRB->CreateSExtOrTrunc(Lo, Tys.Lo, Twine(Name, ".lo.ext"))
+ : IRB->CreateZExtOrTrunc(Lo, Tys.Lo, Twine(Name, ".lo.ext"));
+ }
+ if (ShiftAmount < HiBitWidth) {
+ Hi = IRB->CreateBinOp(Op, Lhs.Hi, ConstantInt::get(Tys.Hi, ShiftAmount),
+ Twine(Name, ".hi"));
+ } else {
+ Hi = IsArith ? IRB->CreateAShr(Lhs.Hi, HiBitWidth - 1, Twine(Name, ".hi"))
+ : ConstantInt::get(Tys.Hi, 0);
+ }
+ return {Lo, Hi};
+}
+
+static Value *createCarry(IRBuilder<> *IRB, Value *Lhs, Value *Rhs,
+ Value *Added, Type *Ty, const StringRef &Name) {
+ return IRB->CreateZExt(
+ IRB->CreateICmpULT(
+ Added,
+ IRB->CreateSelect(IRB->CreateICmpULT(Lhs, Rhs, Twine(Name, ".cmp")),
+ Rhs, Lhs, Twine(Name, ".limit")),
+ Twine(Name, ".overflowed")),
+ Ty, Twine(Name, ".carry"));
+}
+
+static ValueTriple createAdd(IRBuilder<> *IRB, const ValuePair &Lhs,
+ const ValuePair &Rhs, const TypePair &Tys,
+ const StringRef &Name, Type *HiCarryTy) {
+ auto Op = Instruction::Add;
+ // Don't propagate NUW/NSW to the lo operation: it can overflow.
+ Value *Lo = IRB->CreateBinOp(Op, Lhs.Lo, Rhs.Lo, Twine(Name, ".lo"));
+ Value *LoCarry = createCarry(IRB, Lhs.Lo, Rhs.Lo, Lo, Tys.Hi, Name);
+ // TODO(jfb) The hi operation could be tagged with NUW/NSW.
+ Value *HiAdd = IRB->CreateBinOp(Op, Lhs.Hi, Rhs.Hi, Twine(Name, ".hi"));
+ Value *Hi = IRB->CreateBinOp(Op, HiAdd, LoCarry, Twine(Name, ".carried"));
+ Value *HiCarry = HiCarryTy
+ ? createCarry(IRB, Lhs.Hi, Rhs.Hi, Hi, HiCarryTy, Name)
+ : nullptr;
+ return {Lo, Hi, HiCarry};
+}
+
+static ValuePair createSub(IRBuilder<> *IRB, const ValuePair &Lhs,
+ const ValuePair &Rhs, const TypePair &Tys,
+ const StringRef &Name) {
+ auto Op = Instruction::Sub;
+ Value *Borrowed = IRB->CreateSExt(
+ IRB->CreateICmpULT(Lhs.Lo, Rhs.Lo, Twine(Name, ".borrow")), Tys.Hi,
+ Twine(Name, ".borrowing"));
+ Value *Lo = IRB->CreateBinOp(Op, Lhs.Lo, Rhs.Lo, Twine(Name, ".lo"));
+ Value *Hi =
+ IRB->CreateBinOp(Instruction::Add,
+ IRB->CreateBinOp(Op, Lhs.Hi, Rhs.Hi, Twine(Name, ".hi")),
+ Borrowed, Twine(Name, ".borrowed"));
+ return {Lo, Hi};
+}
+
+static Value *createICmpEquality(IRBuilder<> *IRB, CmpInst::Predicate Pred,
+ const ValuePair &Lhs, const ValuePair &Rhs,
+ const StringRef &Name) {
+ assert(Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE);
+ Value *Lo = IRB->CreateICmp(Pred, Lhs.Lo, Rhs.Lo, Twine(Name, ".lo"));
+ Value *Hi = IRB->CreateICmp(Pred, Lhs.Hi, Rhs.Hi, Twine(Name, ".hi"));
+ return IRB->CreateBinOp(
+ Instruction::And, Lo, Hi,
+ Twine(Name, Pred == CmpInst::ICMP_EQ ? ".eq" : ".ne"));
+}
+
+static Value *createICmp(IRBuilder<> *IRB, const ICmpInst *ICmp,
+ const ValuePair &Lhs, const ValuePair &Rhs,
+ const TypePair &Tys, const StringRef &Name) {
+ auto Pred = ICmp->getPredicate();
+ switch (Pred) {
+ case CmpInst::ICMP_EQ:
+ case CmpInst::ICMP_NE:
+ return createICmpEquality(IRB, ICmp->getPredicate(), Lhs, Rhs, Name);
+
+ case CmpInst::ICMP_UGT: // C == 1 and Z == 0
+ case CmpInst::ICMP_UGE: // C == 1
+ case CmpInst::ICMP_ULT: // C == 0 and Z == 0
+ case CmpInst::ICMP_ULE: // C == 0
+ {
+ Value *Carry = createAdd(IRB, Lhs, Rhs, Tys, Name, ICmp->getType()).Bit;
+ if (Pred == CmpInst::ICMP_ULT || Pred == CmpInst::ICMP_ULE)
+ Carry = IRB->CreateNot(Carry, Name);
+ if (Pred == CmpInst::ICMP_UGT || Pred == CmpInst::ICMP_ULT)
+ Carry = IRB->CreateBinOp(
+ Instruction::And, Carry,
+ createICmpEquality(IRB, CmpInst::ICMP_EQ, Lhs, Rhs, Name), Name);
+ return Carry;
+ }
+
+ case CmpInst::ICMP_SGT: // N == V and Z == 0
+ case CmpInst::ICMP_SGE: // N == V
+ case CmpInst::ICMP_SLT: // N != V
+ case CmpInst::ICMP_SLE: // N != V or Z == 1
+ DIE_IF(true, ICmp, "Signed comparisons");
+ default:
+ llvm_unreachable("Invalid integer comparison");
+ }
+}
+
+static ValuePair createLoad(IRBuilder<> *IRB, const DataLayout &DL,
+ LoadInst *Load) {
+ DIE_IF(!Load->isSimple(), Load, "Volatile and atomic loads");
+ Value *Op = Load->getPointerOperand();
+ TypePair Tys = getExpandedIntTypes(Load->getType());
+ AlignPair Align = getAlign(DL, Load, Load->getType());
+ Value *Loty = IRB->CreateBitCast(Op, Tys.Lo->getPointerTo(),
+ Twine(Op->getName(), ".loty"));
+ Value *Lo =
+ IRB->CreateAlignedLoad(Loty, Align.Lo, Twine(Load->getName(), ".lo"));
+ Value *HiAddr =
+ IRB->CreateConstGEP1_32(Loty, 1, Twine(Op->getName(), ".hi.gep"));
+ Value *HiTy = IRB->CreateBitCast(HiAddr, Tys.Hi->getPointerTo(),
+ Twine(Op->getName(), ".hity"));
+ Value *Hi =
+ IRB->CreateAlignedLoad(HiTy, Align.Hi, Twine(Load->getName(), ".hi"));
+ return {Lo, Hi};
+}
+
+static ValuePair createStore(IRBuilder<> *IRB, const DataLayout &DL,
+ StoreInst *Store, const ValuePair &StoreVals) {
+ DIE_IF(!Store->isSimple(), Store, "Volatile and atomic stores");
+ Value *Ptr = Store->getPointerOperand();
+ TypePair Tys = getExpandedIntTypes(Store->getValueOperand()->getType());
+ AlignPair Align = getAlign(DL, Store, Store->getValueOperand()->getType());
+ Value *Loty = IRB->CreateBitCast(Ptr, Tys.Lo->getPointerTo(),
+ Twine(Ptr->getName(), ".loty"));
+ Value *Lo = IRB->CreateAlignedStore(StoreVals.Lo, Loty, Align.Lo);
+ Value *HiAddr =
+ IRB->CreateConstGEP1_32(Loty, 1, Twine(Ptr->getName(), ".hi.gep"));
+ Value *HiTy = IRB->CreateBitCast(HiAddr, Tys.Hi->getPointerTo(),
+ Twine(Ptr->getName(), ".hity"));
+ Value *Hi = IRB->CreateAlignedStore(StoreVals.Hi, HiTy, Align.Hi);
+ return {Lo, Hi};
+}
+
+namespace {
+// Holds the state for converting/replacing values. We visit instructions in
+// reverse post-order, phis are therefore the only instructions which can be
+// visited before the value they use.
+class ConversionState {
+public:
+ // Return the expanded values for Val.
+ ValuePair getConverted(Value *Val) {
+ assert(shouldConvert(Val));
+ // Directly convert constants.
+ if (Constant *C = dyn_cast<Constant>(Val))
+ return expandConstant(C);
+ if (RewrittenIllegals.count(Val)) {
+ ValuePair Found = RewrittenIllegals[Val];
+ if (RewrittenLegals.count(Found.Lo))
+ Found.Lo = RewrittenLegals[Found.Lo];
+ if (RewrittenLegals.count(Found.Hi))
+ Found.Hi = RewrittenLegals[Found.Hi];
+ return Found;
+ }
+ errs() << "Value: " << *Val << "\n";
+ report_fatal_error("Expanded value not found in map");
+ }
+
+ // Returns whether a converted value has been recorded. This is only useful
+ // for phi instructions: they can be encountered before the incoming
+ // instruction, whereas RPO order guarantees that other instructions always
+ // use converted values.
+ bool hasConverted(Value *Val) {
+ assert(shouldConvert(Val));
+ return dyn_cast<Constant>(Val) || RewrittenIllegals.count(Val);
+ }
+
+ // Record a forward phi, temporarily setting it to use Undef. This will be
+ // patched up at the end of RPO.
+ ValuePair recordForwardPHI(Value *Val, PHINode *Lo, PHINode *Hi,
+ unsigned ValueNumber) {
+ DEBUG(dbgs() << "\tRecording as forward PHI\n");
+ ForwardPHIs.push_back(ForwardPHI(Val, Lo, Hi, ValueNumber));
+ return {UndefValue::get(Lo->getType()), UndefValue::get(Hi->getType())};
+ }
+
+ void recordConverted(Instruction *From, const ValuePair &To) {
+ DEBUG(dbgs() << "\tTo: " << *To.Lo << "\n");
+ DEBUG(dbgs() << "\tAnd: " << *To.Hi << "\n");
+ ToErase.push_back(From);
+ RewrittenIllegals[From] = To;
+ }
+
+ // Replace the uses of From with To, give From's name to To, and mark To for
+ // deletion.
+ void recordConverted(Instruction *From, Value *To) {
+ assert(!shouldConvert(From));
+ DEBUG(dbgs() << "\tTo: " << *To << "\n");
+ ToErase.push_back(From);
+ // From does not produce an illegal value, update its users in place.
+ From->replaceAllUsesWith(To);
+ To->takeName(From);
+ RewrittenLegals[From] = To;
+ }
+
+ void patchForwardPHIs() {
+ DEBUG(if (!ForwardPHIs.empty()) dbgs() << "Patching forward PHIs:\n");
+ for (ForwardPHI &F : ForwardPHIs) {
+ ValuePair Ops = getConverted(F.Val);
+ F.Lo->setIncomingValue(F.ValueNumber, Ops.Lo);
+ F.Hi->setIncomingValue(F.ValueNumber, Ops.Hi);
+ DEBUG(dbgs() << "\t" << *F.Lo << "\n\t" << *F.Hi << "\n");
+ }
+ }
+
+ void eraseReplacedInstructions() {
+ for (Instruction *I : ToErase)
+ I->dropAllReferences();
+ for (Instruction *I : ToErase)
+ I->eraseFromParent();
+ }
+
+private:
+ // Maps illegal values to their new converted lo/hi values.
+ DenseMap<Value *, ValuePair> RewrittenIllegals;
+ // Maps legal values to their new converted value.
+ DenseMap<Value *, Value *> RewrittenLegals;
+ // Illegal values which have already been converted, will be erased.
+ SmallVector<Instruction *, 32> ToErase;
+ // PHIs which were encountered but had forward references. They need to get
+ // patched up after RPO traversal.
+ SmallVector<ForwardPHI, 32> ForwardPHIs;
+};
+} // Anonymous namespace
+
+static void convertInstruction(Instruction *Inst, ConversionState &State,
+ const DataLayout &DL) {
+ DEBUG(dbgs() << "Expanding Large Integer: " << *Inst << "\n");
+ // Set the insert point *after* Inst, so that any instructions inserted here
+ // will be visited again. That allows iterative expansion of types > i128.
+ BasicBlock::iterator InsertPos(Inst);
+ IRBuilder<> IRB(++InsertPos);
+ StringRef Name = Inst->getName();
+
+ if (PHINode *Phi = dyn_cast<PHINode>(Inst)) {
+ unsigned N = Phi->getNumIncomingValues();
+ TypePair OpTys = getExpandedIntTypes(Phi->getIncomingValue(0)->getType());
+ PHINode *Lo = IRB.CreatePHI(OpTys.Lo, N, Twine(Name + ".lo"));
+ PHINode *Hi = IRB.CreatePHI(OpTys.Hi, N, Twine(Name + ".hi"));
+ for (unsigned I = 0; I != N; ++I) {
+ Value *InVal = Phi->getIncomingValue(I);
+ BasicBlock *InBB = Phi->getIncomingBlock(I);
+ // If the value hasn't already been converted then this is a
+ // forward-reference PHI which needs to be patched up after RPO traversal.
+ ValuePair Ops = State.hasConverted(InVal)
+ ? State.getConverted(InVal)
+ : State.recordForwardPHI(InVal, Lo, Hi, I);
+ Lo->addIncoming(Ops.Lo, InBB);
+ Hi->addIncoming(Ops.Hi, InBB);
+ }
+ State.recordConverted(Phi, {Lo, Hi});
+
+ } else if (ZExtInst *ZExt = dyn_cast<ZExtInst>(Inst)) {
+ Value *Operand = ZExt->getOperand(0);
+ Type *OpTy = Operand->getType();
+ TypePair Tys = getExpandedIntTypes(Inst->getType());
+ Value *Lo, *Hi;
+ if (OpTy->getIntegerBitWidth() <= kChunkBits) {
+ Lo = IRB.CreateZExt(Operand, Tys.Lo, Twine(Name, ".lo"));
+ Hi = ConstantInt::get(Tys.Hi, 0);
+ } else {
+ ValuePair Ops = State.getConverted(Operand);
+ Lo = Ops.Lo;
+ Hi = IRB.CreateZExt(Ops.Hi, Tys.Hi, Twine(Name, ".hi"));
+ }
+ State.recordConverted(ZExt, {Lo, Hi});
+
+ } else if (TruncInst *Trunc = dyn_cast<TruncInst>(Inst)) {
+ Value *Operand = Trunc->getOperand(0);
+ assert(shouldConvert(Operand) && "TruncInst is expandable but not its op");
+ ValuePair Ops = State.getConverted(Operand);
+ if (!shouldConvert(Inst)) {
+ Value *NewInst = IRB.CreateTrunc(Ops.Lo, Trunc->getType(), Name);
+ State.recordConverted(Trunc, NewInst);
+ } else {
+ TypePair Tys = getExpandedIntTypes(Trunc->getType());
+ assert(Tys.Lo == getExpandedIntTypes(Operand->getType()).Lo);
+ Value *Lo = Ops.Lo;
+ Value *Hi = IRB.CreateTrunc(Ops.Hi, Tys.Hi, Twine(Name, ".hi"));
+ State.recordConverted(Trunc, {Lo, Hi});
+ }
+
+ } else if (BinaryOperator *Binop = dyn_cast<BinaryOperator>(Inst)) {
+ ValuePair Lhs = State.getConverted(Binop->getOperand(0));
+ ValuePair Rhs = State.getConverted(Binop->getOperand(1));
+ TypePair Tys = getExpandedIntTypes(Binop->getType());
+ ValuePair Conv;
+ switch (Binop->getOpcode()) {
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ Conv = createBit(&IRB, Binop, Lhs, Rhs, Tys, Name);
+ break;
+ case Instruction::Shl:
+ Conv = createShl(&IRB, Binop, Lhs, Rhs, Tys, Name);
+ break;
+ case Instruction::AShr:
+ case Instruction::LShr:
+ Conv = createShr(&IRB, Binop, Lhs, Rhs, Tys, Name);
+ break;
+ case Instruction::Add: {
+ ValueTriple VT =
+ createAdd(&IRB, Lhs, Rhs, Tys, Name, /*HiCarryTy=*/nullptr);
+ Conv = {VT.Lo, VT.Hi}; // Ignore Hi carry.
+ } break;
+ case Instruction::Sub:
+ Conv = createSub(&IRB, Lhs, Rhs, Tys, Name);
+ break;
+ default:
+ DIE_IF(true, Binop, "Binary operator type");
+ }
+ State.recordConverted(Binop, Conv);
+
+ } else if (ICmpInst *ICmp = dyn_cast<ICmpInst>(Inst)) {
+ ValuePair Lhs = State.getConverted(ICmp->getOperand(0));
+ ValuePair Rhs = State.getConverted(ICmp->getOperand(1));
+ TypePair Tys = getExpandedIntTypes(ICmp->getOperand(0)->getType());
+ State.recordConverted(ICmp, createICmp(&IRB, ICmp, Lhs, Rhs, Tys, Name));
+
+ } else if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
+ State.recordConverted(Load, createLoad(&IRB, DL, Load));
+
+ } else if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
+ ValuePair StoreVals = State.getConverted(Store->getValueOperand());
+ State.recordConverted(Store, createStore(&IRB, DL, Store, StoreVals));
+
+ } else if (SelectInst *Select = dyn_cast<SelectInst>(Inst)) {
+ Value *Cond = Select->getCondition();
+ ValuePair True = State.getConverted(Select->getTrueValue());
+ ValuePair False = State.getConverted(Select->getFalseValue());
+ Value *Lo = IRB.CreateSelect(Cond, True.Lo, False.Lo, Twine(Name, ".lo"));
+ Value *Hi = IRB.CreateSelect(Cond, True.Hi, False.Hi, Twine(Name, ".hi"));
+ State.recordConverted(Select, {Lo, Hi});
+
+ } else {
+ DIE_IF(true, Inst, "Instruction");
+ }
+}
+
+bool ExpandLargeIntegers::runOnFunction(Function &F) {
+ // Don't support changing the function arguments. Illegal function arguments
+ // should not be generated by clang.
+ for (const Argument &Arg : F.args())
+ if (shouldConvert(&Arg))
+ report_fatal_error("Function " + F.getName() +
+ " has illegal integer argument");
+
+ // TODO(jfb) This should loop to handle nested forward PHIs.
+
+ ConversionState State;
+ DataLayout DL(F.getParent());
+ bool Modified = false;
+ ReversePostOrderTraversal<Function *> RPOT(&F);
+ for (ReversePostOrderTraversal<Function *>::rpo_iterator FI = RPOT.begin(),
+ FE = RPOT.end();
+ FI != FE; ++FI) {
+ BasicBlock *BB = *FI;
+ for (Instruction &I : *BB) {
+ // Only attempt to convert an instruction if its result or any of its
+ // operands are illegal.
+ bool ShouldConvert = shouldConvert(&I);
+ for (Value *Op : I.operands())
+ ShouldConvert |= shouldConvert(Op);
+ if (ShouldConvert) {
+ convertInstruction(&I, State, DL);
+ Modified = true;
+ }
+ }
+ }
+ State.patchForwardPHIs();
+ State.eraseReplacedInstructions();
+ return Modified;
+}
+
+FunctionPass *llvm::createExpandLargeIntegersPass() {
+ return new ExpandLargeIntegers();
+}
« no previous file with comments | « lib/Transforms/NaCl/ExpandIndirectBr.cpp ('k') | lib/Transforms/NaCl/ExpandShuffleVector.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698