annotate clang/lib/CodeGen/CGGPUBuiltin.cpp @ 150:1d019706d866

LLVM10
author anatofuz
date Thu, 13 Feb 2020 15:10:13 +0900
parents
children c4bab56944e8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===------ CGGPUBuiltin.cpp - Codegen for GPU builtins -------------------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // Generates code for built-in GPU calls which are not runtime-specific.
anatofuz
parents:
diff changeset
10 // (Runtime-specific codegen lives in programming model specific files.)
anatofuz
parents:
diff changeset
11 //
anatofuz
parents:
diff changeset
12 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
13
anatofuz
parents:
diff changeset
14 #include "CodeGenFunction.h"
anatofuz
parents:
diff changeset
15 #include "clang/Basic/Builtins.h"
anatofuz
parents:
diff changeset
16 #include "llvm/IR/DataLayout.h"
anatofuz
parents:
diff changeset
17 #include "llvm/IR/Instruction.h"
anatofuz
parents:
diff changeset
18 #include "llvm/Support/MathExtras.h"
anatofuz
parents:
diff changeset
19 #include "llvm/Transforms/Utils/AMDGPUEmitPrintf.h"
anatofuz
parents:
diff changeset
20
anatofuz
parents:
diff changeset
21 using namespace clang;
anatofuz
parents:
diff changeset
22 using namespace CodeGen;
anatofuz
parents:
diff changeset
23
anatofuz
parents:
diff changeset
24 static llvm::Function *GetVprintfDeclaration(llvm::Module &M) {
anatofuz
parents:
diff changeset
25 llvm::Type *ArgTypes[] = {llvm::Type::getInt8PtrTy(M.getContext()),
anatofuz
parents:
diff changeset
26 llvm::Type::getInt8PtrTy(M.getContext())};
anatofuz
parents:
diff changeset
27 llvm::FunctionType *VprintfFuncType = llvm::FunctionType::get(
anatofuz
parents:
diff changeset
28 llvm::Type::getInt32Ty(M.getContext()), ArgTypes, false);
anatofuz
parents:
diff changeset
29
anatofuz
parents:
diff changeset
30 if (auto* F = M.getFunction("vprintf")) {
anatofuz
parents:
diff changeset
31 // Our CUDA system header declares vprintf with the right signature, so
anatofuz
parents:
diff changeset
32 // nobody else should have been able to declare vprintf with a bogus
anatofuz
parents:
diff changeset
33 // signature.
anatofuz
parents:
diff changeset
34 assert(F->getFunctionType() == VprintfFuncType);
anatofuz
parents:
diff changeset
35 return F;
anatofuz
parents:
diff changeset
36 }
anatofuz
parents:
diff changeset
37
anatofuz
parents:
diff changeset
38 // vprintf doesn't already exist; create a declaration and insert it into the
anatofuz
parents:
diff changeset
39 // module.
anatofuz
parents:
diff changeset
40 return llvm::Function::Create(
anatofuz
parents:
diff changeset
41 VprintfFuncType, llvm::GlobalVariable::ExternalLinkage, "vprintf", &M);
anatofuz
parents:
diff changeset
42 }
anatofuz
parents:
diff changeset
43
anatofuz
parents:
diff changeset
44 // Transforms a call to printf into a call to the NVPTX vprintf syscall (which
anatofuz
parents:
diff changeset
45 // isn't particularly special; it's invoked just like a regular function).
anatofuz
parents:
diff changeset
46 // vprintf takes two args: A format string, and a pointer to a buffer containing
anatofuz
parents:
diff changeset
47 // the varargs.
anatofuz
parents:
diff changeset
48 //
anatofuz
parents:
diff changeset
49 // For example, the call
anatofuz
parents:
diff changeset
50 //
anatofuz
parents:
diff changeset
51 // printf("format string", arg1, arg2, arg3);
anatofuz
parents:
diff changeset
52 //
anatofuz
parents:
diff changeset
53 // is converted into something resembling
anatofuz
parents:
diff changeset
54 //
anatofuz
parents:
diff changeset
55 // struct Tmp {
anatofuz
parents:
diff changeset
56 // Arg1 a1;
anatofuz
parents:
diff changeset
57 // Arg2 a2;
anatofuz
parents:
diff changeset
58 // Arg3 a3;
anatofuz
parents:
diff changeset
59 // };
anatofuz
parents:
diff changeset
60 // char* buf = alloca(sizeof(Tmp));
anatofuz
parents:
diff changeset
61 // *(Tmp*)buf = {a1, a2, a3};
anatofuz
parents:
diff changeset
62 // vprintf("format string", buf);
anatofuz
parents:
diff changeset
63 //
anatofuz
parents:
diff changeset
64 // buf is aligned to the max of {alignof(Arg1), ...}. Furthermore, each of the
anatofuz
parents:
diff changeset
65 // args is itself aligned to its preferred alignment.
anatofuz
parents:
diff changeset
66 //
anatofuz
parents:
diff changeset
67 // Note that by the time this function runs, E's args have already undergone the
anatofuz
parents:
diff changeset
68 // standard C vararg promotion (short -> int, float -> double, etc.).
anatofuz
parents:
diff changeset
69 RValue
anatofuz
parents:
diff changeset
70 CodeGenFunction::EmitNVPTXDevicePrintfCallExpr(const CallExpr *E,
anatofuz
parents:
diff changeset
71 ReturnValueSlot ReturnValue) {
anatofuz
parents:
diff changeset
72 assert(getTarget().getTriple().isNVPTX());
anatofuz
parents:
diff changeset
73 assert(E->getBuiltinCallee() == Builtin::BIprintf);
anatofuz
parents:
diff changeset
74 assert(E->getNumArgs() >= 1); // printf always has at least one arg.
anatofuz
parents:
diff changeset
75
anatofuz
parents:
diff changeset
76 const llvm::DataLayout &DL = CGM.getDataLayout();
anatofuz
parents:
diff changeset
77 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
anatofuz
parents:
diff changeset
78
anatofuz
parents:
diff changeset
79 CallArgList Args;
anatofuz
parents:
diff changeset
80 EmitCallArgs(Args,
anatofuz
parents:
diff changeset
81 E->getDirectCallee()->getType()->getAs<FunctionProtoType>(),
anatofuz
parents:
diff changeset
82 E->arguments(), E->getDirectCallee(),
anatofuz
parents:
diff changeset
83 /* ParamsToSkip = */ 0);
anatofuz
parents:
diff changeset
84
anatofuz
parents:
diff changeset
85 // We don't know how to emit non-scalar varargs.
anatofuz
parents:
diff changeset
86 if (std::any_of(Args.begin() + 1, Args.end(), [&](const CallArg &A) {
anatofuz
parents:
diff changeset
87 return !A.getRValue(*this).isScalar();
anatofuz
parents:
diff changeset
88 })) {
anatofuz
parents:
diff changeset
89 CGM.ErrorUnsupported(E, "non-scalar arg to printf");
anatofuz
parents:
diff changeset
90 return RValue::get(llvm::ConstantInt::get(IntTy, 0));
anatofuz
parents:
diff changeset
91 }
anatofuz
parents:
diff changeset
92
anatofuz
parents:
diff changeset
93 // Construct and fill the args buffer that we'll pass to vprintf.
anatofuz
parents:
diff changeset
94 llvm::Value *BufferPtr;
anatofuz
parents:
diff changeset
95 if (Args.size() <= 1) {
anatofuz
parents:
diff changeset
96 // If there are no args, pass a null pointer to vprintf.
anatofuz
parents:
diff changeset
97 BufferPtr = llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(Ctx));
anatofuz
parents:
diff changeset
98 } else {
anatofuz
parents:
diff changeset
99 llvm::SmallVector<llvm::Type *, 8> ArgTypes;
anatofuz
parents:
diff changeset
100 for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I)
anatofuz
parents:
diff changeset
101 ArgTypes.push_back(Args[I].getRValue(*this).getScalarVal()->getType());
anatofuz
parents:
diff changeset
102
anatofuz
parents:
diff changeset
103 // Using llvm::StructType is correct only because printf doesn't accept
anatofuz
parents:
diff changeset
104 // aggregates. If we had to handle aggregates here, we'd have to manually
anatofuz
parents:
diff changeset
105 // compute the offsets within the alloca -- we wouldn't be able to assume
anatofuz
parents:
diff changeset
106 // that the alignment of the llvm type was the same as the alignment of the
anatofuz
parents:
diff changeset
107 // clang type.
anatofuz
parents:
diff changeset
108 llvm::Type *AllocaTy = llvm::StructType::create(ArgTypes, "printf_args");
anatofuz
parents:
diff changeset
109 llvm::Value *Alloca = CreateTempAlloca(AllocaTy);
anatofuz
parents:
diff changeset
110
anatofuz
parents:
diff changeset
111 for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I) {
anatofuz
parents:
diff changeset
112 llvm::Value *P = Builder.CreateStructGEP(AllocaTy, Alloca, I - 1);
anatofuz
parents:
diff changeset
113 llvm::Value *Arg = Args[I].getRValue(*this).getScalarVal();
anatofuz
parents:
diff changeset
114 Builder.CreateAlignedStore(Arg, P, DL.getPrefTypeAlign(Arg->getType()));
anatofuz
parents:
diff changeset
115 }
anatofuz
parents:
diff changeset
116 BufferPtr = Builder.CreatePointerCast(Alloca, llvm::Type::getInt8PtrTy(Ctx));
anatofuz
parents:
diff changeset
117 }
anatofuz
parents:
diff changeset
118
anatofuz
parents:
diff changeset
119 // Invoke vprintf and return.
anatofuz
parents:
diff changeset
120 llvm::Function* VprintfFunc = GetVprintfDeclaration(CGM.getModule());
anatofuz
parents:
diff changeset
121 return RValue::get(Builder.CreateCall(
anatofuz
parents:
diff changeset
122 VprintfFunc, {Args[0].getRValue(*this).getScalarVal(), BufferPtr}));
anatofuz
parents:
diff changeset
123 }
anatofuz
parents:
diff changeset
124
anatofuz
parents:
diff changeset
125 RValue
anatofuz
parents:
diff changeset
126 CodeGenFunction::EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E,
anatofuz
parents:
diff changeset
127 ReturnValueSlot ReturnValue) {
anatofuz
parents:
diff changeset
128 assert(getTarget().getTriple().getArch() == llvm::Triple::amdgcn);
anatofuz
parents:
diff changeset
129 assert(E->getBuiltinCallee() == Builtin::BIprintf ||
anatofuz
parents:
diff changeset
130 E->getBuiltinCallee() == Builtin::BI__builtin_printf);
anatofuz
parents:
diff changeset
131 assert(E->getNumArgs() >= 1); // printf always has at least one arg.
anatofuz
parents:
diff changeset
132
anatofuz
parents:
diff changeset
133 CallArgList CallArgs;
anatofuz
parents:
diff changeset
134 EmitCallArgs(CallArgs,
anatofuz
parents:
diff changeset
135 E->getDirectCallee()->getType()->getAs<FunctionProtoType>(),
anatofuz
parents:
diff changeset
136 E->arguments(), E->getDirectCallee(),
anatofuz
parents:
diff changeset
137 /* ParamsToSkip = */ 0);
anatofuz
parents:
diff changeset
138
anatofuz
parents:
diff changeset
139 SmallVector<llvm::Value *, 8> Args;
anatofuz
parents:
diff changeset
140 for (auto A : CallArgs) {
anatofuz
parents:
diff changeset
141 // We don't know how to emit non-scalar varargs.
anatofuz
parents:
diff changeset
142 if (!A.getRValue(*this).isScalar()) {
anatofuz
parents:
diff changeset
143 CGM.ErrorUnsupported(E, "non-scalar arg to printf");
anatofuz
parents:
diff changeset
144 return RValue::get(llvm::ConstantInt::get(IntTy, -1));
anatofuz
parents:
diff changeset
145 }
anatofuz
parents:
diff changeset
146
anatofuz
parents:
diff changeset
147 llvm::Value *Arg = A.getRValue(*this).getScalarVal();
anatofuz
parents:
diff changeset
148 Args.push_back(Arg);
anatofuz
parents:
diff changeset
149 }
anatofuz
parents:
diff changeset
150
anatofuz
parents:
diff changeset
151 llvm::IRBuilder<> IRB(Builder.GetInsertBlock(), Builder.GetInsertPoint());
anatofuz
parents:
diff changeset
152 IRB.SetCurrentDebugLocation(Builder.getCurrentDebugLocation());
anatofuz
parents:
diff changeset
153 auto Printf = llvm::emitAMDGPUPrintfCall(IRB, Args);
anatofuz
parents:
diff changeset
154 Builder.SetInsertPoint(IRB.GetInsertBlock(), IRB.GetInsertPoint());
anatofuz
parents:
diff changeset
155 return RValue::get(Printf);
anatofuz
parents:
diff changeset
156 }