LLVM  13.0.0git
AMDGPUEmitPrintf.cpp
Go to the documentation of this file.
1 //===- AMDGPUEmitPrintf.cpp -----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Utility function to lower a printf call into a series of device
10 // library calls on the AMDGPU target.
11 //
12 // WARNING: This file knows about certain library functions. It recognizes them
13 // by name, and hardwires knowledge of their semantics.
14 //
15 //===----------------------------------------------------------------------===//
16 
20 
21 using namespace llvm;
22 
23 #define DEBUG_TYPE "amdgpu-emit-printf"
24 
25 static bool isCString(const Value *Arg) {
26  auto Ty = Arg->getType();
27  auto PtrTy = dyn_cast<PointerType>(Ty);
28  if (!PtrTy)
29  return false;
30 
31  auto IntTy = dyn_cast<IntegerType>(PtrTy->getElementType());
32  if (!IntTy)
33  return false;
34 
35  return IntTy->getBitWidth() == 8;
36 }
37 
39  auto Int64Ty = Builder.getInt64Ty();
40  auto Ty = Arg->getType();
41 
42  if (auto IntTy = dyn_cast<IntegerType>(Ty)) {
43  switch (IntTy->getBitWidth()) {
44  case 32:
45  return Builder.CreateZExt(Arg, Int64Ty);
46  case 64:
47  return Arg;
48  }
49  }
50 
51  if (Ty->getTypeID() == Type::DoubleTyID) {
52  return Builder.CreateBitCast(Arg, Int64Ty);
53  }
54 
55  if (isa<PointerType>(Ty)) {
56  return Builder.CreatePtrToInt(Arg, Int64Ty);
57  }
58 
59  llvm_unreachable("unexpected type");
60 }
61 
63  auto Int64Ty = Builder.getInt64Ty();
64  auto M = Builder.GetInsertBlock()->getModule();
65  auto Fn = M->getOrInsertFunction("__ockl_printf_begin", Int64Ty, Int64Ty);
66  return Builder.CreateCall(Fn, Version);
67 }
68 
69 static Value *callAppendArgs(IRBuilder<> &Builder, Value *Desc, int NumArgs,
70  Value *Arg0, Value *Arg1, Value *Arg2, Value *Arg3,
71  Value *Arg4, Value *Arg5, Value *Arg6,
72  bool IsLast) {
73  auto Int64Ty = Builder.getInt64Ty();
74  auto Int32Ty = Builder.getInt32Ty();
75  auto M = Builder.GetInsertBlock()->getModule();
76  auto Fn = M->getOrInsertFunction("__ockl_printf_append_args", Int64Ty,
77  Int64Ty, Int32Ty, Int64Ty, Int64Ty, Int64Ty,
78  Int64Ty, Int64Ty, Int64Ty, Int64Ty, Int32Ty);
79  auto IsLastValue = Builder.getInt32(IsLast);
80  auto NumArgsValue = Builder.getInt32(NumArgs);
81  return Builder.CreateCall(Fn, {Desc, NumArgsValue, Arg0, Arg1, Arg2, Arg3,
82  Arg4, Arg5, Arg6, IsLastValue});
83 }
84 
86  bool IsLast) {
87  auto Arg0 = fitArgInto64Bits(Builder, Arg);
88  auto Zero = Builder.getInt64(0);
89  return callAppendArgs(Builder, Desc, 1, Arg0, Zero, Zero, Zero, Zero, Zero,
90  Zero, IsLast);
91 }
92 
93 // The device library does not provide strlen, so we build our own loop
94 // here. While we are at it, we also include the terminating null in the length.
96  auto *Prev = Builder.GetInsertBlock();
97  Module *M = Prev->getModule();
98 
99  auto CharZero = Builder.getInt8(0);
100  auto One = Builder.getInt64(1);
101  auto Zero = Builder.getInt64(0);
102  auto Int64Ty = Builder.getInt64Ty();
103 
104  // The length is either zero for a null pointer, or the computed value for an
105  // actual string. We need a join block for a phi that represents the final
106  // value.
107  //
108  // Strictly speaking, the zero does not matter since
109  // __ockl_printf_append_string_n ignores the length if the pointer is null.
110  BasicBlock *Join = nullptr;
111  if (Prev->getTerminator()) {
112  Join = Prev->splitBasicBlock(Builder.GetInsertPoint(),
113  "strlen.join");
114  Prev->getTerminator()->eraseFromParent();
115  } else {
116  Join = BasicBlock::Create(M->getContext(), "strlen.join",
117  Prev->getParent());
118  }
119  BasicBlock *While =
120  BasicBlock::Create(M->getContext(), "strlen.while",
121  Prev->getParent(), Join);
122  BasicBlock *WhileDone = BasicBlock::Create(
123  M->getContext(), "strlen.while.done",
124  Prev->getParent(), Join);
125 
126  // Emit an early return for when the pointer is null.
127  Builder.SetInsertPoint(Prev);
128  auto CmpNull =
129  Builder.CreateICmpEQ(Str, Constant::getNullValue(Str->getType()));
130  BranchInst::Create(Join, While, CmpNull, Prev);
131 
132  // Entry to the while loop.
133  Builder.SetInsertPoint(While);
134 
135  auto PtrPhi = Builder.CreatePHI(Str->getType(), 2);
136  PtrPhi->addIncoming(Str, Prev);
137  auto PtrNext = Builder.CreateGEP(Builder.getInt8Ty(), PtrPhi, One);
138  PtrPhi->addIncoming(PtrNext, While);
139 
140  // Condition for the while loop.
141  auto Data = Builder.CreateLoad(Builder.getInt8Ty(), PtrPhi);
142  auto Cmp = Builder.CreateICmpEQ(Data, CharZero);
143  Builder.CreateCondBr(Cmp, WhileDone, While);
144 
145  // Add one to the computed length.
146  Builder.SetInsertPoint(WhileDone, WhileDone->begin());
147  auto Begin = Builder.CreatePtrToInt(Str, Int64Ty);
148  auto End = Builder.CreatePtrToInt(PtrPhi, Int64Ty);
149  auto Len = Builder.CreateSub(End, Begin);
150  Len = Builder.CreateAdd(Len, One);
151 
152  // Final join.
153  BranchInst::Create(Join, WhileDone);
154  Builder.SetInsertPoint(Join, Join->begin());
155  auto LenPhi = Builder.CreatePHI(Len->getType(), 2);
156  LenPhi->addIncoming(Len, WhileDone);
157  LenPhi->addIncoming(Zero, Prev);
158 
159  return LenPhi;
160 }
161 
163  Value *Length, bool isLast) {
164  auto Int64Ty = Builder.getInt64Ty();
165  auto CharPtrTy = Builder.getInt8PtrTy();
166  auto Int32Ty = Builder.getInt32Ty();
167  auto M = Builder.GetInsertBlock()->getModule();
168  auto Fn = M->getOrInsertFunction("__ockl_printf_append_string_n", Int64Ty,
169  Int64Ty, CharPtrTy, Int64Ty, Int32Ty);
170  auto IsLastInt32 = Builder.getInt32(isLast);
171  return Builder.CreateCall(Fn, {Desc, Str, Length, IsLastInt32});
172 }
173 
175  bool IsLast) {
176  auto Length = getStrlenWithNull(Builder, Arg);
177  return callAppendStringN(Builder, Desc, Arg, Length, IsLast);
178 }
179 
181  bool SpecIsCString, bool IsLast) {
182  if (SpecIsCString && isCString(Arg)) {
183  return appendString(Builder, Desc, Arg, IsLast);
184  }
185  // If the format specifies a string but the argument is not, the frontend will
186  // have printed a warning. We just rely on undefined behaviour and send the
187  // argument anyway.
188  return appendArg(Builder, Desc, Arg, IsLast);
189 }
190 
191 // Scan the format string to locate all specifiers, and mark the ones that
192 // specify a string, i.e, the "%s" specifier with optional '*' characters.
193 static void locateCStrings(SparseBitVector<8> &BV, Value *Fmt) {
194  StringRef Str;
195  if (!getConstantStringInfo(Fmt, Str) || Str.empty())
196  return;
197 
198  static const char ConvSpecifiers[] = "diouxXfFeEgGaAcspn";
199  size_t SpecPos = 0;
200  // Skip the first argument, the format string.
201  unsigned ArgIdx = 1;
202 
203  while ((SpecPos = Str.find_first_of('%', SpecPos)) != StringRef::npos) {
204  if (Str[SpecPos + 1] == '%') {
205  SpecPos += 2;
206  continue;
207  }
208  auto SpecEnd = Str.find_first_of(ConvSpecifiers, SpecPos);
209  if (SpecEnd == StringRef::npos)
210  return;
211  auto Spec = Str.slice(SpecPos, SpecEnd + 1);
212  ArgIdx += Spec.count('*');
213  if (Str[SpecEnd] == 's') {
214  BV.set(ArgIdx);
215  }
216  SpecPos = SpecEnd + 1;
217  ++ArgIdx;
218  }
219 }
220 
223  auto NumOps = Args.size();
224  assert(NumOps >= 1);
225 
226  auto Fmt = Args[0];
227  SparseBitVector<8> SpecIsCString;
228  locateCStrings(SpecIsCString, Fmt);
229 
230  auto Desc = callPrintfBegin(Builder, Builder.getIntN(64, 0));
231  Desc = appendString(Builder, Desc, Fmt, NumOps == 1);
232 
233  // FIXME: This invokes hostcall once for each argument. We can pack up to
234  // seven scalar printf arguments in a single hostcall. See the signature of
235  // callAppendArgs().
236  for (unsigned int i = 1; i != NumOps; ++i) {
237  bool IsLast = i == NumOps - 1;
238  bool IsCString = SpecIsCString.test(i);
239  Desc = processArg(Builder, Desc, Args[i], IsCString, IsLast);
240  }
241 
242  return Builder.CreateTrunc(Desc, Builder.getInt32Ty());
243 }
i
i
Definition: README.txt:29
Int32Ty
IntegerType * Int32Ty
Definition: NVVMIntrRange.cpp:67
isCString
static bool isCString(const Value *Arg)
Definition: AMDGPUEmitPrintf.cpp:25
llvm::Type::DoubleTyID
@ DoubleTyID
64-bit floating point type
Definition: Type.h:60
llvm
Definition: AllocatorList.h:23
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
callPrintfBegin
static Value * callPrintfBegin(IRBuilder<> &Builder, Value *Version)
Definition: AMDGPUEmitPrintf.cpp:62
llvm::StringRef::npos
static constexpr size_t npos
Definition: StringRef.h:60
processArg
static Value * processArg(IRBuilder<> &Builder, Value *Desc, Value *Arg, bool SpecIsCString, bool IsLast)
Definition: AMDGPUEmitPrintf.cpp:180
llvm::IRBuilder<>
ValueTracking.h
AMDGPUEmitPrintf.h
llvm::Data
@ Data
Definition: SIMachineScheduler.h:56
llvm::BasicBlock
LLVM Basic Block Representation.
Definition: BasicBlock.h:58
SparseBitVector.h
Arg
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
Definition: AMDGPULibCalls.cpp:206
appendString
static Value * appendString(IRBuilder<> &Builder, Value *Desc, Value *Arg, bool IsLast)
Definition: AMDGPUEmitPrintf.cpp:174
llvm::SparseBitVector
Definition: SparseBitVector.h:255
locateCStrings
static void locateCStrings(SparseBitVector< 8 > &BV, Value *Fmt)
Definition: AMDGPUEmitPrintf.cpp:193
llvm::BasicBlock::begin
iterator begin()
Instruction iterator methods.
Definition: BasicBlock.h:296
llvm::IndexedInstrProf::Version
const uint64_t Version
Definition: InstrProf.h:991
appendArg
static Value * appendArg(IRBuilder<> &Builder, Value *Desc, Value *Arg, bool IsLast)
Definition: AMDGPUEmitPrintf.cpp:85
llvm::SparseBitVector::set
void set(unsigned Idx)
Definition: SparseBitVector.h:507
llvm::getConstantStringInfo
bool getConstantStringInfo(const Value *V, StringRef &Str, uint64_t Offset=0, bool TrimAtNul=true)
This function computes the length of a null-terminated C string pointed to by V.
Definition: ValueTracking.cpp:4146
llvm::BranchInst::Create
static BranchInst * Create(BasicBlock *IfTrue, Instruction *InsertBefore=nullptr)
Definition: Instructions.h:3091
llvm::SparseBitVector::test
bool test(unsigned Idx) const
Definition: SparseBitVector.h:471
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
getStrlenWithNull
static Value * getStrlenWithNull(IRBuilder<> &Builder, Value *Str)
Definition: AMDGPUEmitPrintf.cpp:95
Builder
assume Assume Builder
Definition: AssumeBundleBuilder.cpp:651
llvm::ArrayRef
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: APInt.h:32
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:136
llvm::BasicBlock::Create
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:100
fitArgInto64Bits
static Value * fitArgInto64Bits(IRBuilder<> &Builder, Value *Arg)
Definition: AMDGPUEmitPrintf.cpp:38
llvm::Constant::getNullValue
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Definition: Constants.cpp:346
callAppendArgs
static Value * callAppendArgs(IRBuilder<> &Builder, Value *Desc, int NumArgs, Value *Arg0, Value *Arg1, Value *Arg2, Value *Arg3, Value *Arg4, Value *Arg5, Value *Arg6, bool IsLast)
Definition: AMDGPUEmitPrintf.cpp:69
callAppendStringN
static Value * callAppendStringN(IRBuilder<> &Builder, Value *Desc, Value *Str, Value *Length, bool isLast)
Definition: AMDGPUEmitPrintf.cpp:162
llvm::AMDGPU::HSAMD::Kernel::Key::Args
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Definition: AMDGPUMetadata.h:389
llvm::Value
LLVM Value Representation.
Definition: Value.h:75
llvm::emitAMDGPUPrintfCall
Value * emitAMDGPUPrintfCall(IRBuilder<> &Builder, ArrayRef< Value * > Args)
Definition: AMDGPUEmitPrintf.cpp:221