LLVM: lib/Transforms/Utils/AMDGPUEmitPrintf.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

25

26using namespace llvm;

27

28#define DEBUG_TYPE "amdgpu-emit-printf"

29

33

34 if (auto IntTy = dyn_cast(Ty)) {

35 switch (IntTy->getBitWidth()) {

36 case 32:

37 return Builder.CreateZExt(Arg, Int64Ty);

38 case 64:

39 return Arg;

40 }

41 }

42

45 }

46

47 if (isa(Ty)) {

49 }

50

52}

53

57 auto Fn = M->getOrInsertFunction("__ockl_printf_begin", Int64Ty, Int64Ty);

58 return Builder.CreateCall(Fn, Version);

59}

60

64 bool IsLast) {

68 auto Fn = M->getOrInsertFunction("__ockl_printf_append_args", Int64Ty,

69 Int64Ty, Int32Ty, Int64Ty, Int64Ty, Int64Ty,

70 Int64Ty, Int64Ty, Int64Ty, Int64Ty, Int32Ty);

71 auto IsLastValue = Builder.getInt32(IsLast);

72 auto NumArgsValue = Builder.getInt32(NumArgs);

73 return Builder.CreateCall(Fn, {Desc, NumArgsValue, Arg0, Arg1, Arg2, Arg3,

74 Arg4, Arg5, Arg6, IsLastValue});

75}

76

78 bool IsLast) {

80 auto Zero = Builder.getInt64(0);

81 return callAppendArgs(Builder, Desc, 1, Arg0, Zero, Zero, Zero, Zero, Zero,

82 Zero, IsLast);

83}

84

85

86

89 Module *M = Prev->getModule();

90

91 auto CharZero = Builder.getInt8(0);

92 auto One = Builder.getInt64(1);

93 auto Zero = Builder.getInt64(0);

95

96

97

98

99

100

101

103 if (Prev->getTerminator()) {

105 "strlen.join");

107 } else {

109 Prev->getParent());

110 }

113 Prev->getParent(), Join);

115 M->getContext(), "strlen.while.done",

116 Prev->getParent(), Join);

117

118

120 auto CmpNull =

123

124

126

127 auto PtrPhi = Builder.CreatePHI(Str->getType(), 2);

130 PtrPhi->addIncoming(PtrNext, While);

131

132

134 auto Cmp = Builder.CreateICmpEQ(Data, CharZero);

136

137

142 Len = Builder.CreateAdd(Len, One);

143

144

147 auto LenPhi = Builder.CreatePHI(Len->getType(), 2);

149 LenPhi->addIncoming(Zero, Prev);

150

151 return LenPhi;

152}

153

157 auto IsLastInt32 = Builder.getInt32(isLast);

159 auto Fn = M->getOrInsertFunction("__ockl_printf_append_string_n", Int64Ty,

160 Desc->getType(), Str->getType(),

161 Length->getType(), IsLastInt32->getType());

163}

164

166 bool IsLast) {

169}

170

172 bool SpecIsCString, bool IsLast) {

173 if (SpecIsCString && isa(Arg->getType())) {

175 }

176

177

178

180}

181

182

183

185 static const char ConvSpecifiers[] = "diouxXfFeEgGaAcspn";

186 size_t SpecPos = 0;

187

188 unsigned ArgIdx = 1;

189

190 while ((SpecPos = Str.find_first_of('%', SpecPos)) != StringRef::npos) {

191 if (Str[SpecPos + 1] == '%') {

192 SpecPos += 2;

193 continue;

194 }

195 auto SpecEnd = Str.find_first_of(ConvSpecifiers, SpecPos);

197 return;

198 auto Spec = Str.slice(SpecPos, SpecEnd + 1);

199 ArgIdx += Spec.count('*');

200 if (Str[SpecEnd] == 's') {

201 BV.set(ArgIdx);

202 }

203 SpecPos = SpecEnd + 1;

204 ++ArgIdx;

205 }

206}

207

208

214

217};

218

219

220

221

227 Value *NonConstStrLen = nullptr;

228 Value *LenWithNull = nullptr;

229 Value *LenWithNullAligned = nullptr;

230 Value *TempAdd = nullptr;

231

232

233 size_t BufSize = 4;

234 if (isConstFmtStr)

235

236 BufSize += 8;

