/// \brief Returns the allocation data for the given value if it is a call to a /// known allocation function, and NULL otherwise. static const AllocFnsTy *getAllocationData(const Value *V, AllocType AllocTy, const TargetLibraryInfo *TLI, bool LookThroughBitCast = false) { // Skip all intrinsics but duetto.allocate if (const IntrinsicInst* II = dyn_cast<IntrinsicInst>(V)) { if (II->getIntrinsicID() == Intrinsic::duetto_allocate) return &AllocationFnData[0]; return 0; } Function *Callee = getCalledFunction(V, LookThroughBitCast); if (!Callee) return 0; // Make sure that the function is available. StringRef FnName = Callee->getName(); LibFunc::Func TLIFn; if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return 0; unsigned i = 0; bool found = false; for ( ; i < array_lengthof(AllocationFnData); ++i) { if (AllocationFnData[i].Func == TLIFn) { found = true; break; } } if (!found) return 0; const AllocFnsTy *FnData = &AllocationFnData[i]; if ((FnData->AllocTy & AllocTy) != FnData->AllocTy) return 0; // Check function prototype. int FstParam = FnData->FstParam; int SndParam = FnData->SndParam; FunctionType *FTy = Callee->getFunctionType(); if (FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == FnData->NumParams && (FstParam < 0 || (FTy->getParamType(FstParam)->isIntegerTy(32) || FTy->getParamType(FstParam)->isIntegerTy(64))) && (SndParam < 0 || FTy->getParamType(SndParam)->isIntegerTy(32) || FTy->getParamType(SndParam)->isIntegerTy(64))) return FnData; return 0; }
void Function::BuildLazyArguments() const { // Create the arguments vector, all arguments start out unnamed. FunctionType *FT = getFunctionType(); for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { assert(!FT->getParamType(i)->isVoidTy() && "Cannot have void typed arguments!"); ArgumentList.push_back(new Argument(FT->getParamType(i))); } // Clear the lazy arguments bit. unsigned SDC = getSubclassDataFromValue(); const_cast<Function*>(this)->setValueSubclassData(SDC &= ~1); }
/// isFreeCall - Returns non-null if the value is a call to the builtin free() const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) { const CallInst *CI = dyn_cast<CallInst>(I); if (!CI || isa<IntrinsicInst>(CI)) return 0; Function *Callee = CI->getCalledFunction(); if (Callee == 0 || !Callee->isDeclaration()) return 0; StringRef FnName = Callee->getName(); LibFunc::Func TLIFn; if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return 0; if (TLIFn != LibFunc::free && TLIFn != LibFunc::ZdlPv && // operator delete(void*) TLIFn != LibFunc::ZdaPv) // operator delete[](void*) return 0; // Check free prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin // attribute will exist. FunctionType *FTy = Callee->getFunctionType(); if (!FTy->getReturnType()->isVoidTy()) return 0; if (FTy->getNumParams() != 1) return 0; if (FTy->getParamType(0) != Type::getInt8PtrTy(Callee->getContext())) return 0; return CI; }
static Instruction* applyRewriteToCall(Module& M, const CallRewrite* const rw, CallSite cs) { Function* target = cs.getCalledFunction(); assert(target != NULL); Function* newTarget = M.getFunction(rw->function); if (newTarget == NULL) { // There isn't a function, we need to construct it FunctionType* newType = target->getFunctionType(); std::vector<Type*> argTypes; for (std::vector<unsigned>::const_iterator i = rw->args.begin(), e = rw->args.end(); i != e; ++i) argTypes.push_back(newType->getParamType(*i)); ArrayRef<Type*> params(argTypes); newType = FunctionType::get(target->getReturnType(), params, target->isVarArg()); newTarget = dyn_cast<Function> (M.getOrInsertFunction(rw->function, newType)); } assert(newTarget != NULL); return specializeCallSite(cs.getInstruction(), newTarget, rw->args); }
/// isFreeCall - Returns non-null if the value is a call to the builtin free() static const CallInst* isFreeCall(const Value* I) { const CallInst* CI = dyn_cast<CallInst>(I); if (!CI) return 0; Function* Callee = CI->getCalledFunction(); if (Callee == 0 || !Callee->isDeclaration()) return 0; if (Callee->getName() != "free" /*&& Callee->getName() != "my_free" && Callee->getName() != "_ZdlPv" && // operator delete(void*) Callee->getName() != "_ZdaPv"*/) // operator delete[](void*) return 0; // Check free prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin // attribute will exist. FunctionType* FTy = Callee->getFunctionType(); if (!FTy->getReturnType()->isVoidTy()) return 0; if (FTy->getNumParams() != 1) return 0; if (FTy->getParamType(0) != Type::getInt8PtrTy(Callee->getContext())) return 0; return CI; }
void TypeDuplicater::RemoveNonLocalTypes(Module &M){ std::set<Function *> UndefinedFunctions; for(auto IF = M.begin(), EF = M.end(); IF != EF; ++IF){ Function *F = &*IF; if(F->isDeclaration()) UndefinedFunctions.insert(F); } for(auto F: UndefinedFunctions){ FunctionType *FuncType = cast<FunctionType>(F->getFunctionType()); for(int i=0; i<FuncType->getNumParams(); i++){ Type *T =FuncType->getParamType(i); while(T->isPointerTy()) T = T->getPointerElementType(); if(auto *ST = dyn_cast<StructType>(T)) RawStructs.erase(ST); } Type *T =FuncType->getReturnType(); while(T->isPointerTy()) T = T->getPointerElementType(); if(auto *ST = dyn_cast<StructType>(T)) RawStructs.erase(ST); } }
/// isFreeCall - Returns non-null if the value is a call to the builtin free() const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) { bool IsNoBuiltinCall; const Function *Callee = getCalledFunction(I, /*LookThroughBitCast=*/false, IsNoBuiltinCall); if (Callee == nullptr || IsNoBuiltinCall) return nullptr; StringRef FnName = Callee->getName(); LibFunc TLIFn; if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return nullptr; unsigned ExpectedNumParams; if (TLIFn == LibFunc_free || TLIFn == LibFunc_ZdlPv || // operator delete(void*) TLIFn == LibFunc_ZdaPv || // operator delete[](void*) TLIFn == LibFunc_msvc_delete_ptr32 || // operator delete(void*) TLIFn == LibFunc_msvc_delete_ptr64 || // operator delete(void*) TLIFn == LibFunc_msvc_delete_array_ptr32 || // operator delete[](void*) TLIFn == LibFunc_msvc_delete_array_ptr64) // operator delete[](void*) ExpectedNumParams = 1; else if (TLIFn == LibFunc_ZdlPvj || // delete(void*, uint) TLIFn == LibFunc_ZdlPvm || // delete(void*, ulong) TLIFn == LibFunc_ZdlPvRKSt9nothrow_t || // delete(void*, nothrow) TLIFn == LibFunc_ZdlPvSt11align_val_t || // delete(void*, align_val_t) TLIFn == LibFunc_ZdaPvj || // delete[](void*, uint) TLIFn == LibFunc_ZdaPvm || // delete[](void*, ulong) TLIFn == LibFunc_ZdaPvRKSt9nothrow_t || // delete[](void*, nothrow) TLIFn == LibFunc_ZdaPvSt11align_val_t || // delete[](void*, align_val_t) TLIFn == LibFunc_msvc_delete_ptr32_int || // delete(void*, uint) TLIFn == LibFunc_msvc_delete_ptr64_longlong || // delete(void*, ulonglong) TLIFn == LibFunc_msvc_delete_ptr32_nothrow || // delete(void*, nothrow) TLIFn == LibFunc_msvc_delete_ptr64_nothrow || // delete(void*, nothrow) TLIFn == LibFunc_msvc_delete_array_ptr32_int || // delete[](void*, uint) TLIFn == LibFunc_msvc_delete_array_ptr64_longlong || // delete[](void*, ulonglong) TLIFn == LibFunc_msvc_delete_array_ptr32_nothrow || // delete[](void*, nothrow) TLIFn == LibFunc_msvc_delete_array_ptr64_nothrow) // delete[](void*, nothrow) ExpectedNumParams = 2; else if (TLIFn == LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t || // delete(void*, align_val_t, nothrow) TLIFn == LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t) // delete[](void*, align_val_t, nothrow) ExpectedNumParams = 3; else return nullptr; // Check free prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin // attribute will exist. FunctionType *FTy = Callee->getFunctionType(); if (!FTy->getReturnType()->isVoidTy()) return nullptr; if (FTy->getNumParams() != ExpectedNumParams) return nullptr; if (FTy->getParamType(0) != Type::getInt8PtrTy(Callee->getContext())) return nullptr; return dyn_cast<CallInst>(I); }
/// \brief Returns the allocation data for the given value if it is a call to a /// known allocation function, and NULL otherwise. static const AllocFnsTy *getAllocationData(const Value *V, AllocType AllocTy, const TargetLibraryInfo *TLI, bool LookThroughBitCast = false) { // Skip intrinsics if (isa<IntrinsicInst>(V)) return nullptr; Function *Callee = getCalledFunction(V, LookThroughBitCast); if (!Callee) return nullptr; // Make sure that the function is available. StringRef FnName = Callee->getName(); LibFunc::Func TLIFn; if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return nullptr; const AllocFnsTy *FnData = std::find_if(std::begin(AllocationFnData), std::end(AllocationFnData), [TLIFn](const AllocFnsTy &Fn) { return Fn.Func == TLIFn; }); if (FnData == std::end(AllocationFnData)) return nullptr; if ((FnData->AllocTy & AllocTy) != FnData->AllocTy) return nullptr; // Check function prototype. int FstParam = FnData->FstParam; int SndParam = FnData->SndParam; FunctionType *FTy = Callee->getFunctionType(); if (FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == FnData->NumParams && (FstParam < 0 || (FTy->getParamType(FstParam)->isIntegerTy(32) || FTy->getParamType(FstParam)->isIntegerTy(64))) && (SndParam < 0 || FTy->getParamType(SndParam)->isIntegerTy(32) || FTy->getParamType(SndParam)->isIntegerTy(64))) return FnData; return nullptr; }
// We accept bswap for a limited set of types (i16, i32, i64). // The various backends are able to generate instructions to // implement the intrinsic. Also, i16 and i64 are easy to // implement as along as there is a way to do i32. static bool isWhitelistedBswap(const Function *F) { FunctionType *FT = F->getFunctionType(); if (FT->getNumParams() != 1) return false; Type *ParamType = FT->getParamType(0); LLVMContext &C = F->getContext(); Type *AcceptableTypes[] = { Type::getInt16Ty(C), Type::getInt32Ty(C), Type::getInt64Ty(C) }; return TypeAcceptable(ParamType, AcceptableTypes); }
static void check(Value *Func, ArrayRef<Value *> Args) { FunctionType *FTy = cast<FunctionType>(cast<PointerType>(Func->getType())->getElementType()); assert((Args.size() == FTy->getNumParams() || (FTy->isVarArg() && Args.size() > FTy->getNumParams())) && "XXCalling a function with bad signature!"); for (unsigned i = 0; i != Args.size(); ++i) { if (!(FTy->getParamType(i) == Args[i]->getType())) { errs() << "types:\n "; FTy->getParamType(i)->dump(); errs() << "\n "; Args[i]->getType()->dump(); errs() << "\n"; } assert((i >= FTy->getNumParams() || FTy->getParamType(i) == Args[i]->getType()) && "YYCalling a function with a bad signature!"); } }
/// isFreeCall - Returns non-null if the value is a call to the builtin free() const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) { const CallInst *CI = dyn_cast<CallInst>(I); if (!CI || isa<IntrinsicInst>(CI)) return nullptr; Function *Callee = CI->getCalledFunction(); if (Callee == nullptr) return nullptr; StringRef FnName = Callee->getName(); LibFunc::Func TLIFn; if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return nullptr; unsigned ExpectedNumParams; if (TLIFn == LibFunc::free || TLIFn == LibFunc::ZdlPv || // operator delete(void*) TLIFn == LibFunc::ZdaPv || // operator delete[](void*) TLIFn == LibFunc::msvc_delete_ptr32 || // operator delete(void*) TLIFn == LibFunc::msvc_delete_ptr64 || // operator delete(void*) TLIFn == LibFunc::msvc_delete_array_ptr32 || // operator delete[](void*) TLIFn == LibFunc::msvc_delete_array_ptr64) // operator delete[](void*) ExpectedNumParams = 1; else if (TLIFn == LibFunc::ZdlPvj || // delete(void*, uint) TLIFn == LibFunc::ZdlPvm || // delete(void*, ulong) TLIFn == LibFunc::ZdlPvRKSt9nothrow_t || // delete(void*, nothrow) TLIFn == LibFunc::ZdaPvj || // delete[](void*, uint) TLIFn == LibFunc::ZdaPvm || // delete[](void*, ulong) TLIFn == LibFunc::ZdaPvRKSt9nothrow_t || // delete[](void*, nothrow) TLIFn == LibFunc::msvc_delete_ptr32_int || // delete(void*, uint) TLIFn == LibFunc::msvc_delete_ptr64_longlong || // delete(void*, ulonglong) TLIFn == LibFunc::msvc_delete_ptr32_nothrow || // delete(void*, nothrow) TLIFn == LibFunc::msvc_delete_ptr64_nothrow || // delete(void*, nothrow) TLIFn == LibFunc::msvc_delete_array_ptr32_int || // delete[](void*, uint) TLIFn == LibFunc::msvc_delete_array_ptr64_longlong || // delete[](void*, ulonglong) TLIFn == LibFunc::msvc_delete_array_ptr32_nothrow || // delete[](void*, nothrow) TLIFn == LibFunc::msvc_delete_array_ptr64_nothrow) // delete[](void*, nothrow) ExpectedNumParams = 2; else return nullptr; // Check free prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin // attribute will exist. FunctionType *FTy = Callee->getFunctionType(); if (!FTy->getReturnType()->isVoidTy()) return nullptr; if (FTy->getNumParams() != ExpectedNumParams) return nullptr; if (FTy->getParamType(0) != Type::getInt8PtrTy(Callee->getContext())) return nullptr; return CI; }
static bool isCallocCall(const CallInst *CI) { if (!CI) return false; Function *Callee = CI->getCalledFunction(); if (Callee == 0 || !Callee->isDeclaration()) return false; if (Callee->getName() != "calloc") return false; // Check malloc prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin // attribute exists. FunctionType *FTy = Callee->getFunctionType(); return FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == 2 && ((FTy->getParamType(0)->isIntegerTy(32) && FTy->getParamType(1)->isIntegerTy(32)) || (FTy->getParamType(0)->isIntegerTy(64) && FTy->getParamType(1)->isIntegerTy(64))); }
// TODO Copy-paste static bool isMallocCall(const CallInst* CI) { if (!CI) return false; Function* Callee = CI->getCalledFunction(); if (Callee == 0 || !Callee->isDeclaration()) return false; if (Callee->getName() != "malloc" /*&& Callee->getName() != "my_malloc" && Callee->getName() != "_Znwj" && // operator new(unsigned int) Callee->getName() != "_Znwm" && // operator new(unsigned long) Callee->getName() != "_Znaj" && // operator new[](unsigned int) Callee->getName() != "_Znam"*/) // operator new[](unsigned long) return false; // Check malloc prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin // attribute will exist. FunctionType* FTy = Callee->getFunctionType(); return FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == 1 && (FTy->getParamType(0)->isIntegerTy(32) || FTy->getParamType(0)->isIntegerTy(64)); }
/// Creates a hash-code for the function which is the same for any two /// functions that will compare equal, without looking at the instructions /// inside the function. static unsigned profileFunction(const Function *F) { FunctionType *FTy = F->getFunctionType(); FoldingSetNodeID ID; ID.AddInteger(F->size()); ID.AddInteger(F->getCallingConv()); ID.AddBoolean(F->hasGC()); ID.AddBoolean(FTy->isVarArg()); ID.AddInteger(getTypeIDForHash(FTy->getReturnType())); for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) ID.AddInteger(getTypeIDForHash(FTy->getParamType(i))); return ID.ComputeHash(); }
/// Replace \p Thunk with a simple tail call to \p ToFunc. Also add parameters /// to the call to \p ToFunc, which are defined by the FuncIdx's value in /// \p Params. void SwiftMergeFunctions::writeThunk(Function *ToFunc, Function *Thunk, const ParamInfos &Params, unsigned FuncIdx) { // Delete the existing content of Thunk. Thunk->dropAllReferences(); BasicBlock *BB = BasicBlock::Create(Thunk->getContext(), "", Thunk); IRBuilder<> Builder(BB); SmallVector<Value *, 16> Args; unsigned ParamIdx = 0; FunctionType *ToFuncTy = ToFunc->getFunctionType(); // Add arguments which are passed through Thunk. for (Argument & AI : Thunk->args()) { Args.push_back(createCast(Builder, &AI, ToFuncTy->getParamType(ParamIdx))); ++ParamIdx; } // Add new arguments defined by Params. for (const ParamInfo &PI : Params) { assert(ParamIdx < ToFuncTy->getNumParams()); Args.push_back(createCast(Builder, PI.Values[FuncIdx], ToFuncTy->getParamType(ParamIdx))); ++ParamIdx; } CallInst *CI = Builder.CreateCall(ToFunc, Args); CI->setTailCall(); CI->setCallingConv(ToFunc->getCallingConv()); CI->setAttributes(ToFunc->getAttributes()); if (Thunk->getReturnType()->isVoidTy()) { Builder.CreateRetVoid(); } else { Builder.CreateRet(createCast(Builder, CI, Thunk->getReturnType())); } LLVM_DEBUG(dbgs() << " writeThunk: " << Thunk->getName() << '\n'); ++NumSwiftThunksWritten; }
/// \brief Returns the allocation data for the given value if it is a call to a /// known allocation function, and NULL otherwise. static const AllocFnsTy *getAllocationData(const Value *V, AllocType AllocTy, bool LookThroughBitCast = false) { Function *Callee = getCalledFunction(V, LookThroughBitCast); if (!Callee) return 0; unsigned i = 0; bool found = false; for ( ; i < array_lengthof(AllocationFnData); ++i) { if (Callee->getName() == AllocationFnData[i].Name) { found = true; break; } } if (!found) return 0; const AllocFnsTy *FnData = &AllocationFnData[i]; if ((FnData->AllocTy & AllocTy) == 0) return 0; // Check function prototype. // FIXME: Check the nobuiltin metadata?? (PR5130) int FstParam = FnData->FstParam; int SndParam = FnData->SndParam; FunctionType *FTy = Callee->getFunctionType(); if (FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == FnData->NumParams && (FstParam < 0 || (FTy->getParamType(FstParam)->isIntegerTy(32) || FTy->getParamType(FstParam)->isIntegerTy(64))) && (SndParam < 0 || FTy->getParamType(SndParam)->isIntegerTy(32) || FTy->getParamType(SndParam)->isIntegerTy(64))) return FnData; return 0; }
// a simple function 'prototype' printer void printFuncProtoType(Function *F) { F->getReturnType()->dump(); errs() << " " << F->getName() << "("; FunctionType * FTY = F->getFunctionType(); unsigned params = FTY->getNumParams(); unsigned i; for (i = 0; i < params; i++) { FTY->getParamType(i)->dump(); if (i != params - 1) errs() << ","; } errs() << ")"; }
/// Returns the allocation data for the given value if it's either a call to a /// known allocation function, or a call to a function with the allocsize /// attribute. static Optional<AllocFnsTy> getAllocationDataForFunction(const Function *Callee, AllocType AllocTy, const TargetLibraryInfo *TLI) { // Make sure that the function is available. StringRef FnName = Callee->getName(); LibFunc TLIFn; if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return None; const auto *Iter = find_if( AllocationFnData, [TLIFn](const std::pair<LibFunc, AllocFnsTy> &P) { return P.first == TLIFn; }); if (Iter == std::end(AllocationFnData)) return None; const AllocFnsTy *FnData = &Iter->second; if ((FnData->AllocTy & AllocTy) != FnData->AllocTy) return None; // Check function prototype. int FstParam = FnData->FstParam; int SndParam = FnData->SndParam; FunctionType *FTy = Callee->getFunctionType(); if (FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == FnData->NumParams && (FstParam < 0 || (FTy->getParamType(FstParam)->isIntegerTy(32) || FTy->getParamType(FstParam)->isIntegerTy(64))) && (SndParam < 0 || FTy->getParamType(SndParam)->isIntegerTy(32) || FTy->getParamType(SndParam)->isIntegerTy(64))) return *FnData; return None; }
// Replace G with a simple tail call to bitcast(F). Also replace direct uses // of G with bitcast(F). Deletes G. void MergeFunctions::writeThunk(Function *F, Function *G) { if (!G->mayBeOverridden()) { // Redirect direct callers of G to F. replaceDirectCallers(G, F); } // If G was internal then we may have replaced all uses of G with F. If so, // stop here and delete G. There's no need for a thunk. if (G->hasLocalLinkage() && G->use_empty()) { G->eraseFromParent(); return; } Function *NewG = Function::Create(G->getFunctionType(), G->getLinkage(), "", G->getParent()); BasicBlock *BB = BasicBlock::Create(F->getContext(), "", NewG); IRBuilder<false> Builder(BB); SmallVector<Value *, 16> Args; unsigned i = 0; FunctionType *FFTy = F->getFunctionType(); for (Function::arg_iterator AI = NewG->arg_begin(), AE = NewG->arg_end(); AI != AE; ++AI) { Args.push_back(createCast(Builder, (Value*)AI, FFTy->getParamType(i))); ++i; } CallInst *CI = Builder.CreateCall(F, Args); CI->setTailCall(); CI->setCallingConv(F->getCallingConv()); if (NewG->getReturnType()->isVoidTy()) { Builder.CreateRetVoid(); } else { Builder.CreateRet(createCast(Builder, CI, NewG->getReturnType())); } NewG->copyAttributesFrom(G); NewG->takeName(G); removeUsers(G); G->replaceAllUsesWith(NewG); G->eraseFromParent(); DEBUG(dbgs() << "writeThunk: " << NewG->getName() << '\n'); ++NumThunksWritten; }
bool SimplifyFortifiedLibCalls::fold(CallInst *CI, const DataLayout *TD, const TargetLibraryInfo *TLI) { // We really need DataLayout for later. if (!TD) return false; this->CI = CI; Function *Callee = CI->getCalledFunction(); StringRef Name = Callee->getName(); FunctionType *FT = Callee->getFunctionType(); LLVMContext &Context = CI->getParent()->getContext(); IRBuilder<> B(CI); if (Name == "__memcpy_chk") { // Check if this has the right signature. if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) || !FT->getParamType(0)->isPointerTy() || !FT->getParamType(1)->isPointerTy() || FT->getParamType(2) != TD->getIntPtrType(Context) || FT->getParamType(3) != TD->getIntPtrType(Context)) return false; if (isFoldable(3, 2, false)) { B.CreateMemCpy(CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), 1); replaceCall(CI->getArgOperand(0)); return true; } return false; } // Should be similar to memcpy. if (Name == "__mempcpy_chk") { return false; } if (Name == "__memmove_chk") { // Check if this has the right signature. if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) || !FT->getParamType(0)->isPointerTy() || !FT->getParamType(1)->isPointerTy() || FT->getParamType(2) != TD->getIntPtrType(Context) || FT->getParamType(3) != TD->getIntPtrType(Context)) return false; if (isFoldable(3, 2, false)) { B.CreateMemMove(CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), 1); replaceCall(CI->getArgOperand(0)); return true; } return false; } if (Name == "__memset_chk") { // Check if this has the right signature. if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) || !FT->getParamType(0)->isPointerTy() || !FT->getParamType(1)->isIntegerTy() || FT->getParamType(2) != TD->getIntPtrType(Context) || FT->getParamType(3) != TD->getIntPtrType(Context)) return false; if (isFoldable(3, 2, false)) { Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false); B.CreateMemSet(CI->getArgOperand(0), Val, CI->getArgOperand(2), 1); replaceCall(CI->getArgOperand(0)); return true; } return false; } if (Name == "__strcpy_chk" || Name == "__stpcpy_chk") { // Check if this has the right signature. if (FT->getNumParams() != 3 || FT->getReturnType() != FT->getParamType(0) || FT->getParamType(0) != FT->getParamType(1) || FT->getParamType(0) != Type::getInt8PtrTy(Context) || FT->getParamType(2) != TD->getIntPtrType(Context)) return 0; // If a) we don't have any length information, or b) we know this will // fit then just lower to a plain st[rp]cpy. Otherwise we'll keep our // st[rp]cpy_chk call which may fail at runtime if the size is too long. // TODO: It might be nice to get a maximum length out of the possible // string lengths for varying. if (isFoldable(2, 1, true)) { Value *Ret = EmitStrCpy(CI->getArgOperand(0), CI->getArgOperand(1), B, TD, TLI, Name.substr(2, 6)); if (!Ret) return false; replaceCall(Ret); return true; } return false; } if (Name == "__strncpy_chk" || Name == "__stpncpy_chk") { // Check if this has the right signature. if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) || FT->getParamType(0) != FT->getParamType(1) || FT->getParamType(0) != Type::getInt8PtrTy(Context) || !FT->getParamType(2)->isIntegerTy() || FT->getParamType(3) != TD->getIntPtrType(Context)) return false; if (isFoldable(3, 2, false)) { Value *Ret = EmitStrNCpy(CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), B, TD, TLI, Name.substr(2, 7)); if (!Ret) return false; replaceCall(Ret); return true; } return false; } if (Name == "__strcat_chk") { return false; } if (Name == "__strncat_chk") { return false; } return false; }
bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, LibFunc::Func F, const DataLayout *DL) const { LLVMContext &Ctx = FTy.getContext(); Type *PCharTy = Type::getInt8PtrTy(Ctx); Type *SizeTTy = DL ? DL->getIntPtrType(Ctx, /*AS=*/0) : nullptr; auto IsSizeTTy = [SizeTTy](Type *Ty) { return SizeTTy ? Ty == SizeTTy : Ty->isIntegerTy(); }; unsigned NumParams = FTy.getNumParams(); switch (F) { case LibFunc::strlen: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType()->isIntegerTy()); case LibFunc::strchr: case LibFunc::strrchr: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1)->isIntegerTy()); case LibFunc::strtol: case LibFunc::strtod: case LibFunc::strtof: case LibFunc::strtoul: case LibFunc::strtoll: case LibFunc::strtold: case LibFunc::strtoull: return ((NumParams == 2 || NumParams == 3) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::strcat: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1) == FTy.getReturnType()); case LibFunc::strncat: return (NumParams == 3 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1) == FTy.getReturnType() && FTy.getParamType(2)->isIntegerTy()); case LibFunc::strcpy_chk: case LibFunc::stpcpy_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; // fallthrough case LibFunc::strcpy: case LibFunc::stpcpy: return (NumParams == 2 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getParamType(0) == PCharTy); case LibFunc::strncpy_chk: case LibFunc::stpncpy_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; // fallthrough case LibFunc::strncpy: case LibFunc::stpncpy: return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getParamType(0) == PCharTy && FTy.getParamType(2)->isIntegerTy()); case LibFunc::strxfrm: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::strcmp: return (NumParams == 2 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(0) == FTy.getParamType(1)); case LibFunc::strncmp: return (NumParams == 3 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getParamType(2)->isIntegerTy()); case LibFunc::strspn: case LibFunc::strcspn: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getReturnType()->isIntegerTy()); case LibFunc::strcoll: case LibFunc::strcasecmp: case LibFunc::strncasecmp: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::strstr: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::strpbrk: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0) == FTy.getParamType(1)); case LibFunc::strtok: case LibFunc::strtok_r: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::scanf: case LibFunc::setbuf: case LibFunc::setvbuf: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc::strdup: case LibFunc::strndup: return (NumParams >= 1 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy()); case LibFunc::sscanf: case LibFunc::stat: case LibFunc::statvfs: case LibFunc::sprintf: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::snprintf: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::setitimer: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::system: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc::malloc: return (NumParams == 1 && FTy.getReturnType()->isPointerTy()); case LibFunc::memcmp: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); case LibFunc::memchr: case LibFunc::memrchr: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy(32) && FTy.getParamType(2)->isIntegerTy() && FTy.getReturnType()->isPointerTy()); case LibFunc::modf: case LibFunc::modff: case LibFunc::modfl: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::memcpy_chk: case LibFunc::memmove_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; // fallthrough case LibFunc::memcpy: case LibFunc::mempcpy: case LibFunc::memmove: return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && IsSizeTTy(FTy.getParamType(2))); case LibFunc::memset_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; // fallthrough case LibFunc::memset: return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy() && IsSizeTTy(FTy.getParamType(2))); case LibFunc::memccpy: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::memalign: return (FTy.getReturnType()->isPointerTy()); case LibFunc::realloc: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType()->isPointerTy()); case LibFunc::read: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); case LibFunc::rewind: case LibFunc::rmdir: case LibFunc::remove: case LibFunc::realpath: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc::rename: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::readlink: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::write: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); case LibFunc::bcopy: case LibFunc::bcmp: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::bzero: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::calloc: return (NumParams == 2 && FTy.getReturnType()->isPointerTy()); case LibFunc::atof: case LibFunc::atoi: case LibFunc::atol: case LibFunc::atoll: case LibFunc::ferror: case LibFunc::getenv: case LibFunc::getpwnam: case LibFunc::pclose: case LibFunc::perror: case LibFunc::printf: case LibFunc::puts: case LibFunc::uname: case LibFunc::under_IO_getc: case LibFunc::unlink: case LibFunc::unsetenv: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc::chmod: case LibFunc::chown: case LibFunc::clearerr: case LibFunc::closedir: case LibFunc::ctermid: case LibFunc::fclose: case LibFunc::feof: case LibFunc::fflush: case LibFunc::fgetc: case LibFunc::fileno: case LibFunc::flockfile: case LibFunc::free: case LibFunc::fseek: case LibFunc::fseeko64: case LibFunc::fseeko: case LibFunc::fsetpos: case LibFunc::ftell: case LibFunc::ftello64: case LibFunc::ftello: case LibFunc::ftrylockfile: case LibFunc::funlockfile: case LibFunc::getc: case LibFunc::getc_unlocked: case LibFunc::getlogin_r: case LibFunc::mkdir: case LibFunc::mktime: case LibFunc::times: return (NumParams != 0 && FTy.getParamType(0)->isPointerTy()); case LibFunc::access: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::fopen: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fdopen: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fputc: case LibFunc::fstat: case LibFunc::frexp: case LibFunc::frexpf: case LibFunc::frexpl: case LibFunc::fstatvfs: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::fgets: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::fread: return (NumParams == 4 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(3)->isPointerTy()); case LibFunc::fwrite: return (NumParams == 4 && FTy.getReturnType()->isIntegerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy() && FTy.getParamType(2)->isIntegerTy() && FTy.getParamType(3)->isPointerTy()); case LibFunc::fputs: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fscanf: case LibFunc::fprintf: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fgetpos: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::gets: case LibFunc::getchar: case LibFunc::getitimer: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::ungetc: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::utime: case LibFunc::utimes: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::putc: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::pread: case LibFunc::pwrite: return (NumParams == 4 && FTy.getParamType(1)->isPointerTy()); case LibFunc::popen: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::vscanf: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::vsscanf: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::vfscanf: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::valloc: return (FTy.getReturnType()->isPointerTy()); case LibFunc::vprintf: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::vfprintf: case LibFunc::vsprintf: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::vsnprintf: return (NumParams == 4 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::open: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::opendir: return (NumParams == 1 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy()); case LibFunc::tmpfile: return (FTy.getReturnType()->isPointerTy()); case LibFunc::htonl: case LibFunc::htons: case LibFunc::ntohl: case LibFunc::ntohs: case LibFunc::lstat: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::lchown: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy()); case LibFunc::qsort: return (NumParams == 4 && FTy.getParamType(3)->isPointerTy()); case LibFunc::dunder_strdup: case LibFunc::dunder_strndup: return (NumParams >= 1 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy()); case LibFunc::dunder_strtok_r: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); case LibFunc::under_IO_putc: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::dunder_isoc99_scanf: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc::stat64: case LibFunc::lstat64: case LibFunc::statvfs64: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::dunder_isoc99_sscanf: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fopen64: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::tmpfile64: return (FTy.getReturnType()->isPointerTy()); case LibFunc::fstat64: case LibFunc::fstatvfs64: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::open64: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::gettimeofday: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::Znwj: // new(unsigned int); case LibFunc::Znwm: // new(unsigned long); case LibFunc::Znaj: // new[](unsigned int); case LibFunc::Znam: // new[](unsigned long); case LibFunc::msvc_new_int: // new(unsigned int); case LibFunc::msvc_new_longlong: // new(unsigned long long); case LibFunc::msvc_new_array_int: // new[](unsigned int); case LibFunc::msvc_new_array_longlong: // new[](unsigned long long); return (NumParams == 1); case LibFunc::memset_pattern16: return (!FTy.isVarArg() && NumParams == 3 && isa<PointerType>(FTy.getParamType(0)) && isa<PointerType>(FTy.getParamType(1)) && isa<IntegerType>(FTy.getParamType(2))); // int __nvvm_reflect(const char *); case LibFunc::nvvm_reflect: return (NumParams == 1 && isa<PointerType>(FTy.getParamType(0))); case LibFunc::sin: case LibFunc::sinf: case LibFunc::sinl: case LibFunc::cos: case LibFunc::cosf: case LibFunc::cosl: case LibFunc::tan: case LibFunc::tanf: case LibFunc::tanl: case LibFunc::exp: case LibFunc::expf: case LibFunc::expl: case LibFunc::exp2: case LibFunc::exp2f: case LibFunc::exp2l: case LibFunc::log: case LibFunc::logf: case LibFunc::logl: case LibFunc::log10: case LibFunc::log10f: case LibFunc::log10l: case LibFunc::log2: case LibFunc::log2f: case LibFunc::log2l: case LibFunc::fabs: case LibFunc::fabsf: case LibFunc::fabsl: case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl: case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill: case LibFunc::trunc: case LibFunc::truncf: case LibFunc::truncl: case LibFunc::rint: case LibFunc::rintf: case LibFunc::rintl: case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl: case LibFunc::round: case LibFunc::roundf: case LibFunc::roundl: case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl: return (NumParams == 1 && FTy.getReturnType()->isFloatingPointTy() && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc::fmin: case LibFunc::fminf: case LibFunc::fminl: case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl: case LibFunc::copysign: case LibFunc::copysignf: case LibFunc::copysignl: case LibFunc::pow: case LibFunc::powf: case LibFunc::powl: return (NumParams == 2 && FTy.getReturnType()->isFloatingPointTy() && FTy.getReturnType() == FTy.getParamType(0) && FTy.getReturnType() == FTy.getParamType(1)); case LibFunc::ffs: case LibFunc::ffsl: case LibFunc::ffsll: case LibFunc::isdigit: case LibFunc::isascii: case LibFunc::toascii: return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isIntegerTy()); case LibFunc::fls: case LibFunc::flsl: case LibFunc::flsll: case LibFunc::abs: case LibFunc::labs: case LibFunc::llabs: return (NumParams == 1 && FTy.getReturnType()->isIntegerTy() && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc::cxa_atexit: return (NumParams == 3 && FTy.getReturnType()->isIntegerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::sinpi: case LibFunc::cospi: return (NumParams == 1 && FTy.getReturnType()->isDoubleTy() && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc::sinpif: case LibFunc::cospif: return (NumParams == 1 && FTy.getReturnType()->isFloatTy() && FTy.getReturnType() == FTy.getParamType(0)); default: // Assume the other functions are correct. // FIXME: It'd be really nice to cover them all. return true; } }
bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) { LLVMContext &C = M.getContext(); IRBuilder<> IRB(C); Function *SetjmpF = M.getFunction("setjmp"); Function *LongjmpF = M.getFunction("longjmp"); bool SetjmpUsed = SetjmpF && !SetjmpF->use_empty(); bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty(); bool DoSjLj = EnableSjLj && (SetjmpUsed || LongjmpUsed); // Create global variables __THREW__, threwValue, and __tempRet0, which are // used in common for both exception handling and setjmp/longjmp handling ThrewGV = createGlobalVariableI32(M, IRB, "__THREW__"); ThrewValueGV = createGlobalVariableI32(M, IRB, "__threwValue"); TempRet0GV = createGlobalVariableI32(M, IRB, "__tempRet0"); bool Changed = false; // Exception handling if (EnableEH) { // Register __resumeException function FunctionType *ResumeFTy = FunctionType::get(IRB.getVoidTy(), IRB.getInt8PtrTy(), false); ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage, ResumeFName, &M); // Register llvm_eh_typeid_for function FunctionType *EHTypeIDTy = FunctionType::get(IRB.getInt32Ty(), IRB.getInt8PtrTy(), false); EHTypeIDF = Function::Create(EHTypeIDTy, GlobalValue::ExternalLinkage, EHTypeIDFName, &M); for (Function &F : M) { if (F.isDeclaration()) continue; Changed |= runEHOnFunction(F); } } // Setjmp/longjmp handling if (DoSjLj) { Changed = true; // We have setjmp or longjmp somewhere // Register saveSetjmp function FunctionType *SetjmpFTy = SetjmpF->getFunctionType(); SmallVector<Type *, 4> Params = {SetjmpFTy->getParamType(0), IRB.getInt32Ty(), Type::getInt32PtrTy(C), IRB.getInt32Ty()}; FunctionType *FTy = FunctionType::get(Type::getInt32PtrTy(C), Params, false); SaveSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage, SaveSetjmpFName, &M); // Register testSetjmp function Params = {IRB.getInt32Ty(), Type::getInt32PtrTy(C), IRB.getInt32Ty()}; FTy = FunctionType::get(IRB.getInt32Ty(), Params, false); TestSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage, TestSetjmpFName, &M); if (LongjmpF) { // Replace all uses of longjmp with emscripten_longjmp_jmpbuf, which is // defined in JS code EmLongjmpJmpbufF = Function::Create(LongjmpF->getFunctionType(), GlobalValue::ExternalLinkage, EmLongjmpJmpbufFName, &M); LongjmpF->replaceAllUsesWith(EmLongjmpJmpbufF); } FTy = FunctionType::get(IRB.getVoidTy(), {IRB.getInt32Ty(), IRB.getInt32Ty()}, false); EmLongjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage, EmLongjmpFName, &M); // Only traverse functions that uses setjmp in order not to insert // unnecessary prep / cleanup code in every function SmallPtrSet<Function *, 8> SetjmpUsers; for (User *U : SetjmpF->users()) { auto *UI = cast<Instruction>(U); SetjmpUsers.insert(UI->getFunction()); } for (Function *F : SetjmpUsers) runSjLjOnFunction(*F); } if (!Changed) { // Delete unused global variables and functions ThrewGV->eraseFromParent(); ThrewValueGV->eraseFromParent(); TempRet0GV->eraseFromParent(); if (ResumeF) ResumeF->eraseFromParent(); if (EHTypeIDF) EHTypeIDF->eraseFromParent(); if (EmLongjmpF) EmLongjmpF->eraseFromParent(); if (SaveSetjmpF) SaveSetjmpF->eraseFromParent(); if (TestSetjmpF) TestSetjmpF->eraseFromParent(); return false; } // If we have made any changes while doing exception handling or // setjmp/longjmp handling, we have to create these functions for JavaScript // to call. createSetThrewFunction(M); createSetTempRet0Function(M); return true; }
/// cmpType - compares two types, /// defines total ordering among the types set. /// See method declaration comments for more details. int FunctionComparator::cmpType(Type *TyL, Type *TyR) const { PointerType *PTyL = dyn_cast<PointerType>(TyL); PointerType *PTyR = dyn_cast<PointerType>(TyR); if (DL) { if (PTyL && PTyL->getAddressSpace() == 0) TyL = DL->getIntPtrType(TyL); if (PTyR && PTyR->getAddressSpace() == 0) TyR = DL->getIntPtrType(TyR); } if (TyL == TyR) return 0; if (int Res = cmpNumbers(TyL->getTypeID(), TyR->getTypeID())) return Res; switch (TyL->getTypeID()) { default: llvm_unreachable("Unknown type!"); // Fall through in Release mode. case Type::IntegerTyID: case Type::VectorTyID: // TyL == TyR would have returned true earlier. return cmpNumbers((uint64_t)TyL, (uint64_t)TyR); case Type::VoidTyID: case Type::FloatTyID: case Type::DoubleTyID: case Type::X86_FP80TyID: case Type::FP128TyID: case Type::PPC_FP128TyID: case Type::LabelTyID: case Type::MetadataTyID: return 0; case Type::PointerTyID: { assert(PTyL && PTyR && "Both types must be pointers here."); return cmpNumbers(PTyL->getAddressSpace(), PTyR->getAddressSpace()); } case Type::StructTyID: { StructType *STyL = cast<StructType>(TyL); StructType *STyR = cast<StructType>(TyR); if (STyL->getNumElements() != STyR->getNumElements()) return cmpNumbers(STyL->getNumElements(), STyR->getNumElements()); if (STyL->isPacked() != STyR->isPacked()) return cmpNumbers(STyL->isPacked(), STyR->isPacked()); for (unsigned i = 0, e = STyL->getNumElements(); i != e; ++i) { if (int Res = cmpType(STyL->getElementType(i), STyR->getElementType(i))) return Res; } return 0; } case Type::FunctionTyID: { FunctionType *FTyL = cast<FunctionType>(TyL); FunctionType *FTyR = cast<FunctionType>(TyR); if (FTyL->getNumParams() != FTyR->getNumParams()) return cmpNumbers(FTyL->getNumParams(), FTyR->getNumParams()); if (FTyL->isVarArg() != FTyR->isVarArg()) return cmpNumbers(FTyL->isVarArg(), FTyR->isVarArg()); if (int Res = cmpType(FTyL->getReturnType(), FTyR->getReturnType())) return Res; for (unsigned i = 0, e = FTyL->getNumParams(); i != e; ++i) { if (int Res = cmpType(FTyL->getParamType(i), FTyR->getParamType(i))) return Res; } return 0; } case Type::ArrayTyID: { ArrayType *ATyL = cast<ArrayType>(TyL); ArrayType *ATyR = cast<ArrayType>(TyR); if (ATyL->getNumElements() != ATyR->getNumElements()) return cmpNumbers(ATyL->getNumElements(), ATyR->getNumElements()); return cmpType(ATyL->getElementType(), ATyR->getElementType()); } } }
/// cmpType - compares two types, /// defines total ordering among the types set. /// See method declaration comments for more details. int FunctionComparator::cmpTypes(Type *TyL, Type *TyR) const { PointerType *PTyL = dyn_cast<PointerType>(TyL); PointerType *PTyR = dyn_cast<PointerType>(TyR); const DataLayout &DL = FnL->getParent()->getDataLayout(); if (PTyL && PTyL->getAddressSpace() == 0) TyL = DL.getIntPtrType(TyL); if (PTyR && PTyR->getAddressSpace() == 0) TyR = DL.getIntPtrType(TyR); if (TyL == TyR) return 0; if (int Res = cmpNumbers(TyL->getTypeID(), TyR->getTypeID())) return Res; switch (TyL->getTypeID()) { default: llvm_unreachable("Unknown type!"); // Fall through in Release mode. LLVM_FALLTHROUGH; case Type::IntegerTyID: return cmpNumbers(cast<IntegerType>(TyL)->getBitWidth(), cast<IntegerType>(TyR)->getBitWidth()); // TyL == TyR would have returned true earlier, because types are uniqued. case Type::VoidTyID: case Type::FloatTyID: case Type::DoubleTyID: case Type::X86_FP80TyID: case Type::FP128TyID: case Type::PPC_FP128TyID: case Type::LabelTyID: case Type::MetadataTyID: case Type::TokenTyID: return 0; case Type::PointerTyID: { assert(PTyL && PTyR && "Both types must be pointers here."); return cmpNumbers(PTyL->getAddressSpace(), PTyR->getAddressSpace()); } case Type::StructTyID: { StructType *STyL = cast<StructType>(TyL); StructType *STyR = cast<StructType>(TyR); if (STyL->getNumElements() != STyR->getNumElements()) return cmpNumbers(STyL->getNumElements(), STyR->getNumElements()); if (STyL->isPacked() != STyR->isPacked()) return cmpNumbers(STyL->isPacked(), STyR->isPacked()); for (unsigned i = 0, e = STyL->getNumElements(); i != e; ++i) { if (int Res = cmpTypes(STyL->getElementType(i), STyR->getElementType(i))) return Res; } return 0; } case Type::FunctionTyID: { FunctionType *FTyL = cast<FunctionType>(TyL); FunctionType *FTyR = cast<FunctionType>(TyR); if (FTyL->getNumParams() != FTyR->getNumParams()) return cmpNumbers(FTyL->getNumParams(), FTyR->getNumParams()); if (FTyL->isVarArg() != FTyR->isVarArg()) return cmpNumbers(FTyL->isVarArg(), FTyR->isVarArg()); if (int Res = cmpTypes(FTyL->getReturnType(), FTyR->getReturnType())) return Res; for (unsigned i = 0, e = FTyL->getNumParams(); i != e; ++i) { if (int Res = cmpTypes(FTyL->getParamType(i), FTyR->getParamType(i))) return Res; } return 0; } case Type::ArrayTyID: case Type::VectorTyID: { auto *STyL = cast<SequentialType>(TyL); auto *STyR = cast<SequentialType>(TyR); if (STyL->getNumElements() != STyR->getNumElements()) return cmpNumbers(STyL->getNumElements(), STyR->getNumElements()); return cmpTypes(STyL->getElementType(), STyR->getElementType()); } } }
GenericValue MCJIT::runFunction(Function *F, const std::vector<GenericValue> &ArgValues) { assert(F && "Function *F was null at entry to run()"); void *FPtr = getPointerToFunction(F); assert(FPtr && "Pointer to fn's code was null after getPointerToFunction"); FunctionType *FTy = F->getFunctionType(); Type *RetTy = FTy->getReturnType(); assert((FTy->getNumParams() == ArgValues.size() || (FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) && "Wrong number of arguments passed into function!"); assert(FTy->getNumParams() == ArgValues.size() && "This doesn't support passing arguments through varargs (yet)!"); // Handle some common cases first. These cases correspond to common `main' // prototypes. if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) { switch (ArgValues.size()) { case 3: if (FTy->getParamType(0)->isIntegerTy(32) && FTy->getParamType(1)->isPointerTy() && FTy->getParamType(2)->isPointerTy()) { int (*PF)(int, char **, const char **) = (int(*)(int, char **, const char **))(intptr_t)FPtr; // Call the function. GenericValue rv; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), (char **)GVTOP(ArgValues[1]), (const char **)GVTOP(ArgValues[2]))); return rv; } break; case 2: if (FTy->getParamType(0)->isIntegerTy(32) && FTy->getParamType(1)->isPointerTy()) { int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr; // Call the function. GenericValue rv; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), (char **)GVTOP(ArgValues[1]))); return rv; } break; case 1: if (FTy->getNumParams() == 1 && FTy->getParamType(0)->isIntegerTy(32)) { GenericValue rv; int (*PF)(int) = (int(*)(int))(intptr_t)FPtr; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue())); return rv; } break; } } // Handle cases where no arguments are passed first. if (ArgValues.empty()) { GenericValue rv; switch (RetTy->getTypeID()) { default: llvm_unreachable("Unknown return type for function call!"); case Type::IntegerTyID: { unsigned BitWidth = cast<IntegerType>(RetTy)->getBitWidth(); if (BitWidth == 1) rv.IntVal = APInt(BitWidth, ((bool(*)())(intptr_t)FPtr)()); else if (BitWidth <= 8) rv.IntVal = APInt(BitWidth, ((char(*)())(intptr_t)FPtr)()); else if (BitWidth <= 16) rv.IntVal = APInt(BitWidth, ((short(*)())(intptr_t)FPtr)()); else if (BitWidth <= 32) rv.IntVal = APInt(BitWidth, ((int(*)())(intptr_t)FPtr)()); else if (BitWidth <= 64) rv.IntVal = APInt(BitWidth, ((int64_t(*)())(intptr_t)FPtr)()); else llvm_unreachable("Integer types > 64 bits not supported"); return rv; } case Type::VoidTyID: rv.IntVal = APInt(32, ((int(*)())(intptr_t)FPtr)()); return rv; case Type::FloatTyID: rv.FloatVal = ((float(*)())(intptr_t)FPtr)(); return rv; case Type::DoubleTyID: rv.DoubleVal = ((double(*)())(intptr_t)FPtr)(); return rv; case Type::X86_FP80TyID: case Type::FP128TyID: case Type::PPC_FP128TyID: llvm_unreachable("long double not supported yet"); case Type::PointerTyID: return PTOGV(((void*(*)())(intptr_t)FPtr)()); } } llvm_unreachable("Full-featured argument passing not supported yet!"); }
/// PromotePrivates Implementation - Used to promote pointers from new/delete operations to global segment in HSA /// bool PromotePrivates::runOnFunction(Function &F) { if (F.getName().find("cxxamp_trampoline") == StringRef::npos) return false; // Need refactor! Module *M = F.getParent(); if ((M->getFunction(/*"_Znwj"*/ "_Znwm") == NULL) && (M->getFunction(/*"_Znaj"*/ "_Znam") == NULL)) return false; //errs() << "Execute PromotePrivates::runOnFunction: " << F.getName() << "\n"; LLVMContext& C = F.getContext(); std::vector<Instruction*> NeedPromoted; for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I) { NewedMemoryAnalyzer NMA(F); NMA.analyze(*I); if (NMA.isNewed()) NeedPromoted.push_back(&*I); } #if 0 for (unsigned i = 0; i < NeedPromoted.size(); i++) errs () << *NeedPromoted[i] << "\n"; #endif while (!NeedPromoted.empty()) { Instruction *I = NeedPromoted.back(); #if 0 llvm::errs() << "NeedPromoted:" << *I << "\n"; #endif if (StoreInst *SI = dyn_cast<StoreInst>(I)) { IRBuilder<> Builder(SI); //Value *StoreAddr = Builder.CreatePointerCast(SI->getPointerOperand(), Type::getInt64PtrTy(C, 1)); PointerType *DestTy = SI->getPointerOperand()->getType()->getPointerElementType()->getPointerTo(1); Value *StoreAddr = Builder.CreatePointerCast(SI->getPointerOperand(), DestTy); StoreInst* nSI = new StoreInst(SI->getValueOperand(), StoreAddr); ReplaceInstWithInst(SI, nSI); } if (LoadInst *LI = dyn_cast<LoadInst>(I)) { IRBuilder<> Builder(LI); Value *LoadAddr = Builder.CreatePointerCast(LI->getPointerOperand(), Type::getInt32PtrTy(C, 1)); LoadInst* nLI = new LoadInst(LoadAddr); ReplaceInstWithInst(LI, nLI); } if (CallInst *CI = dyn_cast<CallInst>(I)) { IRBuilder<> Builder(CI); PointerType *DestTy = CI->getArgOperand(0)->getType()->getPointerElementType()->getPointerTo(1); Value *MemsetAddr = Builder.CreatePointerCast(CI->getArgOperand(0), DestTy); std::vector<Value*> ArgsVec; ArgsVec.push_back(MemsetAddr); for (int i = 1, e = CI->getNumArgOperands(); i < e; i++) { ArgsVec.push_back(CI->getArgOperand(i)); } ArrayRef<Value*> Args(ArgsVec); FunctionType *MemsetFuncType = CI->getCalledFunction()->getFunctionType(); Type *MemsetRetType = MemsetFuncType->getReturnType(); std::vector<Type*> ArgsTypeVec; ArgsTypeVec.push_back(DestTy); for (int i = 1, e = MemsetFuncType->getNumParams(); i < e; i++) { ArgsTypeVec.push_back(MemsetFuncType->getParamType(i)); } ArrayRef<Type*> ArgsType(ArgsTypeVec); FunctionType *nMemsetFuncType = FunctionType::get(MemsetRetType, ArgsType, false); M->getOrInsertFunction("llvm.memset.p1i8.i64", nMemsetFuncType); Function *MemsetFunc = M->getFunction("llvm.memset.p1i8.i64"); CallInst* nCI = CallInst::Create(MemsetFunc, Args); ReplaceInstWithInst(CI, nCI); } #if 0 if (StoreInst *SI = dyn_cast<StoreInst>(NeedPromoted.back()) ) { IRBuilder<> Builder(SI); Value *StoreAddr = Builder.CreatePointerCast(SI->getPointerOperand(), Type::getInt32PtrTy(C, 1)); StoreInst* nSI = new StoreInst(SI->getValueOperand(), StoreAddr); ReplaceInstWithInst(SI, nSI); } else if (LoadInst *LI = dyn_cast<LoadInst>(NeedPromoted.back()) ) { IRBuilder<> Builder(LI); Value *StoreAddr = Builder.CreatePointerCast(LI->getPointerOperand(), Type::getInt32PtrTy(C, 1)); LoadInst* nLI = new LoadInst(/*SI->getValueOperand(), */StoreAddr); ReplaceInstWithInst(LI, nLI); } #endif NeedPromoted.pop_back(); } //F.dump(); //errs() << "Finished PromotePrivates::runOnFunction\n"; return true; }
// ============================================================================= // andOOPIsGone (formerly: createProcess) // // Formerly, OOP permitted the same SC_{METHOD,THREAD} functions to apply // to each copy of a SC_MODULE. Aaaaand it's gone ! // (but OTOH we enable better optimizations) // Creates a new C-style function that calls the old member function with the // given sc_module. The call is then inlined. // FIXME: assumes the method is non-virtual and that sc_module is the first // inherited class of the SC_MODULE // ============================================================================= Function *TwetoPassImpl::andOOPIsGone(Function * oldProc, sc_core::sc_module * initiatorMod) { if (!oldProc) return NULL; // can't statically optimize if the address of the module isn't predictible // TODO: also handle already-static variables, which also have // fixed $pc-relative addresses if (staticopt == optlevel && !permalloc::is_from (initiatorMod)) return NULL; LLVMContext & context = getGlobalContext(); FunctionType *funType = oldProc->getFunctionType(); Type *type = funType->getParamType(0); FunctionType *newProcType = FunctionType::get(oldProc->getReturnType(), ArrayRef < Type * >(), false); // Create the new function std::ostringstream id; id << proc_counter++; std::string name = oldProc->getName().str() + std::string("_clone_") + id.str(); Function *newProc = Function::Create(newProcType, Function::ExternalLinkage, name, this->llvmMod); assert(newProc->empty()); newProc->addFnAttr(Attribute::InlineHint); // Create call to old function BasicBlock *bb = BasicBlock::Create(context, "entry", newProc); IRBuilder <> *irb = new IRBuilder <> (context); irb->SetInsertPoint(bb); Value* thisAddr = createRelocatablePointer (type, initiatorMod, irb); CallInst *ci = irb->CreateCall(oldProc, ArrayRef < Value * >(std::vector<Value*>(1,thisAddr))); //bb->getInstList().insert(ci, thisAddr); if (ci->getType()->isVoidTy()) irb->CreateRetVoid(); else irb->CreateRet(ci); // The function should be valid now verifyFunction(*newProc); { // Inline the call DataLayout *td = new DataLayout(this->llvmMod); InlineFunctionInfo i(NULL, td); bool success = InlineFunction(ci, i); assert(success); verifyFunction(*newProc); } // further optimize the function inlineBasicIO (initiatorMod, newProc); newProc->dump(); return newProc; }
// FIXME: This might have been relevant for the old JIT but the MCJIT // has a completly different implementation so this comment below is // likely irrelevant and misleading. // // For performance purposes we construct the stub in such a way that the // arguments pointer is passed through the static global variable gTheArgsP in // this file. This is done so that the stub function prototype trivially matches // the special cases that the JIT knows how to directly call. If this is not // done, then the jit will end up generating a nullary stub just to call our // stub, for every single function call. Function *ExternalDispatcherImpl::createDispatcher(Function *target, Instruction *inst, Module *module) { if (!resolveSymbol(target->getName())) return 0; CallSite cs; if (inst->getOpcode() == Instruction::Call) { cs = CallSite(cast<CallInst>(inst)); } else { cs = CallSite(cast<InvokeInst>(inst)); } Value **args = new Value *[cs.arg_size()]; std::vector<Type *> nullary; // MCJIT functions need unique names, or wrong function can be called. // The module identifier is included because for the MCJIT we need // unique function names across all `llvm::Modules`s. std::string fnName = "dispatcher_" + target->getName().str() + module->getModuleIdentifier(); Function *dispatcher = Function::Create(FunctionType::get(Type::getVoidTy(ctx), nullary, false), GlobalVariable::ExternalLinkage, fnName, module); BasicBlock *dBB = BasicBlock::Create(ctx, "entry", dispatcher); // Get a Value* for &gTheArgsP, as an i64**. Instruction *argI64sp = new IntToPtrInst( ConstantInt::get(Type::getInt64Ty(ctx), (uintptr_t)(void *)&gTheArgsP), PointerType::getUnqual(PointerType::getUnqual(Type::getInt64Ty(ctx))), "argsp", dBB); Instruction *argI64s = new LoadInst(argI64sp, "args", dBB); // Get the target function type. FunctionType *FTy = cast<FunctionType>( cast<PointerType>(target->getType())->getElementType()); // Each argument will be passed by writing it into gTheArgsP[i]. unsigned i = 0, idx = 2; for (CallSite::arg_iterator ai = cs.arg_begin(), ae = cs.arg_end(); ai != ae; ++ai, ++i) { // Determine the type the argument will be passed as. This accomodates for // the corresponding code in Executor.cpp for handling calls to bitcasted // functions. Type *argTy = (i < FTy->getNumParams() ? FTy->getParamType(i) : (*ai)->getType()); Instruction *argI64p = GetElementPtrInst::Create( KLEE_LLVM_GEP_TYPE(nullptr) argI64s, ConstantInt::get(Type::getInt32Ty(ctx), idx), "", dBB); Instruction *argp = new BitCastInst(argI64p, PointerType::getUnqual(argTy), "", dBB); args[i] = new LoadInst(argp, "", dBB); unsigned argSize = argTy->getPrimitiveSizeInBits(); idx += ((!!argSize ? argSize : 64) + 63) / 64; } Constant *dispatchTarget = module->getOrInsertFunction( target->getName(), FTy, target->getAttributes()); Instruction *result = CallInst::Create( dispatchTarget, llvm::ArrayRef<Value *>(args, args + i), "", dBB); if (result->getType() != Type::getVoidTy(ctx)) { Instruction *resp = new BitCastInst( argI64s, PointerType::getUnqual(result->getType()), "", dBB); new StoreInst(result, resp, dBB); } ReturnInst::Create(ctx, dBB); delete[] args; return dispatcher; }
/// run - Start execution with the specified function and arguments. /// GenericValue JIT::runFunction(Function *F, const std::vector<GenericValue> &ArgValues) { assert(F && "Function *F was null at entry to run()"); void *FPtr = getPointerToFunction(F); assert(FPtr && "Pointer to fn's code was null after getPointerToFunction"); FunctionType *FTy = F->getFunctionType(); Type *RetTy = FTy->getReturnType(); assert((FTy->getNumParams() == ArgValues.size() || (FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) && "Wrong number of arguments passed into function!"); assert(FTy->getNumParams() == ArgValues.size() && "This doesn't support passing arguments through varargs (yet)!"); // Handle some common cases first. These cases correspond to common `main' // prototypes. if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) { switch (ArgValues.size()) { case 3: if (FTy->getParamType(0)->isIntegerTy(32) && FTy->getParamType(1)->isPointerTy() && FTy->getParamType(2)->isPointerTy()) { int (*PF)(int, char **, const char **) = (int(*)(int, char **, const char **))(intptr_t)FPtr; // Call the function. GenericValue rv; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), (char **)GVTOP(ArgValues[1]), (const char **)GVTOP(ArgValues[2]))); return rv; } break; case 2: if (FTy->getParamType(0)->isIntegerTy(32) && FTy->getParamType(1)->isPointerTy()) { int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr; // Call the function. GenericValue rv; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), (char **)GVTOP(ArgValues[1]))); return rv; } break; case 1: if (FTy->getParamType(0)->isIntegerTy(32)) { GenericValue rv; int (*PF)(int) = (int(*)(int))(intptr_t)FPtr; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue())); return rv; } if (FTy->getParamType(0)->isPointerTy()) { GenericValue rv; int (*PF)(char *) = (int(*)(char *))(intptr_t)FPtr; rv.IntVal = APInt(32, PF((char*)GVTOP(ArgValues[0]))); return rv; } break; } } // Handle cases where no arguments are passed first. if (ArgValues.empty()) { GenericValue rv; switch (RetTy->getTypeID()) { default: llvm_unreachable("Unknown return type for function call!"); case Type::IntegerTyID: { unsigned BitWidth = cast<IntegerType>(RetTy)->getBitWidth(); if (BitWidth == 1) rv.IntVal = APInt(BitWidth, ((bool(*)())(intptr_t)FPtr)()); else if (BitWidth <= 8) rv.IntVal = APInt(BitWidth, ((char(*)())(intptr_t)FPtr)()); else if (BitWidth <= 16) rv.IntVal = APInt(BitWidth, ((short(*)())(intptr_t)FPtr)()); else if (BitWidth <= 32) rv.IntVal = APInt(BitWidth, ((int(*)())(intptr_t)FPtr)()); else if (BitWidth <= 64) rv.IntVal = APInt(BitWidth, ((int64_t(*)())(intptr_t)FPtr)()); else llvm_unreachable("Integer types > 64 bits not supported"); return rv; } case Type::VoidTyID: rv.IntVal = APInt(32, ((int(*)())(intptr_t)FPtr)()); return rv; case Type::FloatTyID: rv.FloatVal = ((float(*)())(intptr_t)FPtr)(); return rv; case Type::DoubleTyID: rv.DoubleVal = ((double(*)())(intptr_t)FPtr)(); return rv; case Type::X86_FP80TyID: case Type::FP128TyID: case Type::PPC_FP128TyID: llvm_unreachable("long double not supported yet"); case Type::PointerTyID: return PTOGV(((void*(*)())(intptr_t)FPtr)()); } } // Okay, this is not one of our quick and easy cases. Because we don't have a // full FFI, we have to codegen a nullary stub function that just calls the // function we are interested in, passing in constants for all of the // arguments. Make this function and return. // First, create the function. FunctionType *STy=FunctionType::get(RetTy, false); Function *Stub = Function::Create(STy, Function::InternalLinkage, "", F->getParent()); // Insert a basic block. BasicBlock *StubBB = BasicBlock::Create(F->getContext(), "", Stub); // Convert all of the GenericValue arguments over to constants. Note that we // currently don't support varargs. SmallVector<Value*, 8> Args; for (unsigned i = 0, e = ArgValues.size(); i != e; ++i) { Constant *C = 0; Type *ArgTy = FTy->getParamType(i); const GenericValue &AV = ArgValues[i]; switch (ArgTy->getTypeID()) { default: llvm_unreachable("Unknown argument type for function call!"); case Type::IntegerTyID: C = ConstantInt::get(F->getContext(), AV.IntVal); break; case Type::FloatTyID: C = ConstantFP::get(F->getContext(), APFloat(AV.FloatVal)); break; case Type::DoubleTyID: C = ConstantFP::get(F->getContext(), APFloat(AV.DoubleVal)); break; case Type::PPC_FP128TyID: case Type::X86_FP80TyID: case Type::FP128TyID: C = ConstantFP::get(F->getContext(), APFloat(ArgTy->getFltSemantics(), AV.IntVal)); break; case Type::PointerTyID: void *ArgPtr = GVTOP(AV); if (sizeof(void*) == 4) C = ConstantInt::get(Type::getInt32Ty(F->getContext()), (int)(intptr_t)ArgPtr); else C = ConstantInt::get(Type::getInt64Ty(F->getContext()), (intptr_t)ArgPtr); // Cast the integer to pointer C = ConstantExpr::getIntToPtr(C, ArgTy); break; } Args.push_back(C); } CallInst *TheCall = CallInst::Create(F, Args, "", StubBB); TheCall->setCallingConv(F->getCallingConv()); TheCall->setTailCall(); if (!TheCall->getType()->isVoidTy()) // Return result of the call. ReturnInst::Create(F->getContext(), TheCall, StubBB); else ReturnInst::Create(F->getContext(), StubBB); // Just return void. // Finally, call our nullary stub function. GenericValue Result = runFunction(Stub, std::vector<GenericValue>()); // Erase it, since no other function can have a reference to it. Stub->eraseFromParent(); // And return the result. return Result; }
static bool ffiInvoke(RawFunc Fn, Function *F, ArrayRef<GenericValue> ArgVals, const DataLayout &TD, GenericValue &Result) { ffi_cif cif; FunctionType *FTy = F->getFunctionType(); const unsigned NumArgs = F->arg_size(); // TODO: We don't have type information about the remaining arguments, because // this information is never passed into ExecutionEngine::runFunction(). if (ArgVals.size() > NumArgs && F->isVarArg()) { report_fatal_error("Calling external var arg function '" + F->getName() + "' is not supported by the Interpreter."); } unsigned ArgBytes = 0; std::vector<ffi_type*> args(NumArgs); for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end(); A != E; ++A) { const unsigned ArgNo = A->getArgNo(); Type *ArgTy = FTy->getParamType(ArgNo); args[ArgNo] = ffiTypeFor(ArgTy); ArgBytes += TD.getTypeStoreSize(ArgTy); } SmallVector<uint8_t, 128> ArgData; ArgData.resize(ArgBytes); uint8_t *ArgDataPtr = ArgData.data(); SmallVector<void*, 16> values(NumArgs); for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end(); A != E; ++A) { const unsigned ArgNo = A->getArgNo(); Type *ArgTy = FTy->getParamType(ArgNo); values[ArgNo] = ffiValueFor(ArgTy, ArgVals[ArgNo], ArgDataPtr); ArgDataPtr += TD.getTypeStoreSize(ArgTy); } Type *RetTy = FTy->getReturnType(); ffi_type *rtype = ffiTypeFor(RetTy); if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NumArgs, rtype, args.data()) == FFI_OK) { SmallVector<uint8_t, 128> ret; if (RetTy->getTypeID() != Type::VoidTyID) ret.resize(TD.getTypeStoreSize(RetTy)); ffi_call(&cif, Fn, ret.data(), values.data()); switch (RetTy->getTypeID()) { case Type::IntegerTyID: switch (cast<IntegerType>(RetTy)->getBitWidth()) { case 8: Result.IntVal = APInt(8 , *(int8_t *) ret.data()); break; case 16: Result.IntVal = APInt(16, *(int16_t*) ret.data()); break; case 32: Result.IntVal = APInt(32, *(int32_t*) ret.data()); break; case 64: Result.IntVal = APInt(64, *(int64_t*) ret.data()); break; } break; case Type::FloatTyID: Result.FloatVal = *(float *) ret.data(); break; case Type::DoubleTyID: Result.DoubleVal = *(double*) ret.data(); break; case Type::PointerTyID: Result.PointerVal = *(void **) ret.data(); break; default: break; } return true; } return false; }