LLVM: lib/Target/AMDGPU/AMDGPUPrintfRuntimeBinding.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

33

34using namespace llvm;

35

36#define DEBUG_TYPE "printfToRuntime"

38

39namespace {

40class AMDGPUPrintfRuntimeBinding final : public ModulePass {

41

42public:

43 static char ID;

44

45 explicit AMDGPUPrintfRuntimeBinding() : ModulePass(ID) {}

46

47private:

48 bool runOnModule(Module &M) override;

49};

50

51class AMDGPUPrintfRuntimeBindingImpl {

52public:

53 AMDGPUPrintfRuntimeBindingImpl() = default;

55

56private:

57 void getConversionSpecifiers(SmallVectorImpl &OpConvSpecifiers,

58 StringRef fmt, size_t num_ops) const;

59

60 bool lowerPrintfForGpu(Module &M);

61

62 const DataLayout *TD;

64};

65}

66

67char AMDGPUPrintfRuntimeBinding::ID = 0;

68

70 "amdgpu-printf-runtime-binding", "AMDGPU Printf lowering",

71 false, false)

76

78

80 return new AMDGPUPrintfRuntimeBinding();

81}

82

83void AMDGPUPrintfRuntimeBindingImpl::getConversionSpecifiers(

85 size_t NumOps) const {

86

87

88

89

90

91 static const char ConvSpecifiers[] = "cdieEfFgGaAosuxXp";

92 size_t CurFmtSpecifierIdx = 0;

93 size_t PrevFmtSpecifierIdx = 0;

94

96 ConvSpecifiers, CurFmtSpecifierIdx)) != StringRef::npos) {

97 bool ArgDump = false;

99 CurFmtSpecifierIdx - PrevFmtSpecifierIdx);

102 ArgDump = true;

103 while (pTag && CurFmt[--pTag] == '%') {

104 ArgDump = !ArgDump;

105 }

106 }

107

108 if (ArgDump)

109 OpConvSpecifiers.push_back(Fmt[CurFmtSpecifierIdx]);

110

111 PrevFmtSpecifierIdx = ++CurFmtSpecifierIdx;

112 }

113}

114

118

121

129

133 "printf format string must be a trivially resolved constant string "

134 "global variable",

136}

137

138bool AMDGPUPrintfRuntimeBindingImpl::lowerPrintfForGpu(Module &M) {

139 LLVMContext &Ctx = M.getContext();

141 Type *I32Ty = Type::getInt32Ty(Ctx);

142

143

144

145

146

147 NamedMDNode *metaD = M.getOrInsertNamedMetadata("llvm.printf.fmts");

149

150 for (auto *CI : Printfs) {

151 unsigned NumOps = CI->arg_size();

152

153 SmallString<16> OpConvSpecifiers;

154 Value *Op = CI->getArgOperand(0);

155

156 StringRef FormatStr;

158 Value *Stripped = Op->stripPointerCasts();

161 continue;

162 }

163

164

165

166 getConversionSpecifiers(OpConvSpecifiers, FormatStr, NumOps - 1);

167

168

169 std::string AStreamHolder;

170 raw_string_ostream Sizes(AStreamHolder);

172 Sizes << CI->arg_size() - 1;

174 for (unsigned ArgCount = 1;

175 ArgCount < CI->arg_size() && ArgCount <= OpConvSpecifiers.size();

176 ArgCount++) {

177 Value *Arg = CI->getArgOperand(ArgCount);

180

181

182

183

185 Type *ResType = Type::getInt32Ty(Ctx);

187 ResType = VectorType::get(ResType, VecType->getElementCount());

188 Builder.SetInsertPoint(CI);

189 Builder.SetCurrentDebugLocation(CI->getDebugLoc());

190

192 Arg = Builder.CreateBitCast(

193 Arg,

195 }

196

197 if (OpConvSpecifiers[ArgCount - 1] == 'x' ||

198 OpConvSpecifiers[ArgCount - 1] == 'X' ||

199 OpConvSpecifiers[ArgCount - 1] == 'u' ||

200 OpConvSpecifiers[ArgCount - 1] == 'o')

201 Arg = Builder.CreateZExt(Arg, ResType);

202 else

203 Arg = Builder.CreateSExt(Arg, ResType);

204 ArgType = Arg->getType();

206 CI->setOperand(ArgCount, Arg);

207 }

208 if (OpConvSpecifiers[ArgCount - 1] == 'f') {

210 if (FpCons)

211 ArgSize = 4;

212 else {

216 ArgSize = 4;

217 }

218 }

219 if (shouldPrintAsStr(OpConvSpecifiers[ArgCount - 1], ArgType))

221

222 LLVM_DEBUG(dbgs() << "Printf ArgSize (in buffer) = " << ArgSize

223 << " for type: " << *ArgType << '\n');

224 Sizes << ArgSize << ':';

225 Sum += ArgSize;

226 }