237 else {

239

240

241 TempAdd = Builder.CreateAdd(LenWithNull,

242 ConstantInt::get(LenWithNull->getType(), 7U));

243 NonConstStrLen = Builder.CreateAnd(

244 TempAdd, ConstantInt::get(LenWithNull->getType(), ~7U));

245

248 }

249

250 for (size_t i = 1; i < Args.size(); i++) {

251 if (SpecIsCString.test(i)) {

254 auto alignedLen = alignTo(ArgStr.size() + 1, 8);

256 ArgStr,

257 nullptr, nullptr, true));

258 BufSize += alignedLen;

259 } else {

261

262

264 LenWithNull, ConstantInt::get(LenWithNull->getType(), 7U));

265 LenWithNullAligned = Builder.CreateAnd(

266 TempAdd, ConstantInt::get(LenWithNull->getType(), ~7U));

267

268 if (NonConstStrLen) {

269 auto Val = Builder.CreateAdd(LenWithNullAligned, NonConstStrLen,

270 "cumulativeAdd");

271 NonConstStrLen = Val;

272 } else

273 NonConstStrLen = LenWithNullAligned;

274

277 }

278 } else {

279 int AllocSize = M->getDataLayout().getTypeAllocSize(Args[i]->getType());

280

281

282 BufSize += std::max(AllocSize, 8);

283 }

284 }

285

286

287 Value *SizeToReserve = ConstantInt::get(Builder.getInt64Ty(), BufSize, false);

289 if (NonConstStrLen)

290 SizeToReserve = Builder.CreateAdd(NonConstStrLen, SizeToReserve);

291

294

295

298

300 Type *PtrTy =

301 Builder.getPtrTy(M->getDataLayout().getDefaultGlobalsAddressSpace());

302 FunctionType *FTy_alloc = FunctionType::get(PtrTy, Tys_alloc, false);

303 auto PrintfAllocFn =

304 M->getOrInsertFunction(StringRef("__printf_alloc"), FTy_alloc, Attr);

305

306 return Builder.CreateCall(PrintfAllocFn, Alloc_args, "printf_alloc_fn");

307}

308

309

312 std::string Str(SD->Str.str() + '\0');

313

314 DataExtractor Extractor(Str, true, 8);

316 while (Offset && Offset.tell() < Str.size()) {

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

320 switch (ReadNow) {

321 default:

323 case 1:

325 break;

326 case 2:

328 break;

329 case 3:

331 break;

332 case 4:

334 break;

335 }

336 cantFail(Offset.takeError(), "failed to read bytes from constant array");

337

338 APInt IntVal(8 * ReadSize, ReadBytes);

339

340

341 if (ReadNow < ReadSize)

342 IntVal = IntVal.zext(8 * ReadSize);

343

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

346 }

347

348 int Rem = (Str.size() % 8);

349 if (Rem > 0 && Rem <= 4)

351}

352

355 auto Ty = Arg->getType();

356

357 if (auto IntTy = dyn_cast(Ty)) {

358 if (IntTy->getBitWidth() < 64) {

360 }

361 }

362

363 if (Ty->isFloatingPointTy()) {

364 if (DL.getTypeAllocSize(Ty) < 8) {

366 }

367 }

368

369 return Arg;

370}

371

372static void

376 bool IsConstFmtStr) {

379 auto StrIt = StringContents.begin();

380 size_t i = IsConstFmtStr ? 1 : 0;

381 for (; i < Args.size(); i++) {

383 if ((i == 0) || SpecIsCString.test(i)) {

384 if (StrIt->IsConst) {

386 StrIt++;

387 } else {

388

389

390

391

392

394 Args[i]->getPointerAlignment(DL),

395 StrIt->RealSize);

396

397 PtrToStore =

399 {StrIt->AlignedSize}, "PrintBuffNextPtr");

400 LLVM_DEBUG(dbgs() << "inserting gep to the printf buffer:"

401 << *PtrToStore << '\n');

402

403

404 StrIt++;

405 continue;

406 }

407 } else {

409 }

410

411 for (Value *toStore : WhatToStore) {

413 LLVM_DEBUG(dbgs() << "inserting store to printf buffer:" << *StBuff

414 << '\n');

415 (void)StBuff;

418 M->getDataLayout().getTypeAllocSize(toStore->getType()),

419 "PrintBuffNextPtr");

