/* * Copyright © 2012 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ /** * \file llvm_intrinisc_lowering.cpp * \author Yang Rong */ #include "llvm_includes.hpp" #include "llvm/llvm_gen_backend.hpp" #include "sys/map.hpp" using namespace llvm; namespace gbe { class InstrinsicLowering : public BasicBlockPass { public: static char ID; InstrinsicLowering() : BasicBlockPass(ID) {} void getAnalysisUsage(AnalysisUsage &AU) const { } #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 40 virtual StringRef getPassName() const #else virtual const char *getPassName() const #endif { return "SPIR backend: lowering instrinsics"; } static char convertSpaceToName(Value *val) { const uint32_t space = val->getType()->getPointerAddressSpace(); switch(space) { case 0: return 'p'; case 1: return 'g'; case 2: return 'c'; case 3: return 'l'; case 4: return 'n'; default: assert(0 && "Non support address space"); return '\0'; } } static CallInst *replaceCallWith(const char *NewFn, CallInst *CI, Value **ArgBegin, Value **ArgEnd, Type *RetTy) { // If we haven't already looked up this function, check to see if the // program already contains a function with this name. Module *M = CI->getParent()->getParent()->getParent(); // Get or insert the definition now. std::vector ParamTys; for (Value** I = ArgBegin; I != ArgEnd; ++I) ParamTys.push_back((*I)->getType()); Constant* FCache = M->getOrInsertFunction(NewFn, FunctionType::get(RetTy, ParamTys, false)); IRBuilder<> Builder(CI->getParent(), BasicBlock::iterator(CI)); SmallVector Args(ArgBegin, ArgEnd); CallInst *NewCI = Builder.CreateCall(FCache, Args); NewCI->setName(CI->getName()); if (!CI->use_empty()) CI->replaceAllUsesWith(NewCI); CI->eraseFromParent(); return NewCI; } virtual bool runOnBasicBlock(BasicBlock &BB) { bool changedBlock = false; Module *M = BB.getParent()->getParent(); DataLayout TD(M); LLVMContext &Context = BB.getContext(); for (BasicBlock::iterator DI = BB.begin(); DI != BB.end(); ) { Instruction *Inst = &*DI++; CallInst* CI = dyn_cast(Inst); if(CI == NULL) continue; IRBuilder<> Builder(&BB, BasicBlock::iterator(CI)); // only support memcpy and memset if (Function *F = CI->getCalledFunction()) { const Intrinsic::ID intrinsicID = (Intrinsic::ID) F->getIntrinsicID(); if (intrinsicID == 0) continue; switch (intrinsicID) { case Intrinsic::memcpy: { Type *IntPtr = TD.getIntPtrType(Context); Value *Size = Builder.CreateIntCast(CI->getArgOperand(2), IntPtr, /* isSigned */ false); Value *align = Builder.CreateIntCast(CI->getArgOperand(3), IntPtr, /* isSigned */ false); ConstantInt *ci = dyn_cast(align); Value *Ops[3]; Ops[0] = CI->getArgOperand(0); Ops[1] = CI->getArgOperand(1); Ops[2] = Size; char name[24] = "__gen_memcpy_xx"; name[13] = convertSpaceToName(Ops[0]); name[14] = convertSpaceToName(Ops[1]); if(ci && (ci->getZExtValue() % 4 == 0)) //alignment is constant and 4 byte align strcat(name, "_align"); replaceCallWith(name, CI, Ops, Ops+3, Type::getVoidTy(Context)); break; } case Intrinsic::memset: { Value *Op0 = CI->getArgOperand(0); Value *val = Builder.CreateIntCast(CI->getArgOperand(1), IntegerType::getInt8Ty(Context), /* isSigned */ false); Type *IntPtr = TD.getIntPtrType(Op0->getType()); Value *Size = Builder.CreateIntCast(CI->getArgOperand(2), IntPtr, /* isSigned */ false); Value *align = Builder.CreateIntCast(CI->getArgOperand(3), IntPtr, /* isSigned */ false); ConstantInt *ci = dyn_cast(align); Value *Ops[3]; Ops[0] = Op0; // Extend the amount to i32. Ops[1] = val; Ops[2] = Size; char name[24] = "__gen_memset_x"; name[13] = convertSpaceToName(Ops[0]); if(ci && (ci->getZExtValue() % 4 == 0)) //alignment is constant and 4 byte align strcat(name, "_align"); replaceCallWith(name, CI, Ops, Ops+3, Type::getVoidTy(Context)); break; } default: continue; } } } return changedBlock; } }; char InstrinsicLowering::ID = 0; BasicBlockPass *createIntrinsicLoweringPass() { return new InstrinsicLowering(); } } // end namespace