227 LLVM_DEBUG(dbgs() << "Printf format string in source = " << FormatStr

228 << '\n');

229 for (char C : FormatStr) {

230

231

232 switch (C) {

233 case '\a':

235 break;

236 case '\b':

238 break;

239 case '\f':

241 break;

242 case '\n':

244 break;

245 case '\r':

247 break;

248 case '\v':

250 break;

251 case ':':

252

253

255 break;

256 default:

258 break;

259 }

260 }

261

262

263 Builder.SetInsertPoint(CI);

264 Builder.SetCurrentDebugLocation(CI->getDebugLoc());

265

266 AttributeList Attr = AttributeList::get(Ctx, AttributeList::FunctionIndex,

267 Attribute::NoUnwind);

268

269 Type *SizetTy = Type::getInt32Ty(Ctx);

270

271 Type *Tys_alloc[1] = {SizetTy};

272 Type *I8Ty = Type::getInt8Ty(Ctx);

273 Type *I8Ptr = PointerType::get(Ctx, 1);

274 FunctionType *FTy_alloc = FunctionType::get(I8Ptr, Tys_alloc, false);

275 FunctionCallee PrintfAllocFn =

276 M.getOrInsertFunction(StringRef("__printf_alloc"), FTy_alloc, Attr);

277

279 std::string fmtstr = itostr(++UniqID) + ":" + Sizes.str();

280 MDString *fmtStrArray = MDString::get(Ctx, fmtstr);

281

282 MDNode *myMD = MDNode::get(Ctx, fmtStrArray);

284 Value *sumC = ConstantInt::get(SizetTy, Sum, false);

287 CallInst *pcall = CallInst::Create(PrintfAllocFn, alloc_args,

288 "printf_alloc_fn", CI->getIterator());

289

290

291

292

293

294

295 ConstantPointerNull *zeroIntPtr =

297 auto *cmp = cast(Builder.CreateICmpNE(pcall, zeroIntPtr, ""));

298 if (!CI->use_empty()) {

300 Builder.CreateSExt(Builder.CreateNot(cmp), I32Ty, "printf_res");

301 CI->replaceAllUsesWith(result);

302 }

307

308 Builder.SetInsertPoint(Brnch);

309

310

311

313 I8Ty, pcall, ConstantInt::get(Ctx, APInt(32, 0)), "PrintBuffID",

314 BrnchPoint);

315

317 Value *id_gep_cast =

318 new BitCastInst(BufferIdx, idPointer, "PrintBuffIdCast", BrnchPoint);

319

320 new StoreInst(ConstantInt::get(I32Ty, UniqID), id_gep_cast, BrnchPoint);

321

322

323

325 ConstantInt::get(Ctx, APInt(32, 4)),

326 "PrintBuffGep", BrnchPoint);

327

329 for (unsigned ArgCount = 1;

330 ArgCount < CI->arg_size() && ArgCount <= OpConvSpecifiers.size();

331 ArgCount++) {

332 Value *Arg = CI->getArgOperand(ArgCount);

336 if (OpConvSpecifiers[ArgCount - 1] == 'f') {

339 bool Lost = false;

340 Val.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven,

341 &Lost);

342 Arg = ConstantFP::get(Ctx, Val);

344 if (FpExt->getType()->isDoubleTy() &&

345 FpExt->getOperand(0)->getType()->isFloatTy()) {

346 Arg = FpExt->getOperand(0);

347 }

348 }