420 LLVM_DEBUG(dbgs() << "inserting gep to the printf buffer:" << *PtrToStore

421 << '\n');

422 }

423 }

424}

425

427 bool IsBuffered) {

428 auto NumOps = Args.size();

430

431 auto Fmt = Args[0];

434

437

438 if (IsBuffered) {

442 auto Int8Ty = Builder.getInt8Ty();

444 bool IsConstFmtStr = !FmtStr.empty();

445

446 Value *ArgSize = nullptr;

449 SpecIsCString, StringContents, ArgSize);

450

451

452

455

456 auto *Cmp = cast(Builder.CreateICmpNE(Ptr, zeroIntPtr, ""));

457

462

465

466

467

468

469

470 auto ConstantTwo = Builder.getInt32(2);

471 auto ControlDWord = Builder.CreateShl(ArgSize, ConstantTwo);

472 if (IsConstFmtStr)

473 ControlDWord = Builder.CreateOr(ControlDWord, ConstantTwo);

474

476

478

479

480

481 NamedMDNode *metaD = M->getOrInsertNamedMetadata("llvm.printf.fmts");

482 if (IsConstFmtStr) {

483 MD5 Hasher;

485 Hasher.update(FmtStr);

486 Hasher.final(Hash);

487

488

489

490 std::string MetadataStr =

491 "0:0:" + llvm::utohexstr(Hash.low(), true) + "," +

492 FmtStr.str();

496

499 } else {

500

501

502

505 MDString::get(Ctx, "0:0:ffffffff,\"Non const format string\"");

508 }

509 }

510

511

513 IsConstFmtStr);

514

515

518 return Builder.CreateSExt(Builder.CreateNot(Cmp), Int32Ty, "printf_result");

519 }

520

523

524

525

526

527 for (unsigned int i = 1; i != NumOps; ++i) {

528 bool IsLast = i == NumOps - 1;

529 bool IsCString = SpecIsCString.test(i);

531 }

532

534}

static Value * appendString(IRBuilder<> &Builder, Value *Desc, Value *Arg, bool IsLast)

static void callBufferedPrintfArgPush(IRBuilder<> &Builder, ArrayRef< Value * > Args, Value *PtrToStore, SparseBitVector< 8 > &SpecIsCString, SmallVectorImpl< StringData > &StringContents, bool IsConstFmtStr)

static void processConstantStringArg(StringData *SD, IRBuilder<> &Builder, SmallVectorImpl< Value * > &WhatToStore)

static Value * callBufferedPrintfStart(IRBuilder<> &Builder, ArrayRef< Value * > Args, Value *Fmt, bool isConstFmtStr, SparseBitVector< 8 > &SpecIsCString, SmallVectorImpl< StringData > &StringContents, Value *&ArgSize)

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)

static Value * callPrintfBegin(IRBuilder<> &Builder, Value *Version)

static Value * fitArgInto64Bits(IRBuilder<> &Builder, Value *Arg)

static void locateCStrings(SparseBitVector< 8 > &BV, StringRef Str)

static Value * callAppendStringN(IRBuilder<> &Builder, Value *Desc, Value *Str, Value *Length, bool isLast)

static Value * appendArg(IRBuilder<> &Builder, Value *Desc, Value *Arg, bool IsLast)

static Value * processNonStringArg(Value *Arg, IRBuilder<> &Builder)

static Value * processArg(IRBuilder<> &Builder, Value *Desc, Value *Arg, bool SpecIsCString, bool IsLast)

static Value * getStrlenWithNull(IRBuilder<> &Builder, Value *Str)

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

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

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

This file defines the SparseBitVector class.

static SymbolRef::Type getType(const Symbol *Sym)

Class for arbitrary precision integers.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute > > Attrs)

Create an AttributeList with the specified parameters in it.

LLVM Basic Block Representation.

iterator begin()

Instruction iterator methods.

static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)

Creates a new BasicBlock.

BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="", bool Before=false)

Split the basic block into two basic blocks at the specified instruction.

const Function * getParent() const

Return the enclosing method, or null if none.

const DataLayout & getDataLayout() const

Get the data layout of the module this basic block belongs to.

const Instruction * getTerminator() const LLVM_READONLY

Returns the terminator instruction if the block is well formed or null if the block is not well forme...

const Module * getModule() const

