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