1
1
module KernelAbstractions
2
2
3
3
export @kernel
4
- export @Const , @localmem , @private , @uniform , @synchronize , @index , groupsize, @print
4
+ export @Const , @localmem , @private , @uniform , @synchronize , @index , groupsize, @print , @printf
5
5
export Device, GPU, CPU, CUDADevice, Event, MultiEvent, NoneEvent
6
6
export async_copy!
7
7
8
8
9
9
using MacroTools
10
+ using Printf
10
11
using StaticArrays
11
12
using Cassette
12
13
using Adapt
@@ -28,6 +29,7 @@ and then invoked on the arguments.
28
29
- [`@uniform`](@ref)
29
30
- [`@synchronize`](@ref)
30
31
- [`@print`](@ref)
32
+ - [`@printf`](@ref)
31
33
32
34
# Example:
33
35
@@ -236,6 +238,37 @@ macro print(items...)
236
238
end
237
239
end
238
240
241
+ @generated function promote_c_argument (arg)
242
+ # > When a function with a variable-length argument list is called, the variable
243
+ # > arguments are passed using C's old ``default argument promotions.'' These say that
244
+ # > types char and short int are automatically promoted to int, and type float is
245
+ # > automatically promoted to double. Therefore, varargs functions will never receive
246
+ # > arguments of type char, short int, or float.
247
+
248
+ if arg == Cchar || arg == Cshort
249
+ return :(Cint (arg))
250
+ elseif arg == Cfloat
251
+ return :(Cdouble (arg))
252
+ else
253
+ return :(arg)
254
+ end
255
+ end
256
+
257
+ """
258
+ @printf(fmt::String, args...)
259
+
260
+ This is a unified formatted print statement.
261
+
262
+ # Platform differences
263
+ - `GPU`: This will reorganize the items to print via @cuprintf
264
+ - `CPU`: This will call `print(items...)`
265
+ """
266
+ macro printf (fmt:: String , args... )
267
+ fmt_val = Val (Symbol (fmt))
268
+
269
+ return :(__printf ($ fmt_val, $ (map (arg -> :(promote_c_argument ($ arg)), esc .(args))... )))
270
+ end
271
+
239
272
"""
240
273
@index
241
274
452
485
end
453
486
end
454
487
488
+ # Results in "Conversion of boxed type String is not allowed"
489
+ # @generated function __printf(::Val{fmt}, argspec...) where {fmt}
490
+ # arg_exprs = [:( argspec[$i] ) for i in 1:length(argspec)]
491
+ # arg_types = [argspec...]
492
+
493
+ # T_void = LLVM.VoidType(LLVM.Interop.JuliaContext())
494
+ # T_int32 = LLVM.Int32Type(LLVM.Interop.JuliaContext())
495
+ # T_pint8 = LLVM.PointerType(LLVM.Int8Type(LLVM.Interop.JuliaContext()))
496
+
497
+ # # create functions
498
+ # param_types = LLVMType[convert.(LLVMType, arg_types)...]
499
+ # llvm_f, _ = create_function(T_int32, param_types)
500
+ # mod = LLVM.parent(llvm_f)
501
+ # sfmt = String(fmt)
502
+ # # generate IR
503
+ # Builder(LLVM.Interop.JuliaContext()) do builder
504
+ # entry = BasicBlock(llvm_f, "entry", LLVM.Interop.JuliaContext())
505
+ # position!(builder, entry)
506
+
507
+ # str = globalstring_ptr!(builder, sfmt)
508
+
509
+ # # construct and fill args buffer
510
+ # if isempty(argspec)
511
+ # buffer = LLVM.PointerNull(T_pint8)
512
+ # else
513
+ # argtypes = LLVM.StructType("printf_args", LLVM.Interop.JuliaContext())
514
+ # elements!(argtypes, param_types)
515
+
516
+ # args = alloca!(builder, argtypes)
517
+ # for (i, param) in enumerate(parameters(llvm_f))
518
+ # p = struct_gep!(builder, args, i-1)
519
+ # store!(builder, param, p)
520
+ # end
521
+
522
+ # buffer = bitcast!(builder, args, T_pint8)
523
+ # end
524
+
525
+ # # invoke vprintf and return
526
+ # vprintf_typ = LLVM.FunctionType(T_int32, [T_pint8, T_pint8])
527
+ # vprintf = LLVM.Function(mod, "vprintf", vprintf_typ)
528
+ # chars = call!(builder, vprintf, [str, buffer])
529
+
530
+ # ret!(builder, chars)
531
+ # end
532
+
533
+ # arg_tuple = Expr(:tuple, arg_exprs...)
534
+ # call_function(llvm_f, Int32, Tuple{arg_types...}, arg_tuple)
535
+ # end
536
+
537
+ # Results in "InvalidIRError: compiling kernel
538
+ # gpu_kernel_printf(... Reason: unsupported dynamic
539
+ # function invocation"
540
+ @generated function __printf (:: Val{fmt} , items... ) where {fmt}
541
+ str = " "
542
+ args = []
543
+
544
+ for i in 1 : length (items)
545
+ item = :(items[$ i])
546
+ T = items[i]
547
+ if T <: Val
548
+ item = QuoteNode (T. parameters[1 ])
549
+ end
550
+ push! (args, item)
551
+ end
552
+ sfmt = String (fmt)
553
+ quote
554
+ # @sprintf($sfmt, $(args...))
555
+ @print (@sprintf ($ sfmt, $ (args... )))
556
+ # @print("test")
557
+ end
558
+ end
559
+
455
560
# ##
456
561
# Backends/Implementation
457
562
# ##
0 commit comments