349 }

352 if (shouldPrintAsStr(OpConvSpecifiers[ArgCount - 1], ArgType)) {

354 if (!S.empty()) {

355 const uint64_t ReadSize = 4;

356

357 DataExtractor Extractor(S, true, 8);

358 DataExtractor::Cursor Offset(0);

360 uint64_t ReadNow = std::min(ReadSize, S.size() - Offset.tell());

361 uint64_t ReadBytes = 0;

362 switch (ReadNow) {

364 case 1:

365 ReadBytes = Extractor.getU8(Offset);

366 break;

367 case 2:

368 ReadBytes = Extractor.getU16(Offset);

369 break;

370 case 3:

371 ReadBytes = Extractor.getU24(Offset);

372 break;

373 case 4:

374 ReadBytes = Extractor.getU32(Offset);

375 break;

376 }

377

379 "failed to read bytes from constant array");

380

381 APInt IntVal(8 * ReadSize, ReadBytes);

382

383

384 if (ReadNow < ReadSize)

386

387 Type *IntTy = Type::getIntNTy(Ctx, IntVal.getBitWidth());

388 WhatToStore.push_back(ConstantInt::get(IntTy, IntVal));

389 }

390 } else {

391

392 Value *ANumV = ConstantInt::get(Int32Ty, 0xFFFFFF00, false);

394 }

395 } else {

397 }

398 } else {

400 }

401 for (unsigned I = 0, E = WhatToStore.size(); I != E; ++I) {

402 Value *TheBtCast = WhatToStore[I];

404 StoreInst *StBuff = new StoreInst(TheBtCast, BufferIdx, BrnchPoint);

405 LLVM_DEBUG(dbgs() << "inserting store to printf buffer:\n"

406 << *StBuff << '\n');

407 (void)StBuff;

408 if (I + 1 == E && ArgCount + 1 == CI->arg_size())

409 break;

411 I8Ty, BufferIdx, {ConstantInt::get(I32Ty, ArgSize)},

412 "PrintBuffNextPtr", BrnchPoint);

413 LLVM_DEBUG(dbgs() << "inserting gep to the printf buffer:\n"

414 << *BufferIdx << '\n');

415 }

416 }

417 }

418

419

420 for (auto *CI : Printfs)

421 CI->eraseFromParent();

422

423 Printfs.clear();

424 return true;

425}

426

427bool AMDGPUPrintfRuntimeBindingImpl::run(Module &M) {

428 Triple TT(M.getTargetTriple());

430 return false;

431

432 auto *PrintfFunction = M.getFunction("printf");

433 if (!PrintfFunction || !PrintfFunction->isDeclaration() ||

434 M.getModuleFlag("openmp"))

435 return false;

436

437 for (auto &U : PrintfFunction->uses()) {

439 if (CI->isCallee(&U) && !CI->isNoBuiltin())

440 Printfs.push_back(CI);

441 }

442 }

443

444 if (Printfs.empty())

445 return false;

446

447 TD = &M.getDataLayout();

448

449 return lowerPrintfForGpu(M);

450}

451

452bool AMDGPUPrintfRuntimeBinding::runOnModule(Module &M) {

453 return AMDGPUPrintfRuntimeBindingImpl().run(M);

454}

455

456PreservedAnalyses

458 bool Changed = AMDGPUPrintfRuntimeBindingImpl().run(M);

460}

static void diagnoseInvalidFormatString(const CallBase *CI)

Definition AMDGPUPrintfRuntimeBinding.cpp:130

@ DWORD_ALIGN

Definition AMDGPUPrintfRuntimeBinding.cpp:37

constexpr StringLiteral NonLiteralStr("???")

static StringRef getAsConstantStr(Value *V)

Definition AMDGPUPrintfRuntimeBinding.cpp:122

static bool shouldPrintAsStr(char Specifier, Type *OpType)

Definition AMDGPUPrintfRuntimeBinding.cpp:115

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

