//===------ CGGPUBuiltin.cpp - Codegen for GPU builtins -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Generates code for built-in GPU calls which are not runtime-specific.
// (Runtime-specific codegen lives in programming model specific files.)
//
//===----------------------------------------------------------------------===//

#include "CodeGenFunction.h"
#include "clang/Basic/Builtins.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Instruction.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Transforms/Utils/AMDGPUEmitPrintf.h"

using namespace clang;
using namespace CodeGen;

namespace {
llvm::Function *GetVprintfDeclaration(llvm::Module &M) {
  llvm::Type *ArgTypes[] = {llvm::PointerType::getUnqual(M.getContext()),
                            llvm::PointerType::getUnqual(M.getContext())};
  llvm::FunctionType *VprintfFuncType = llvm::FunctionType::get(
      llvm::Type::getInt32Ty(M.getContext()), ArgTypes, false);

  if (auto *F = M.getFunction("vprintf")) {
    // Our CUDA system header declares vprintf with the right signature, so
    // nobody else should have been able to declare vprintf with a bogus
    // signature.
    assert(F->getFunctionType() == VprintfFuncType);
    return F;
  }

  // vprintf doesn't already exist; create a declaration and insert it into the
  // module.
  return llvm::Function::Create(
      VprintfFuncType, llvm::GlobalVariable::ExternalLinkage, "vprintf", &M);
}

// Transforms a call to printf into a call to the NVPTX vprintf syscall (which
// isn't particularly special; it's invoked just like a regular function).
// vprintf takes two args: A format string, and a pointer to a buffer containing
// the varargs.
//
// For example, the call
//
//   printf("format string", arg1, arg2, arg3);
//
// is converted into something resembling
//
//   struct Tmp {
//     Arg1 a1;
//     Arg2 a2;
//     Arg3 a3;
//   };
//   char* buf = alloca(sizeof(Tmp));
//   *(Tmp*)buf = {a1, a2, a3};
//   vprintf("format string", buf);
//
// buf is aligned to the max of {alignof(Arg1), ...}.  Furthermore, each of the
// args is itself aligned to its preferred alignment.
//
// Note that by the time this function runs, E's args have already undergone the
// standard C vararg promotion (short -> int, float -> double, etc.).

std::pair<llvm::Value *, llvm::TypeSize>
packArgsIntoNVPTXFormatBuffer(CodeGenFunction *CGF, const CallArgList &Args) {
  const llvm::DataLayout &DL = CGF->CGM.getDataLayout();
  llvm::LLVMContext &Ctx = CGF->CGM.getLLVMContext();
  CGBuilderTy &Builder = CGF->Builder;

  // Construct and fill the args buffer that we'll pass to vprintf.
  if (Args.size() <= 1) {
    // If there are no args, pass a null pointer and size 0
    llvm::Value *BufferPtr =
        llvm::ConstantPointerNull::get(llvm::PointerType::getUnqual(Ctx));
    return {BufferPtr, llvm::TypeSize::getFixed(0)};
  } else {
    llvm::SmallVector<llvm::Type *, 8> ArgTypes;
    for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I)
      ArgTypes.push_back(Args[I].getRValue(*CGF).getScalarVal()->getType());

    // Using llvm::StructType is correct only because printf doesn't accept
    // aggregates.  If we had to handle aggregates here, we'd have to manually
    // compute the offsets within the alloca -- we wouldn't be able to assume
    // that the alignment of the llvm type was the same as the alignment of the
    // clang type.
    llvm::Type *AllocaTy = llvm::StructType::create(ArgTypes, "printf_args");
    llvm::Value *Alloca = CGF->CreateTempAlloca(AllocaTy);

    for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I) {
      llvm::Value *P = Builder.CreateStructGEP(AllocaTy, Alloca, I - 1);
      llvm::Value *Arg = Args[I].getRValue(*CGF).getScalarVal();
      Builder.CreateAlignedStore(Arg, P, DL.getPrefTypeAlign(Arg->getType()));
    }
    llvm::Value *BufferPtr =
        Builder.CreatePointerCast(Alloca, llvm::PointerType::getUnqual(Ctx));
    return {BufferPtr, DL.getTypeAllocSize(AllocaTy)};
  }
}

