This emits a device-side call to "i32 vprintf(i8* fmt, arguments_type* arguments)" in the driver; see http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability/index.html#system-calls
| 330 | // "i32 vprintf(i8* fmt, arguments_type* arguments)" in the driver; see |
| 331 | // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability/index.html#system-calls |
| 332 | llvm::Value* EmitPrintf(absl::string_view fmt, |
| 333 | absl::Span<llvm::Value* const> arguments, |
| 334 | llvm::IRBuilder<>* builder) { |
| 335 | std::vector<llvm::Type*> argument_types; |
| 336 | |
| 337 | // Variadic arguments implicit promotion [1] converts float to double, |
| 338 | // and bool/char/short are converted to int. |
| 339 | // [1] https://en.cppreference.com/w/cpp/language/variadic_arguments |
| 340 | auto requires_int32_promotion = [](llvm::Type* type) { |
| 341 | return type->isIntegerTy(/*BitWidth=*/1) || |
| 342 | type->isIntegerTy(/*BitWidth=*/8) || |
| 343 | type->isIntegerTy(/*BitWidth=*/16); |
| 344 | }; |
| 345 | auto requires_double_promotion = [](llvm::Type* type) { |
| 346 | return type->isFloatingPointTy(); |
| 347 | }; |
| 348 | |
| 349 | for (auto argument : arguments) { |
| 350 | llvm::Type* type = argument->getType(); |
| 351 | if (requires_double_promotion(type)) { |
| 352 | argument_types.push_back(builder->getDoubleTy()); |
| 353 | } else if (requires_int32_promotion(type)) { |
| 354 | argument_types.push_back(builder->getInt32Ty()); |
| 355 | } else { |
| 356 | argument_types.push_back(type); |
| 357 | } |
| 358 | } |
| 359 | auto* arguments_type = llvm::StructType::create(argument_types); |
| 360 | llvm::Value* arguments_ptr = builder->CreateAlloca(arguments_type); |
| 361 | for (size_t i = 0; i < arguments.size(); ++i) { |
| 362 | llvm::Value* value = arguments[i]; |
| 363 | llvm::Type* type = value->getType(); |
| 364 | if (requires_double_promotion(type)) { |
| 365 | value = builder->CreateFPCast(value, builder->getDoubleTy()); |
| 366 | } else if (requires_int32_promotion(type)) { |
| 367 | value = builder->CreateIntCast(value, builder->getInt32Ty(), |
| 368 | /*isSigned=*/true); |
| 369 | } |
| 370 | builder->CreateStore( |
| 371 | value, builder->CreateGEP(arguments_ptr, {builder->getInt64(0), |
| 372 | builder->getInt32(i)})); |
| 373 | } |
| 374 | llvm::Type* ptr_ty = builder->getInt8Ty()->getPointerTo(); |
| 375 | return builder->CreateCall( |
| 376 | builder->GetInsertBlock()->getParent()->getParent()->getOrInsertFunction( |
| 377 | "vprintf", |
| 378 | llvm::FunctionType::get(builder->getInt32Ty(), {ptr_ty, ptr_ty}, |
| 379 | /*isVarArg=*/false)), |
| 380 | {builder->CreateGlobalStringPtr(llvm_ir::AsStringRef(fmt)), |
| 381 | builder->CreatePointerCast(arguments_ptr, ptr_ty)}); |
| 382 | } |
| 383 | |
| 384 | // Helper function to emit call to AMDGPU shfl_down function. |
| 385 | llvm::Value* EmitAMDGPUShflDown(llvm::Value* value, llvm::Value* offset, |
no test coverage detected