Module.h This file contains the declarations for the Module class.

const size_t AbstractManglingParser< Derived, Alloc >::NumOps

Machine Check Debug Module

#define INITIALIZE_PASS_DEPENDENCY(depName)

#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)

#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)

InstListType::iterator iterator

Instruction iterators...

Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...

static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)

const APFloat & getValueAPF() const

static LLVM_ABI ConstantPointerNull * get(PointerType *T)

Static factory methods - Return objects of the specified value.

LLVM_ABI TypeSize getTypeAllocSize(Type *Ty) const

Returns the offset in bytes between successive objects of the specified type, including alignment pad...

Diagnostic information for unsupported feature in backend.

Legacy analysis pass which computes a DominatorTree.

static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)

const DebugLoc & getDebugLoc() const

Return the debug location for this node as a DebugLoc.

LLVM_ABI const Function * getFunction() const

Return the function this instruction belongs to.

LLVM_ABI void diagnose(const DiagnosticInfo &DI)

Report a message to the currently installed diagnostic handler.

static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)

static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)

ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...

A Module instance is used to store all the information related to an LLVM module.

LLVM_ABI unsigned getNumOperands() const

LLVM_ABI void addOperand(MDNode *M)

static PreservedAnalyses none()

Convenience factory function for the empty preserved set.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void push_back(const T &Elt)

A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...

StringRef - Represent a constant reference to a string, i.e.

static constexpr size_t npos

constexpr StringRef substr(size_t Start, size_t N=npos) const

Return a reference to the substring from [Start, Start + N).

constexpr bool empty() const

empty - Check if the string is empty.

constexpr size_t size() const

size - Get the string size.

size_t find_last_of(char C, size_t From=npos) const

Find the last character in the string that is C, or npos if not found.

size_t find_first_of(char C, size_t From=0) const

Find the first character in the string that is C, or npos if not found.

The instances of the Type class are immutable: once they are created, they are never changed.

bool isFloatTy() const

Return true if this is 'float', a 32-bit IEEE fp type.

LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY

Return the basic size of this type if it is a primitive type.

bool isDoubleTy() const

Return true if this is 'double', a 64-bit IEEE fp type.

bool isFloatingPointTy() const

Return true if this is one of the floating-point types.

bool isFPOrFPVectorTy() const

Return true if this is a FP type or a vector of FP.

Value * getOperand(unsigned i) const

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

LLVM_ABI LLVMContext & getContext() const

All values hold a context through their type.

self_iterator getIterator()

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

@ GLOBAL_ADDRESS

Address space for global memory (RAT0, VTX0).

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

@ C

The default llvm calling convention, compatible with C.

PointerTypeMap run(const Module &M)

Compute the PointerTypeMap for the module M.

friend class Instruction

Iterator for Instructions in a `BasicBlock.

This is an optimization pass for GlobalISel generic memory operations.

FunctionAddr VTableAddr Value

auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)

Get the size of a range.

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty

LLVM_ABI bool getConstantStringInfo(const Value *V, StringRef &Str, bool TrimAtNul=true)

This function computes the length of a null-terminated C string pointed to by V.

char & AMDGPUPrintfRuntimeBindingID

Definition AMDGPUPrintfRuntimeBinding.cpp:77

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

ModulePass * createAMDGPUPrintfRuntimeBinding()

Definition AMDGPUPrintfRuntimeBinding.cpp:79

void cantFail(Error Err, const char *Msg=nullptr)

Report a fatal error if Err is a failure value.

IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >

uint64_t alignTo(uint64_t Size, Align A)

Returns a multiple of A needed to store Size bytes.

DWARFExpression::Operation Op

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.

LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="", bool Before=false)

Split the specified block at the specified instruction.

LLVM_ABI Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)

Split the containing block at the specified instruction - everything before SplitBefore stays in the ...

std::string itostr(int64_t X)

AnalysisManager< Module > ModuleAnalysisManager

Convenience typedef for the Module analysis manager.

PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)

Definition AMDGPUPrintfRuntimeBinding.cpp:457