/* * (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(I); if (MemTransferInst *MTI = dyn_cast(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(NumBytes) || MTI->isVolatile()) return false; /* Remove this instruction if the access size is zero. */ size_t Len = cast(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(I)) { /* memset */ Value *Src = MSI->getValue(); Value *Dst = MSI->getDest(); Value *NumBytes = MSI->getLength(); if (CI->getArgOperand(0)->getType() != Int8PtrTy || !isa(Src) || !isa(NumBytes) || MSI->isVolatile()) return false; size_t Val = cast(Src)->getZExtValue(); size_t Len = cast(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(Inst)) { if (replaceMemoryIntrinsic(II)) continue; if (isa(II)) toErase.push_back(II); } } ProcessErase(toErase); return true; } /* * vim: ts=8 sts=4 sw=4 expandtab */