Return the module owning the function this basic block belongs to, or nullptr if the function does no...

static BranchInst * Create(BasicBlock *IfTrue, InsertPosition InsertBefore=nullptr)

A constant pointer value that points to null.

static ConstantPointerNull * get(PointerType *T)

Static factory methods - Return objects of the specified value.

static Constant * getNullValue(Type *Ty)

Constructor to create a '0' constant of arbitrary type.

A parsed version of the target data layout string in and methods for querying it.

Type * getDoubleTy()

Fetch the type representing a 64-bit floating point value.

BasicBlock::iterator GetInsertPoint() const

Value * CreateSExt(Value *V, Type *DestTy, const Twine &Name="")

IntegerType * getInt32Ty()

Fetch the type representing a 32-bit integer.

Value * CreateConstInBoundsGEP1_32(Type *Ty, Value *Ptr, unsigned Idx0, const Twine &Name="")

ConstantInt * getInt8(uint8_t C)

Get a constant 8-bit value.

BasicBlock * GetInsertBlock() const

IntegerType * getInt64Ty()

Fetch the type representing a 64-bit integer.

Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")

Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")

Value * CreateGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())

ConstantInt * getInt64(uint64_t C)

Get a constant 64-bit value.

ConstantInt * getInt32(uint32_t C)

Get a constant 32-bit value.

PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")

Value * CreateNot(Value *V, const Twine &Name="")

Value * CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name="")

Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")

ConstantInt * getIntN(unsigned N, uint64_t C)

Get a constant N-bit value, zero extended or truncated from a 64-bit value.

BranchInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)

Create a conditional 'br Cond, TrueDest, FalseDest' instruction.

LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)

Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...

Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)

LLVMContext & getContext() const

Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")

StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)

Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")

CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)

Value * CreateTrunc(Value *V, Type *DestTy, const Twine &Name="", bool IsNUW=false, bool IsNSW=false)

Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="")

PointerType * getPtrTy(unsigned AddrSpace=0)

Fetch the type representing a pointer.

void SetInsertPoint(BasicBlock *TheBB)

This specifies that created instructions should be appended to the end of the specified block.

Value * CreateFPExt(Value *V, Type *DestTy, const Twine &Name="", MDNode *FPMathTag=nullptr)

IntegerType * getInt8Ty()

Fetch the type representing an 8-bit integer.

CallInst * CreateMemCpy(Value *Dst, MaybeAlign DstAlign, Value *Src, MaybeAlign SrcAlign, uint64_t Size, bool isVolatile=false, MDNode *TBAATag=nullptr, MDNode *TBAAStructTag=nullptr, MDNode *ScopeTag=nullptr, MDNode *NoAliasTag=nullptr)

Create and insert a memcpy between the specified pointers.

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

InstListType::iterator eraseFromParent()

This method unlinks 'this' from the containing basic block and deletes it.

This is an important class for using LLVM in a threaded context.

void update(ArrayRef< uint8_t > Data)

Updates the hash for the byte stream provided.

void final(MD5Result &Result)

Finishes off the hash and puts the result in result.

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

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

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

unsigned getNumOperands() const

void addOperand(MDNode *M)

void addIncoming(Value *V, BasicBlock *BB)

Add an incoming value to the end of the PHI list.

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

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

bool test(unsigned Idx) const

An instruction for storing to memory.

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

std::string str() const

str - Get the contents as an std::string.

constexpr bool empty() const

empty - Check if the string is empty.

constexpr size_t size() const

size - Get the string size.

static constexpr size_t npos

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

@ DoubleTyID

64-bit floating point type

static IntegerType * getIntNTy(LLVMContext &C, unsigned N)

LLVM Value Representation.

Type * getType() const

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

#define llvm_unreachable(msg)

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

This is an optimization pass for GlobalISel generic memory operations.

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.

Value * emitAMDGPUPrintfCall(IRBuilder<> &Builder, ArrayRef< Value * > Args, bool isBuffered)

raw_ostream & dbgs()

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

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

Report a fatal error if Err is a failure value.

uint64_t alignTo(uint64_t Size, Align A)

Returns a multiple of A needed to store Size bytes.

StringData(StringRef ST, Value *RS, Value *AS, bool IC)

This struct is a compact representation of a valid (non-zero power of two) alignment.

Description of the encoding of one expression Op.