bool containsNonScalarVarargs(CodeGenFunction *CGF, const CallArgList &Args) {
  return llvm::any_of(llvm::drop_begin(Args), [&](const CallArg &A) {
    return !A.getRValue(*CGF).isScalar();
  });
}

RValue EmitDevicePrintfCallExpr(const CallExpr *E, CodeGenFunction *CGF,
                                llvm::Function *Decl, bool WithSizeArg) {
  CodeGenModule &CGM = CGF->CGM;
  CGBuilderTy &Builder = CGF->Builder;
  assert(E->getBuiltinCallee() == Builtin::BIprintf ||
         E->getBuiltinCallee() == Builtin::BI__builtin_printf);
  assert(E->getNumArgs() >= 1); // printf always has at least one arg.

  // Uses the same format as nvptx for the argument packing, but also passes
  // an i32 for the total size of the passed pointer
  CallArgList Args;
  CGF->EmitCallArgs(Args,
                    E->getDirectCallee()->getType()->getAs<FunctionProtoType>(),
                    E->arguments(), E->getDirectCallee(),
                    /* ParamsToSkip = */ 0);

  // We don't know how to emit non-scalar varargs.
  if (containsNonScalarVarargs(CGF, Args)) {
    CGM.ErrorUnsupported(E, "non-scalar arg to printf");
    return RValue::get(llvm::ConstantInt::get(CGF->IntTy, 0));
  }

  auto r = packArgsIntoNVPTXFormatBuffer(CGF, Args);
  llvm::Value *BufferPtr = r.first;

  llvm::SmallVector<llvm::Value *, 3> Vec = {
      Args[0].getRValue(*CGF).getScalarVal(), BufferPtr};
  if (WithSizeArg) {
    // Passing > 32bit of data as a local alloca doesn't work for nvptx or
    // amdgpu
    llvm::Constant *Size =
        llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGM.getLLVMContext()),
                               static_cast<uint32_t>(r.second.getFixedValue()));

    Vec.push_back(Size);
  }
  return RValue::get(Builder.CreateCall(Decl, Vec));
}
} // namespace

RValue CodeGenFunction::EmitNVPTXDevicePrintfCallExpr(const CallExpr *E) {
  assert(getTarget().getTriple().isNVPTX());
  return EmitDevicePrintfCallExpr(
      E, this, GetVprintfDeclaration(CGM.getModule()), false);
}

RValue CodeGenFunction::EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E) {
  assert(getTarget().getTriple().isAMDGCN() ||
         (getTarget().getTriple().isSPIRV() &&
          getTarget().getTriple().getVendor() == llvm::Triple::AMD));
  assert(E->getBuiltinCallee() == Builtin::BIprintf ||
         E->getBuiltinCallee() == Builtin::BI__builtin_printf);
  assert(E->getNumArgs() >= 1); // printf always has at least one arg.

  CallArgList CallArgs;
  EmitCallArgs(CallArgs,
               E->getDirectCallee()->getType()->getAs<FunctionProtoType>(),
               E->arguments(), E->getDirectCallee(),
               /* ParamsToSkip = */ 0);

  SmallVector<llvm::Value *, 8> Args;
  for (const auto &A : CallArgs) {
    // We don't know how to emit non-scalar varargs.
    if (!A.getRValue(*this).isScalar()) {
      CGM.ErrorUnsupported(E, "non-scalar arg to printf");
      return RValue::get(llvm::ConstantInt::get(IntTy, -1));
    }

    llvm::Value *Arg = A.getRValue(*this).getScalarVal();
    Args.push_back(Arg);
  }

  llvm::IRBuilder<> IRB(Builder.GetInsertBlock(), Builder.GetInsertPoint());
  IRB.SetCurrentDebugLocation(Builder.getCurrentDebugLocation());

  bool isBuffered = (CGM.getTarget().getTargetOpts().AMDGPUPrintfKindVal ==
                     clang::TargetOptions::AMDGPUPrintfKind::Buffered);
  auto Printf = llvm::emitAMDGPUPrintfCall(IRB, Args, isBuffered);
  Builder.SetInsertPoint(IRB.GetInsertBlock(), IRB.GetInsertPoint());
  return RValue::get(Printf);
}
