summaryrefslogtreecommitdiffstats
path: root/src/llvm/pass/ReplaceIntrinsic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm/pass/ReplaceIntrinsic.cpp')
-rw-r--r--src/llvm/pass/ReplaceIntrinsic.cpp137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/llvm/pass/ReplaceIntrinsic.cpp b/src/llvm/pass/ReplaceIntrinsic.cpp
new file mode 100644
index 0000000..62505f4
--- /dev/null
+++ b/src/llvm/pass/ReplaceIntrinsic.cpp
@@ -0,0 +1,137 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm-types.h"
+#include "llvm-debug.h"
+#include "llvm-target.h"
+#include "llvm-pass.h"
+
+
+#define PASS_NAME "ReplaceIntrinsic"
+
+/*
+ * HQEMU does not allow helpers to contain any memory or debug intrinsics.
+ * This pass substitutes memory intrinsics to load/store instuctions and
+ * removes debug intrinsics (generated by Clang with -g flag).
+ */
+class ReplaceIntrinsic : public FunctionPass {
+ IVec toErase;
+public:
+ static char ID;
+ explicit ReplaceIntrinsic() : FunctionPass(ID) {}
+
+ Value *ConvertType(Value *V, Type *T, Instruction *InsertPos) {
+ if (likely(V->getType() == T))
+ return V;
+ return new BitCastInst(V, T, "", InsertPos);
+ }
+
+ bool replaceMemoryIntrinsic(IntrinsicInst *I);
+ bool runOnFunction(Function &F);
+};
+
+char ReplaceIntrinsic::ID = 0;
+INITIALIZE_PASS(ReplaceIntrinsic, "replaceintrinsic",
+ "Replace memory and debug intrinsics generated by clang",
+ false, false)
+
+FunctionPass *llvm::createReplaceIntrinsic()
+{
+ return new ReplaceIntrinsic();
+}
+
+
+/*
+ * Transform memcpy/memmove/memset to load/store instruction.
+ * Clang attempts to move memory data using LLVM memory intrinsic instructions.
+ * This causes the statemapping pass to miss some guest states. (Statemapping
+ * only considers guest states accessed by general load/store insts).
+ * So, we simply rewrite the memory intrinsics to load/store instuctions.
+ */
+bool ReplaceIntrinsic::replaceMemoryIntrinsic(IntrinsicInst *I)
+{
+ switch (I->getIntrinsicID()) {
+ case Intrinsic::memset:
+ case Intrinsic::memcpy:
+ case Intrinsic::memmove:
+ break;
+ default:
+ return false;
+ }
+
+ LLVMContext &Context = I->getContext();
+ Type *Int8PtrTy = Type::getInt8PtrTy(Context);
+ CallInst *CI = cast<CallInst>(I);
+
+ if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(I)) {
+ /* memcpy/memmove */
+ Value *Src = MTI->getSource();
+ Value *Dst = MTI->getDest();
+ Value *NumBytes = MTI->getLength();
+
+ if (CI->getArgOperand(0)->getType() != Int8PtrTy ||
+ CI->getArgOperand(1)->getType() != Int8PtrTy ||
+ !isa<ConstantInt>(NumBytes) ||
+ MTI->isVolatile())
+ return false;
+
+ /* Remove this instruction if the access size is zero. */
+ size_t Len = cast<ConstantInt>(NumBytes)->getZExtValue();
+ if (Len == 0)
+ goto done;
+
+ Type *Ty = Type::getIntNPtrTy(Context, Len * 8);
+ Src = ConvertType(Src, Ty, I);
+ Dst = ConvertType(Dst, Ty, I);
+ Src = new LoadInst(Src, "", false, I);
+ new StoreInst(Src, Dst, false, I);
+ } else if (MemSetInst *MSI = dyn_cast<MemSetInst>(I)) {
+ /* memset */
+ Value *Src = MSI->getValue();
+ Value *Dst = MSI->getDest();
+ Value *NumBytes = MSI->getLength();
+
+ if (CI->getArgOperand(0)->getType() != Int8PtrTy ||
+ !isa<ConstantInt>(Src) ||
+ !isa<ConstantInt>(NumBytes) ||
+ MSI->isVolatile())
+ return false;
+
+ size_t Val = cast<ConstantInt>(Src)->getZExtValue();
+ size_t Len = cast<ConstantInt>(NumBytes)->getZExtValue();
+ if (Val != 0)
+ return false;
+ if (Len == 0)
+ goto done;
+
+ Type *Ty = Type::getIntNPtrTy(Context, Len * 8);
+ Src = ConstantInt::get(Type::getIntNTy(Context, Len * 8), 0);
+ Dst = ConvertType(Dst, Ty, I);
+ new StoreInst(Src, Dst, false, I);
+ }
+
+done:
+ toErase.push_back(I);
+ return true;
+}
+
+bool ReplaceIntrinsic::runOnFunction(Function &F)
+{
+ for (auto I = inst_begin(&F), E = inst_end(&F); I != E; ++I) {
+ Instruction *Inst = &*I;
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst)) {
+ if (replaceMemoryIntrinsic(II))
+ continue;
+ if (isa<DbgInfoIntrinsic>(II))
+ toErase.push_back(II);
+ }
+ }
+ ProcessErase(toErase);
+ return true;
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
OpenPOWER on IntegriCloud