Justin Lebar | 3039a59 | 2016-01-23 21:28:14 +0000 | [diff] [blame] | 1 | //===----- CGCUDABuiltin.cpp - Codegen for CUDA builtins ------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // Generates code for built-in CUDA calls which are not runtime-specific. |
| 11 | // (Runtime-specific codegen lives in CGCUDARuntime.) |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "CodeGenFunction.h" |
| 16 | #include "clang/Basic/Builtins.h" |
| 17 | #include "llvm/IR/DataLayout.h" |
| 18 | #include "llvm/IR/Instruction.h" |
| 19 | #include "llvm/Support/MathExtras.h" |
| 20 | |
| 21 | using namespace clang; |
| 22 | using namespace CodeGen; |
| 23 | |
| 24 | static llvm::Function *GetVprintfDeclaration(llvm::Module &M) { |
| 25 | llvm::Type *ArgTypes[] = {llvm::Type::getInt8PtrTy(M.getContext()), |
| 26 | llvm::Type::getInt8PtrTy(M.getContext())}; |
| 27 | llvm::FunctionType *VprintfFuncType = llvm::FunctionType::get( |
| 28 | llvm::Type::getInt32Ty(M.getContext()), ArgTypes, false); |
| 29 | |
| 30 | if (auto* F = M.getFunction("vprintf")) { |
| 31 | // Our CUDA system header declares vprintf with the right signature, so |
| 32 | // nobody else should have been able to declare vprintf with a bogus |
| 33 | // signature. |
| 34 | assert(F->getFunctionType() == VprintfFuncType); |
| 35 | return F; |
| 36 | } |
| 37 | |
| 38 | // vprintf doesn't already exist; create a declaration and insert it into the |
| 39 | // module. |
| 40 | return llvm::Function::Create( |
| 41 | VprintfFuncType, llvm::GlobalVariable::ExternalLinkage, "vprintf", &M); |
| 42 | } |
| 43 | |
| 44 | // Transforms a call to printf into a call to the NVPTX vprintf syscall (which |
| 45 | // isn't particularly special; it's invoked just like a regular function). |
| 46 | // vprintf takes two args: A format string, and a pointer to a buffer containing |
| 47 | // the varargs. |
| 48 | // |
| 49 | // For example, the call |
| 50 | // |
| 51 | // printf("format string", arg1, arg2, arg3); |
| 52 | // |
| 53 | // is converted into something resembling |
| 54 | // |
Justin Lebar | c0e4275 | 2016-01-28 23:58:28 +0000 | [diff] [blame] | 55 | // struct Tmp { |
| 56 | // Arg1 a1; |
| 57 | // Arg2 a2; |
| 58 | // Arg3 a3; |
| 59 | // }; |
| 60 | // char* buf = alloca(sizeof(Tmp)); |
| 61 | // *(Tmp*)buf = {a1, a2, a3}; |
Justin Lebar | 3039a59 | 2016-01-23 21:28:14 +0000 | [diff] [blame] | 62 | // vprintf("format string", buf); |
| 63 | // |
| 64 | // buf is aligned to the max of {alignof(Arg1), ...}. Furthermore, each of the |
| 65 | // args is itself aligned to its preferred alignment. |
| 66 | // |
| 67 | // Note that by the time this function runs, E's args have already undergone the |
| 68 | // standard C vararg promotion (short -> int, float -> double, etc.). |
| 69 | RValue |
| 70 | CodeGenFunction::EmitCUDADevicePrintfCallExpr(const CallExpr *E, |
| 71 | ReturnValueSlot ReturnValue) { |
| 72 | assert(getLangOpts().CUDA); |
| 73 | assert(getLangOpts().CUDAIsDevice); |
| 74 | assert(E->getBuiltinCallee() == Builtin::BIprintf); |
| 75 | assert(E->getNumArgs() >= 1); // printf always has at least one arg. |
| 76 | |
| 77 | const llvm::DataLayout &DL = CGM.getDataLayout(); |
| 78 | llvm::LLVMContext &Ctx = CGM.getLLVMContext(); |
| 79 | |
| 80 | CallArgList Args; |
| 81 | EmitCallArgs(Args, |
| 82 | E->getDirectCallee()->getType()->getAs<FunctionProtoType>(), |
| 83 | E->arguments(), E->getDirectCallee(), |
| 84 | /* ParamsToSkip = */ 0); |
| 85 | |
Justin Lebar | 9a2c0fb | 2016-02-11 02:00:52 +0000 | [diff] [blame] | 86 | // We don't know how to emit non-scalar varargs. |
| 87 | if (std::any_of(Args.begin() + 1, Args.end(), |
| 88 | [](const CallArg &A) { return !A.RV.isScalar(); })) { |
| 89 | CGM.ErrorUnsupported(E, "non-scalar arg to printf"); |
| 90 | return RValue::get(llvm::ConstantInt::get(IntTy, 0)); |
| 91 | } |
| 92 | |
Justin Lebar | c0e4275 | 2016-01-28 23:58:28 +0000 | [diff] [blame] | 93 | // Construct and fill the args buffer that we'll pass to vprintf. |
| 94 | llvm::Value *BufferPtr; |
| 95 | if (Args.size() <= 1) { |
Justin Lebar | 3039a59 | 2016-01-23 21:28:14 +0000 | [diff] [blame] | 96 | // If there are no args, pass a null pointer to vprintf. |
| 97 | BufferPtr = llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(Ctx)); |
| 98 | } else { |
Justin Lebar | c0e4275 | 2016-01-28 23:58:28 +0000 | [diff] [blame] | 99 | llvm::SmallVector<llvm::Type *, 8> ArgTypes; |
| 100 | for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I) |
| 101 | ArgTypes.push_back(Args[I].RV.getScalarVal()->getType()); |
| 102 | llvm::Type *AllocaTy = llvm::StructType::create(ArgTypes, "printf_args"); |
| 103 | llvm::Value *Alloca = CreateTempAlloca(AllocaTy); |
Justin Lebar | 3039a59 | 2016-01-23 21:28:14 +0000 | [diff] [blame] | 104 | |
Justin Lebar | 3039a59 | 2016-01-23 21:28:14 +0000 | [diff] [blame] | 105 | for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I) { |
Justin Lebar | c0e4275 | 2016-01-28 23:58:28 +0000 | [diff] [blame] | 106 | llvm::Value *P = Builder.CreateStructGEP(AllocaTy, Alloca, I - 1); |
Justin Lebar | 3039a59 | 2016-01-23 21:28:14 +0000 | [diff] [blame] | 107 | llvm::Value *Arg = Args[I].RV.getScalarVal(); |
Justin Lebar | c0e4275 | 2016-01-28 23:58:28 +0000 | [diff] [blame] | 108 | Builder.CreateAlignedStore(Arg, P, DL.getPrefTypeAlignment(Arg->getType())); |
Justin Lebar | 3039a59 | 2016-01-23 21:28:14 +0000 | [diff] [blame] | 109 | } |
Justin Lebar | c0e4275 | 2016-01-28 23:58:28 +0000 | [diff] [blame] | 110 | BufferPtr = Builder.CreatePointerCast(Alloca, llvm::Type::getInt8PtrTy(Ctx)); |
Justin Lebar | 3039a59 | 2016-01-23 21:28:14 +0000 | [diff] [blame] | 111 | } |
| 112 | |
| 113 | // Invoke vprintf and return. |
| 114 | llvm::Function* VprintfFunc = GetVprintfDeclaration(CGM.getModule()); |
| 115 | return RValue::get( |
| 116 | Builder.CreateCall(VprintfFunc, {Args[0].RV.getScalarVal(), BufferPtr})); |
| 117 | } |