summaryrefslogtreecommitdiffstats
path: root/src/llvm/pass/CombineCasts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm/pass/CombineCasts.cpp')
-rw-r--r--src/llvm/pass/CombineCasts.cpp321
1 files changed, 321 insertions, 0 deletions
diff --git a/src/llvm/pass/CombineCasts.cpp b/src/llvm/pass/CombineCasts.cpp
new file mode 100644
index 0000000..71a74ff
--- /dev/null
+++ b/src/llvm/pass/CombineCasts.cpp
@@ -0,0 +1,321 @@
+/*
+ * (C) 2015 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm/Transforms/Utils/Local.h"
+#include "llvm-target.h"
+#include "llvm-opc.h"
+#include "llvm-pass.h"
+#include "utils.h"
+
+#define PASS_NAME "CombineCasts"
+
+/*
+ * CombineCasts Pass
+ */
+class CombineCasts : public FunctionPass {
+ IRFactory *IF;
+ const DataLayout *DL;
+ MDFactory *MF;
+ IntegerType *Int8Ty;
+ IntegerType *Int32Ty;
+ IntegerType *Int64Ty;
+ IntegerType *IntPtrTy;
+ PointerType *Int8PtrTy;
+ PointerType *Int32PtrTy;
+ PointerType *Int64PtrTy;
+ Type *FloatTy;
+ Type *DoubleTy;
+ IVec toErase;
+
+public:
+ static char ID;
+ explicit CombineCasts() : FunctionPass(ID) {}
+ explicit CombineCasts(IRFactory *IF)
+ : FunctionPass(ID), IF(IF), DL(IF->getDL()), MF(IF->getMDFactory())
+ {
+ LLVMContext &Context = IF->getContext();;
+ Int8Ty = IntegerType::get(Context, 8);
+ Int32Ty = IntegerType::get(Context, 32);
+ Int64Ty = IntegerType::get(Context, 64);
+ IntPtrTy = DL->getIntPtrType(Context);
+ Int8PtrTy = Type::getInt8PtrTy(Context, 0);
+ Int32PtrTy = Type::getInt32PtrTy(Context, 0);
+ Int64PtrTy = Type::getInt64PtrTy(Context, 0);
+ FloatTy = Type::getFloatTy(Context);
+ DoubleTy = Type::getDoubleTy(Context);
+ }
+
+ Instruction *getUniqueUser(Instruction *I) {
+ if (I->hasOneUse())
+ return I->user_back();
+ return nullptr;
+ };
+
+ bool combineLoadCast(LoadInst *LI);
+ bool combineStoreCast(StoreInst *SI);
+ bool combineCastCast(Function &F);
+ bool simplifySignChange(Function &F);
+ bool runOnFunction(Function &F);
+};
+
+char CombineCasts::ID = 0;
+INITIALIZE_PASS(CombineCasts, "combinecast",
+ "Combine bitcast with guest memory loads/stores", false, false)
+
+FunctionPass *llvm::createCombineCasts(IRFactory *IF)
+{
+ return new CombineCasts(IF);
+}
+
+static bool hasSameCastingTy(ArrayRef<BitCastInst *> IL) {
+ Type *SrcTy = IL[0]->getSrcTy();
+ Type *DstTy = IL[0]->getDestTy();
+ for (BitCastInst *I : IL) {
+ if (I->getSrcTy() != SrcTy)
+ return false;
+ if (I->getDestTy() != DstTy)
+ return false;
+ }
+ return true;
+}
+
+/* This function aims to change the load type if (1) the type of loaded data is
+ * casted to another type, (2) only one user of the load instruction is bitcast,
+ * and (3) all other users of the load instruction are stores.
+ *
+ * For example:
+ * %0 = load <typeA>* %0 = load <typeB>*
+ * %1 = bitcast %0, <typeB> %1 = bitcast %0, <typeA>
+ *
+ * %2 = op <typeB> %1, ... => %2 = op <typeB> %0, ...
+ *
+ * store %0, <typeA>* store %1, <typeA>*
+ * store %1, <typeB>* store %0, <typeB>*
+ */
+bool CombineCasts::combineLoadCast(LoadInst *LI)
+{
+ Instruction *Ptr = dyn_cast<Instruction>(LI->getPointerOperand());
+
+ if (!Ptr)
+ return false;
+
+ /* Find all bitcast users of this load. */
+ SmallVector<BitCastInst *, 4> BCIs;
+ for (User *U : LI->users()) {
+ Instruction *UI = cast<Instruction>(U);
+ switch (UI->getOpcode()) {
+ default:
+ return false;
+ case Instruction::PHI:
+ case Instruction::Load:
+ case Instruction::Store:
+ break;
+ case Instruction::BitCast:
+ BCIs.push_back(cast<BitCastInst>(UI));
+ break;
+ }
+ }
+
+ if (BCIs.empty() || !hasSameCastingTy(BCIs))
+ return false;
+
+ Instruction *InsertPos = LI;
+ unsigned Alignment = LI->getAlignment();
+ unsigned Volatile = LI->isVolatile();
+ Type *SrcTy = LI->getType();
+ Type *DstTy = BCIs[0]->getDestTy();
+
+ Type *PtrTy = PointerType::get(DstTy, LI->getPointerAddressSpace());
+ if (isa<IntToPtrInst>(Ptr))
+ Ptr = new IntToPtrInst(Ptr->getOperand(0), PtrTy, "", InsertPos);
+ else
+ Ptr = new BitCastInst(Ptr, PtrTy, "", InsertPos);
+
+ Instruction *NewLI = new LoadInst(Ptr, "", Volatile, Alignment, InsertPos);
+ Instruction *NewBCI = new BitCastInst(NewLI, SrcTy, "", InsertPos);
+
+ if (MF->isGuestMemory(LI))
+ MF->setGuestMemory(NewLI);
+ for (BitCastInst *BCI : BCIs)
+ BCI->replaceAllUsesWith(NewLI);
+ LI->replaceAllUsesWith(NewBCI);
+
+ toErase.push_back(LI);
+ for (BitCastInst *BCI : BCIs)
+ toErase.push_back(BCI);
+
+ return true;
+}
+
+/* This function aims to change the store type if stored data is casted from
+ * another type.
+ *
+ * For example:
+ * %0 = <typeA>
+ * %1 = bitcast %0, <typeB> => store %0, <typeA>*
+ * store %1, <typeB>*
+ */
+bool CombineCasts::combineStoreCast(StoreInst *SI)
+{
+ Instruction *Ptr = dyn_cast<Instruction>(SI->getPointerOperand());
+ Instruction *Data = dyn_cast<Instruction>(SI->getValueOperand());
+
+ if (!Ptr || !Data || !isa<BitCastInst>(Data))
+ return false;
+
+ Instruction *InsertPos = SI;
+ unsigned Alignment = SI->getAlignment();
+ unsigned Volatile = SI->isVolatile();
+ BitCastInst *BCI = cast<BitCastInst>(Data);
+ Value *V = BCI->getOperand(0);
+ Type *SrcTy = V->getType();
+
+ Type *PtrTy = PointerType::get(SrcTy, SI->getPointerAddressSpace());
+ if (isa<IntToPtrInst>(Ptr))
+ Ptr = new IntToPtrInst(Ptr->getOperand(0), PtrTy, "", InsertPos);
+ else
+ Ptr = new BitCastInst(Ptr, PtrTy, "", InsertPos);
+
+ Instruction *NewSI = new StoreInst(V, Ptr, Volatile, Alignment, InsertPos);
+
+ if (MF->isGuestMemory(SI))
+ MF->setGuestMemory(NewSI);
+
+ toErase.push_back(SI);
+ return true;
+}
+
+/* This function aims to eliminate redundant casts.
+ * For example:
+ * %0 = <typeA> %0 = <typeA>
+ * %1 = bitcast %0, <typeB> =>
+ * %2 = bitcast %1, <typeC> %2 = bitcast %0, <typeC>
+ * = op <typeC> %2, ... = op <typeC> %2, ...
+ *
+ * And if <typeA> is the same as <typeC>, the code is further optimized to
+ * %0 = <typeA> %0 = <typeA>
+ * %1 = bitcast %0, <typeB> =>
+ * %2 = bitcast %1, <typeC>
+ * = op <typeC> %2, ... = op <typeA> %0, ...
+ */
+bool CombineCasts::combineCastCast(Function &F)
+{
+ SmallVector<Instruction*, 4> Worklist;
+ for (auto II = inst_begin(F), EE = inst_end(F); II != EE; II++) {
+ Instruction *I = &*II;
+ if (isa<BitCastInst>(I))
+ Worklist.push_back(I);
+ }
+
+ for (auto I : Worklist) {
+ BitCastInst *CI = cast<BitCastInst>(I);
+ BitCastInst *CSrc = dyn_cast<BitCastInst>(CI->getOperand(0));
+ if (!CSrc)
+ continue;
+
+ Type *SrcTy = CSrc->getOperand(0)->getType();
+ Type *DstTy = CI->getType();
+ Value *Result = (SrcTy == DstTy) ? CSrc->getOperand(0) :
+ new BitCastInst(CSrc->getOperand(0), CI->getType(), "", CI);
+ I->replaceAllUsesWith(Result);
+ toErase.push_back(I);
+ }
+
+ if (toErase.empty())
+ return false;
+
+ ProcessErase(toErase);
+ return true;
+}
+
+/* This function converts sign change of float/double data (i.e., -num),
+ * which is implemented with integer operations, to use float/double ops.
+ * For example:
+ * %0 = bitcast float %num to i32
+ * %1 = xor i32 %0, 0x80000000 => %0 = fsub float 0, %num
+ * %2 = bitcast %1, float
+ */
+bool CombineCasts::simplifySignChange(Function &F)
+{
+ SmallVector<BitCastInst*, 16> Worklist;
+
+ for (auto II = inst_begin(F), EE = inst_end(F); II != EE; II++) {
+ Instruction *I = &*II;
+ if (BitCastInst *BCI = dyn_cast<BitCastInst>(I)) {
+ Type *SrcTy = BCI->getSrcTy();
+ Type *DstTy = BCI->getDestTy();
+ if (SrcTy == FloatTy && DstTy == Int32Ty)
+ Worklist.push_back(BCI);
+ else if (SrcTy == DoubleTy && DstTy == Int64Ty)
+ Worklist.push_back(BCI);
+ }
+ }
+
+ for (auto I : Worklist) {
+ Type *Ty = I->getSrcTy();
+ Value *C = (Ty == FloatTy) ? CONST32(0x80000000)
+ : CONST64(0x8000000000000000LL);
+
+ /* Check whether the single user of this bitcast is Xor. */
+ Instruction *UI = getUniqueUser(I);
+ if (UI && UI->getOpcode() == Instruction::Xor && UI->getOperand(1) == C) {
+ /* Check whether the single user of this Xor is a bitcast
+ * instruction that casts the type back to the src type. */
+ Instruction *UUI = getUniqueUser(UI);
+ if (UUI && UUI->getOpcode() == Instruction::BitCast &&
+ cast<BitCastInst>(UUI)->getDestTy() == Ty) {
+ Value *V = BinaryOperator::Create(Instruction::FSub,
+ ConstantFP::get(Ty, 0),
+ I->getOperand(0), "", I);
+ UUI->replaceAllUsesWith(V);
+ toErase.push_back(UUI);
+ }
+ }
+ }
+
+ if (toErase.empty())
+ return false;
+
+ ProcessErase(toErase);
+ return true;
+}
+
+bool CombineCasts::runOnFunction(Function &F)
+{
+ bool Changed = false;
+ SmallVector<LoadInst *, 16> Loads;
+ SmallVector<StoreInst *, 16> Stores;
+
+ /* Collect all guest memory and non-volatile cpu state loads/stores. */
+ for (auto II = inst_begin(F), EE = inst_end(F); II != EE; II++) {
+ Instruction *I = &*II;
+
+ if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
+ if (MF->isGuestMemory(LI) || !LI->isVolatile())
+ Loads.push_back(LI);
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
+ if (MF->isGuestMemory(SI) || !SI->isVolatile())
+ Stores.push_back(SI);
+ }
+ }
+
+ for (auto LI : Loads)
+ Changed |= combineLoadCast(LI);
+ for (auto SI : Stores)
+ Changed |= combineStoreCast(SI);
+
+ if (toErase.size())
+ ProcessErase(toErase);
+
+ Changed |= combineCastCast(F);
+ Changed |= simplifySignChange(F);
+
+ return Changed;
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
OpenPOWER on IntegriCloud