@@ -52,6 +52,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52
52
#include < llvm/ADT/STLExtras.h>
53
53
#include < llvm/ADT/iterator_range.h>
54
54
#include < llvm/IR/Constants.h>
55
+ #include < llvm/IR/DataLayout.h>
55
56
#include < llvm/IR/IRBuilder.h>
56
57
#include < llvm/IR/InstIterator.h>
57
58
#include < llvm/IR/Instructions.h>
@@ -60,6 +61,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
60
61
#include < llvm/Pass.h>
61
62
#include < llvm/Support/ErrorHandling.h>
62
63
64
+ #include " llvmWrapper/IR/DerivedTypes.h"
65
+
63
66
#include < algorithm>
64
67
#include < functional>
65
68
#include < numeric>
@@ -99,7 +102,8 @@ class GenXPrintfResolution final : public ModulePass {
99
102
void setAlwaysInlineForPrintfImpl ();
100
103
CallInst &createPrintfInitCall (CallInst &OrigPrintf);
101
104
CallInst &createPrintfFmtCall (CallInst &OrigPrintf, CallInst &InitCall);
102
- CallInst &createPrintfArgCall (CallInst &OrigPrintf, CallInst &PrevCall);
105
+ CallInst &createPrintfArgCall (CallInst &OrigPrintf, CallInst &PrevCall,
106
+ Value &Arg);
103
107
CallInst &createPrintfRetCall (CallInst &OrigPrintf, CallInst &PrevCall);
104
108
};
105
109
} // namespace
@@ -203,7 +207,7 @@ void GenXPrintfResolution::handlePrintfCall(CallInst &OrigPrintf) {
203
207
auto &LastArgCall = *std::accumulate (
204
208
std::next (OrigPrintf.arg_begin ()), OrigPrintf.arg_end (), &FmtCall,
205
209
[&OrigPrintf, this ](CallInst *PrevCall, Value *Arg) {
206
- return &createPrintfArgCall (OrigPrintf, *PrevCall);
210
+ return &createPrintfArgCall (OrigPrintf, *PrevCall, *Arg );
207
211
});
208
212
auto &RetCall = createPrintfRetCall (OrigPrintf, LastArgCall);
209
213
RetCall.takeName (&OrigPrintf);
@@ -320,10 +324,134 @@ CallInst &GenXPrintfResolution::createPrintfFmtCall(CallInst &OrigPrintf,
320
324
OrigPrintf.getName () + " .printf.fmt" );
321
325
}
322
326
327
+ static ArgKind::Enum getIntegerArgKind (Type &ArgTy) {
328
+ IGC_ASSERT_MESSAGE (ArgTy.isIntegerTy (),
329
+ " wrong argument: integer type was expected" );
330
+ auto BitWidth = ArgTy.getIntegerBitWidth ();
331
+ switch (BitWidth) {
332
+ case 64 :
333
+ return ArgKind::Long;
334
+ case 32 :
335
+ return ArgKind::Int;
336
+ case 16 :
337
+ return ArgKind::Short;
338
+ default :
339
+ IGC_ASSERT_MESSAGE (BitWidth == 8 , " unexpected integer type" );
340
+ return ArgKind::Char;
341
+ }
342
+ }
343
+
344
+ static ArgKind::Enum getFloatingPointArgKind (Type &ArgTy) {
345
+ IGC_ASSERT_MESSAGE (ArgTy.isFloatingPointTy (),
346
+ " wrong argument: floating point type was expected" );
347
+ if (ArgTy.isDoubleTy ())
348
+ return ArgKind::Double;
349
+ // FIXME: what about half?
350
+ IGC_ASSERT_MESSAGE (ArgTy.isFloatTy (), " unexpected floating point type" );
351
+ return ArgKind::Float;
352
+ }
353
+
354
+ static ArgKind::Enum getPointerArgKind (Type &ArgTy) {
355
+ IGC_ASSERT_MESSAGE (ArgTy.isPointerTy (),
356
+ " wrong argument: pointer type was expected" );
357
+ if (ArgTy.getPointerElementType ()->isIntegerTy (8 ))
358
+ // FIXME: what if we want to print a pointer to a string?
359
+ // Seems like it cannot be handled without parsing the format string.
360
+ return ArgKind::String;
361
+ return ArgKind::Pointer;
362
+ }
363
+
364
+ static ArgKind::Enum getArgKind (Type &ArgTy) {
365
+ if (ArgTy.isIntegerTy ())
366
+ return getIntegerArgKind (ArgTy);
367
+ if (ArgTy.isFloatingPointTy ())
368
+ return getFloatingPointArgKind (ArgTy);
369
+ return getPointerArgKind (ArgTy);
370
+ }
371
+
372
+ // sizeof(<2 x i32>) == 64
373
+ static constexpr unsigned VecArgSize = 64 ;
374
+ static constexpr auto VecArgElementSize = VecArgSize / ArgData::Size;
375
+
376
+ // Casts Arg to <2 x i32> vector. For pointers ptrtoint i64 should be generated
377
+ // first.
378
+ Value &get64BitArgAsVector (Value &Arg, IRBuilder<> &IRB, const DataLayout &DL) {
379
+ IGC_ASSERT_MESSAGE (DL.getTypeSizeInBits (Arg.getType ()) == 64 ,
380
+ " 64-bit argument was expected" );
381
+ auto *VecArgTy =
382
+ IGCLLVM::FixedVectorType::get (IRB.getInt32Ty (), ArgData::Size);
383
+ Value *ArgToBitCast = &Arg;
384
+ if (Arg.getType ()->isPointerTy ())
385
+ ArgToBitCast =
386
+ IRB.CreatePtrToInt (&Arg, IRB.getInt64Ty (), Arg.getName () + " .arg.p2i" );
387
+ return *IRB.CreateBitCast (ArgToBitCast, VecArgTy, Arg.getName () + " .arg.bc" );
388
+ }
389
+
390
+ // Just creates this instruction:
391
+ // insertelement <2 x i32> zeroinitializer, i32 %arg, i32 0
392
+ // \p Arg must be i32 type.
393
+ Value &get32BitIntArgAsVector (Value &Arg, IRBuilder<> &IRB,
394
+ const DataLayout &DL) {
395
+ IGC_ASSERT_MESSAGE (Arg.getType ()->isIntegerTy (32 ),
396
+ " i32 argument was expected" );
397
+ auto *VecArgTy =
398
+ IGCLLVM::FixedVectorType::get (IRB.getInt32Ty (), ArgData::Size);
399
+ auto *BlankVec = ConstantAggregateZero::get (VecArgTy);
400
+ return *IRB.CreateInsertElement (BlankVec, &Arg, IRB.getInt32 (0 ),
401
+ Arg.getName () + " .arg.insert" );
402
+ }
403
+
404
+ // Takes arg that is not greater than 32 bit and casts it to i32 with possible
405
+ // zero extension.
406
+ static Value &getArgAs32BitInt (Value &Arg, IRBuilder<> &IRB,
407
+ const DataLayout &DL) {
408
+ auto ArgSize = DL.getTypeSizeInBits (Arg.getType ());
409
+ IGC_ASSERT_MESSAGE (ArgSize <= VecArgElementSize,
410
+ " argument isn't expected to be greater than 32 bit" );
411
+ if (ArgSize < VecArgElementSize) {
412
+ // FIXME: seems like there may be some problems with signed types, depending
413
+ // on our BiF and runtime implementation.
414
+ // FIXME: What about half?
415
+ IGC_ASSERT_MESSAGE (Arg.getType ()->isIntegerTy (),
416
+ " only integers are expected to be less than 32 bits" );
417
+ return *IRB.CreateZExt (&Arg, IRB.getInt32Ty (), Arg.getName () + " .arg.zext" );
418
+ }
419
+ if (Arg.getType ()->isPointerTy ())
420
+ return *IRB.CreatePtrToInt (&Arg, IRB.getInt32Ty (),
421
+ Arg.getName () + " .arg.p2i" );
422
+ if (!Arg.getType ()->isIntegerTy ())
423
+ return *IRB.CreateBitCast (&Arg, IRB.getInt32Ty (),
424
+ Arg.getName () + " .arg.bc" );
425
+ return Arg;
426
+ }
427
+
428
+ // Args are passed via <2 x i32> vector. This function casts \p Arg to this
429
+ // vector type. \p Arg is zext if necessary (zext in common sense - writing
430
+ // top element of a vector with zeros is zero extending too).
431
+ static Value &getArgAsVector (Value &Arg, IRBuilder<> &IRB,
432
+ const DataLayout &DL) {
433
+ IGC_ASSERT_MESSAGE (!isa<IGCLLVM::FixedVectorType>(Arg.getType ()),
434
+ " scalar type is expected" );
435
+ auto ArgSize = DL.getTypeSizeInBits (Arg.getType ());
436
+
437
+ if (ArgSize == VecArgSize)
438
+ return get64BitArgAsVector (Arg, IRB, DL);
439
+ IGC_ASSERT_MESSAGE (ArgSize < VecArgSize,
440
+ " arg is expected to be not greater than 64 bit" );
441
+ Value &Arg32Bit = getArgAs32BitInt (Arg, IRB, DL);
442
+ return get32BitIntArgAsVector (Arg32Bit, IRB, DL);
443
+ }
444
+
323
445
CallInst &GenXPrintfResolution::createPrintfArgCall (CallInst &OrigPrintf,
324
- CallInst &PrevCall) {
446
+ CallInst &PrevCall,
447
+ Value &Arg) {
325
448
assertPrintfCall (OrigPrintf);
326
- return PrevCall;
449
+ ArgKind::Enum Kind = getArgKind (*Arg.getType ());
450
+ IRBuilder<> IRB{&OrigPrintf};
451
+ Value &ArgVec = getArgAsVector (Arg, IRB, *DL);
452
+ return *IRB.CreateCall (PrintfImplDecl[PrintfImplFunc::Arg],
453
+ {&PrevCall, IRB.getInt32 (Kind), &ArgVec},
454
+ OrigPrintf.getName () + " .printf.arg" );
327
455
}
328
456
329
457
CallInst &GenXPrintfResolution::createPrintfRetCall (CallInst &OrigPrintf,
0 commit comments