1e332c22cSNicolas Vasilache //===- FunctionCallUtils.cpp - Utilities for C function calls -------------===// 2e332c22cSNicolas Vasilache // 3e332c22cSNicolas Vasilache // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e332c22cSNicolas Vasilache // See https://llvm.org/LICENSE.txt for license information. 5e332c22cSNicolas Vasilache // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e332c22cSNicolas Vasilache // 7e332c22cSNicolas Vasilache //===----------------------------------------------------------------------===// 8e332c22cSNicolas Vasilache // 9e332c22cSNicolas Vasilache // This file implements helper functions to call common simple C functions in 10e332c22cSNicolas Vasilache // LLVMIR (e.g. amon others to support printing and debugging). 11e332c22cSNicolas Vasilache // 12e332c22cSNicolas Vasilache //===----------------------------------------------------------------------===// 13e332c22cSNicolas Vasilache 14e332c22cSNicolas Vasilache #include "mlir/Dialect/LLVMIR/FunctionCallUtils.h" 15e332c22cSNicolas Vasilache #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 16e332c22cSNicolas Vasilache #include "mlir/IR/Builders.h" 17e332c22cSNicolas Vasilache #include "mlir/IR/OpDefinition.h" 18e332c22cSNicolas Vasilache #include "mlir/Support/LLVM.h" 19e332c22cSNicolas Vasilache 20e332c22cSNicolas Vasilache using namespace mlir; 21e332c22cSNicolas Vasilache using namespace mlir::LLVM; 22e332c22cSNicolas Vasilache 23e332c22cSNicolas Vasilache /// Helper functions to lookup or create the declaration for commonly used 24e332c22cSNicolas Vasilache /// external C function calls. The list of functions provided here must be 25e332c22cSNicolas Vasilache /// implemented separately (e.g. as part of a support runtime library or as 26e332c22cSNicolas Vasilache /// part of the libc). 27e332c22cSNicolas Vasilache static constexpr llvm::StringRef kPrintI64 = "printI64"; 28e332c22cSNicolas Vasilache static constexpr llvm::StringRef kPrintU64 = "printU64"; 29657f60a0SAart Bik static constexpr llvm::StringRef kPrintF16 = "printF16"; 30657f60a0SAart Bik static constexpr llvm::StringRef kPrintBF16 = "printBF16"; 31e332c22cSNicolas Vasilache static constexpr llvm::StringRef kPrintF32 = "printF32"; 32e332c22cSNicolas Vasilache static constexpr llvm::StringRef kPrintF64 = "printF64"; 333be3883eSBenjamin Maxwell static constexpr llvm::StringRef kPrintString = "printString"; 34e332c22cSNicolas Vasilache static constexpr llvm::StringRef kPrintOpen = "printOpen"; 35e332c22cSNicolas Vasilache static constexpr llvm::StringRef kPrintClose = "printClose"; 36e332c22cSNicolas Vasilache static constexpr llvm::StringRef kPrintComma = "printComma"; 37e332c22cSNicolas Vasilache static constexpr llvm::StringRef kPrintNewline = "printNewline"; 38d04c2b2fSMehdi Amini static constexpr llvm::StringRef kMalloc = "malloc"; 39d04c2b2fSMehdi Amini static constexpr llvm::StringRef kAlignedAlloc = "aligned_alloc"; 40d04c2b2fSMehdi Amini static constexpr llvm::StringRef kFree = "free"; 4129fbe600SMichele Scuttari static constexpr llvm::StringRef kGenericAlloc = "_mlir_memref_to_llvm_alloc"; 4229fbe600SMichele Scuttari static constexpr llvm::StringRef kGenericAlignedAlloc = 4329fbe600SMichele Scuttari "_mlir_memref_to_llvm_aligned_alloc"; 4429fbe600SMichele Scuttari static constexpr llvm::StringRef kGenericFree = "_mlir_memref_to_llvm_free"; 45db2de8d7SStephan Herhut static constexpr llvm::StringRef kMemRefCopy = "memrefCopy"; 46e332c22cSNicolas Vasilache 47e332c22cSNicolas Vasilache /// Generic print function lookupOrCreate helper. 48*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 49*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreateFn(Operation *moduleOp, StringRef name, 50*e84f6b6aSLuohao Wang ArrayRef<Type> paramTypes, Type resultType, 51*e84f6b6aSLuohao Wang bool isVarArg, bool isReserved) { 52f543dfd1SChristopher Bate assert(moduleOp->hasTrait<OpTrait::SymbolTable>() && 53f543dfd1SChristopher Bate "expected SymbolTable operation"); 54f543dfd1SChristopher Bate auto func = llvm::dyn_cast_or_null<LLVM::LLVMFuncOp>( 55f543dfd1SChristopher Bate SymbolTable::lookupSymbolIn(moduleOp, name)); 56*e84f6b6aSLuohao Wang auto funcT = LLVMFunctionType::get(resultType, paramTypes, isVarArg); 57*e84f6b6aSLuohao Wang // Assert the signature of the found function is same as expected 58*e84f6b6aSLuohao Wang if (func) { 59*e84f6b6aSLuohao Wang if (funcT != func.getFunctionType()) { 60*e84f6b6aSLuohao Wang if (isReserved) { 61*e84f6b6aSLuohao Wang func.emitError("redefinition of reserved function '") 62*e84f6b6aSLuohao Wang << name << "' of different type " << func.getFunctionType() 63*e84f6b6aSLuohao Wang << " is prohibited"; 64*e84f6b6aSLuohao Wang } else { 65*e84f6b6aSLuohao Wang func.emitError("redefinition of function '") 66*e84f6b6aSLuohao Wang << name << "' of different type " << funcT << " is prohibited"; 67*e84f6b6aSLuohao Wang } 68*e84f6b6aSLuohao Wang return failure(); 69*e84f6b6aSLuohao Wang } 70e332c22cSNicolas Vasilache return func; 71*e84f6b6aSLuohao Wang } 72f543dfd1SChristopher Bate OpBuilder b(moduleOp->getRegion(0)); 73e332c22cSNicolas Vasilache return b.create<LLVM::LLVMFuncOp>( 74e332c22cSNicolas Vasilache moduleOp->getLoc(), name, 75fd85a64fSIngo Müller LLVM::LLVMFunctionType::get(resultType, paramTypes, isVarArg)); 76e332c22cSNicolas Vasilache } 77e332c22cSNicolas Vasilache 78*e84f6b6aSLuohao Wang static FailureOr<LLVM::LLVMFuncOp> 79*e84f6b6aSLuohao Wang lookupOrCreateReservedFn(Operation *moduleOp, StringRef name, 80*e84f6b6aSLuohao Wang ArrayRef<Type> paramTypes, Type resultType) { 81*e84f6b6aSLuohao Wang return lookupOrCreateFn(moduleOp, name, paramTypes, resultType, 82*e84f6b6aSLuohao Wang /*isVarArg=*/false, /*isReserved=*/true); 83*e84f6b6aSLuohao Wang } 84*e84f6b6aSLuohao Wang 85*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 86*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreatePrintI64Fn(Operation *moduleOp) { 87*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 88*e84f6b6aSLuohao Wang moduleOp, kPrintI64, IntegerType::get(moduleOp->getContext(), 64), 89e332c22cSNicolas Vasilache LLVM::LLVMVoidType::get(moduleOp->getContext())); 90e332c22cSNicolas Vasilache } 91e332c22cSNicolas Vasilache 92*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 93*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreatePrintU64Fn(Operation *moduleOp) { 94*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 95*e84f6b6aSLuohao Wang moduleOp, kPrintU64, IntegerType::get(moduleOp->getContext(), 64), 96e332c22cSNicolas Vasilache LLVM::LLVMVoidType::get(moduleOp->getContext())); 97e332c22cSNicolas Vasilache } 98e332c22cSNicolas Vasilache 99*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 100*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreatePrintF16Fn(Operation *moduleOp) { 101*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 102*e84f6b6aSLuohao Wang moduleOp, kPrintF16, 103657f60a0SAart Bik IntegerType::get(moduleOp->getContext(), 16), // bits! 104657f60a0SAart Bik LLVM::LLVMVoidType::get(moduleOp->getContext())); 105657f60a0SAart Bik } 106657f60a0SAart Bik 107*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 108*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreatePrintBF16Fn(Operation *moduleOp) { 109*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 110*e84f6b6aSLuohao Wang moduleOp, kPrintBF16, 111657f60a0SAart Bik IntegerType::get(moduleOp->getContext(), 16), // bits! 112657f60a0SAart Bik LLVM::LLVMVoidType::get(moduleOp->getContext())); 113657f60a0SAart Bik } 114657f60a0SAart Bik 115*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 116*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreatePrintF32Fn(Operation *moduleOp) { 117*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 118*e84f6b6aSLuohao Wang moduleOp, kPrintF32, Float32Type::get(moduleOp->getContext()), 119e332c22cSNicolas Vasilache LLVM::LLVMVoidType::get(moduleOp->getContext())); 120e332c22cSNicolas Vasilache } 121e332c22cSNicolas Vasilache 122*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 123*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreatePrintF64Fn(Operation *moduleOp) { 124*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 125*e84f6b6aSLuohao Wang moduleOp, kPrintF64, Float64Type::get(moduleOp->getContext()), 126e332c22cSNicolas Vasilache LLVM::LLVMVoidType::get(moduleOp->getContext())); 127e332c22cSNicolas Vasilache } 128e332c22cSNicolas Vasilache 12997a238e8SChristian Ulmann static LLVM::LLVMPointerType getCharPtr(MLIRContext *context) { 13050ea17b8SMarkus Böck return LLVM::LLVMPointerType::get(context); 13150ea17b8SMarkus Böck } 13250ea17b8SMarkus Böck 13397a238e8SChristian Ulmann static LLVM::LLVMPointerType getVoidPtr(MLIRContext *context) { 13450ea17b8SMarkus Böck // A char pointer and void ptr are the same in LLVM IR. 13597a238e8SChristian Ulmann return getCharPtr(context); 13650ea17b8SMarkus Böck } 13750ea17b8SMarkus Böck 138*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> mlir::LLVM::lookupOrCreatePrintStringFn( 139f543dfd1SChristopher Bate Operation *moduleOp, std::optional<StringRef> runtimeFunctionName) { 140*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 141*e84f6b6aSLuohao Wang moduleOp, runtimeFunctionName.value_or(kPrintString), 14297a238e8SChristian Ulmann getCharPtr(moduleOp->getContext()), 143325b58d5SMatthias Springer LLVM::LLVMVoidType::get(moduleOp->getContext())); 144325b58d5SMatthias Springer } 145325b58d5SMatthias Springer 146*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 147*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreatePrintOpenFn(Operation *moduleOp) { 148*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 149*e84f6b6aSLuohao Wang moduleOp, kPrintOpen, {}, 150e332c22cSNicolas Vasilache LLVM::LLVMVoidType::get(moduleOp->getContext())); 151e332c22cSNicolas Vasilache } 152e332c22cSNicolas Vasilache 153*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 154*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreatePrintCloseFn(Operation *moduleOp) { 155*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 156*e84f6b6aSLuohao Wang moduleOp, kPrintClose, {}, 157e332c22cSNicolas Vasilache LLVM::LLVMVoidType::get(moduleOp->getContext())); 158e332c22cSNicolas Vasilache } 159e332c22cSNicolas Vasilache 160*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 161*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreatePrintCommaFn(Operation *moduleOp) { 162*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 163*e84f6b6aSLuohao Wang moduleOp, kPrintComma, {}, 164e332c22cSNicolas Vasilache LLVM::LLVMVoidType::get(moduleOp->getContext())); 165e332c22cSNicolas Vasilache } 166e332c22cSNicolas Vasilache 167*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 168*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreatePrintNewlineFn(Operation *moduleOp) { 169*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 170*e84f6b6aSLuohao Wang moduleOp, kPrintNewline, {}, 171e332c22cSNicolas Vasilache LLVM::LLVMVoidType::get(moduleOp->getContext())); 172e332c22cSNicolas Vasilache } 173e332c22cSNicolas Vasilache 174*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 175*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreateMallocFn(Operation *moduleOp, Type indexType) { 176*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn(moduleOp, kMalloc, indexType, 17797a238e8SChristian Ulmann getVoidPtr(moduleOp->getContext())); 178e332c22cSNicolas Vasilache } 179e332c22cSNicolas Vasilache 180*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 181*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreateAlignedAllocFn(Operation *moduleOp, Type indexType) { 182*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn(moduleOp, kAlignedAlloc, 18397a238e8SChristian Ulmann {indexType, indexType}, 18497a238e8SChristian Ulmann getVoidPtr(moduleOp->getContext())); 185a8601f11SMichele Scuttari } 186a8601f11SMichele Scuttari 187*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 188*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreateFreeFn(Operation *moduleOp) { 189*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 190*e84f6b6aSLuohao Wang moduleOp, kFree, getVoidPtr(moduleOp->getContext()), 191*e84f6b6aSLuohao Wang LLVM::LLVMVoidType::get(moduleOp->getContext())); 192*e84f6b6aSLuohao Wang } 193*e84f6b6aSLuohao Wang 194*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 195*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreateGenericAllocFn(Operation *moduleOp, Type indexType) { 196*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn(moduleOp, kGenericAlloc, indexType, 197*e84f6b6aSLuohao Wang getVoidPtr(moduleOp->getContext())); 198*e84f6b6aSLuohao Wang } 199*e84f6b6aSLuohao Wang 200*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 201*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreateGenericAlignedAllocFn(Operation *moduleOp, 202*e84f6b6aSLuohao Wang Type indexType) { 203*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn(moduleOp, kGenericAlignedAlloc, 204*e84f6b6aSLuohao Wang {indexType, indexType}, 205*e84f6b6aSLuohao Wang getVoidPtr(moduleOp->getContext())); 206*e84f6b6aSLuohao Wang } 207*e84f6b6aSLuohao Wang 208*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 209*e84f6b6aSLuohao Wang mlir::LLVM::lookupOrCreateGenericFreeFn(Operation *moduleOp) { 210*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 21197a238e8SChristian Ulmann moduleOp, kGenericFree, getVoidPtr(moduleOp->getContext()), 212a8601f11SMichele Scuttari LLVM::LLVMVoidType::get(moduleOp->getContext())); 213a8601f11SMichele Scuttari } 214a8601f11SMichele Scuttari 215*e84f6b6aSLuohao Wang FailureOr<LLVM::LLVMFuncOp> 216f543dfd1SChristopher Bate mlir::LLVM::lookupOrCreateMemRefCopyFn(Operation *moduleOp, Type indexType, 21788d5eba1SStephan Herhut Type unrankedDescriptorType) { 218*e84f6b6aSLuohao Wang return lookupOrCreateReservedFn( 21988d5eba1SStephan Herhut moduleOp, kMemRefCopy, 22088d5eba1SStephan Herhut ArrayRef<Type>{indexType, unrankedDescriptorType, unrankedDescriptorType}, 22188d5eba1SStephan Herhut LLVM::LLVMVoidType::get(moduleOp->getContext())); 22288d5eba1SStephan Herhut } 223