@@ -52,6 +52,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5252#include < llvm/ADT/STLExtras.h>
5353#include < llvm/ADT/iterator_range.h>
5454#include < llvm/IR/Constants.h>
55+ #include < llvm/IR/DataLayout.h>
5556#include < llvm/IR/IRBuilder.h>
5657#include < llvm/IR/InstIterator.h>
5758#include < llvm/IR/Instructions.h>
@@ -60,6 +61,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6061#include < llvm/Pass.h>
6162#include < llvm/Support/ErrorHandling.h>
6263
64+ #include " llvmWrapper/IR/DerivedTypes.h"
65+
6366#include < algorithm>
6467#include < functional>
6568#include < numeric>
@@ -99,7 +102,8 @@ class GenXPrintfResolution final : public ModulePass {
99102 void setAlwaysInlineForPrintfImpl ();
100103 CallInst &createPrintfInitCall (CallInst &OrigPrintf);
101104 CallInst &createPrintfFmtCall (CallInst &OrigPrintf, CallInst &InitCall);
102- CallInst &createPrintfArgCall (CallInst &OrigPrintf, CallInst &PrevCall);
105+ CallInst &createPrintfArgCall (CallInst &OrigPrintf, CallInst &PrevCall,
106+ Value &Arg);
103107 CallInst &createPrintfRetCall (CallInst &OrigPrintf, CallInst &PrevCall);
104108};
105109} // namespace
@@ -203,7 +207,7 @@ void GenXPrintfResolution::handlePrintfCall(CallInst &OrigPrintf) {
203207 auto &LastArgCall = *std::accumulate (
204208 std::next (OrigPrintf.arg_begin ()), OrigPrintf.arg_end (), &FmtCall,
205209 [&OrigPrintf, this ](CallInst *PrevCall, Value *Arg) {
206- return &createPrintfArgCall (OrigPrintf, *PrevCall);
210+ return &createPrintfArgCall (OrigPrintf, *PrevCall, *Arg );
207211 });
208212 auto &RetCall = createPrintfRetCall (OrigPrintf, LastArgCall);
209213 RetCall.takeName (&OrigPrintf);
@@ -320,10 +324,134 @@ CallInst &GenXPrintfResolution::createPrintfFmtCall(CallInst &OrigPrintf,
320324 OrigPrintf.getName () + " .printf.fmt" );
321325}
322326
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+
323445CallInst &GenXPrintfResolution::createPrintfArgCall (CallInst &OrigPrintf,
324- CallInst &PrevCall) {
446+ CallInst &PrevCall,
447+ Value &Arg) {
325448 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" );
327455}
328456
329457CallInst &GenXPrintfResolution::createPrintfRetCall (CallInst &OrigPrintf,
0 commit comments