Repository: llvm/llvm-project
File: llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp (C++)

Code before:

std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
                                 SPIRV::InstructionSet::InstructionSet Set,
                                 MachineIRBuilder &MIRBuilder,
                                 const Register OrigRet, const Type *OrigRetTy,
                                 const SmallVectorImpl<Register> &Args,
                                 SPIRVGlobalRegistry *GR, const CallBase &CB) {
  LLVM_DEBUG(dbgs() << "Lowering builtin call: " << DemangledCall << "\n");

  // Lookup the builtin in the TableGen records.
  SPIRVTypeInst SpvType = GR->getSPIRVTypeForVReg(OrigRet);
  assert(SpvType && "Inconsistent return register: expected valid type info");
  std::unique_ptr<const IncomingCall> Call =
      lookupBuiltin(DemangledCall, Set, OrigRet, SpvType, Args);

  if (!Call) {
    LLVM_DEBUG(dbgs() << "Builtin record was not found!\n");
    return std::nullopt;
  }

  // Check if the provided args meet the builtin requirements. If not, treat
  // the call as a regular function call rather than crashing.
  if (Args.size() < Call->Builtin->MinNumArgs) {
    LLVM_DEBUG(dbgs() << "Too few arguments for builtin " << DemangledCall
                      << ": expected at least " << Call->Builtin->MinNumArgs
                      << ", got " << Args.size() << "\n");
    return std::nullopt;
  }
  if (Call->Builtin->MaxNumArgs && Args.size() > Call->Builtin->MaxNumArgs)
    LLVM_DEBUG(dbgs() << "More arguments provided than required!\n");

  // Match the builtin with implementation based on the grouping.
  switch (Call->Builtin->Group) {
  case SPIRV::Extended:
    return generateExtInst(Call.get(), MIRBuilder, GR, CB);
  case SPIRV::Relational:
    return generateRelationalInst(Call.get(), MIRBuilder, GR);
  case SPIRV::Group:
    return generateGroupInst(Call.get(), MIRBuilder, GR);
  case SPIRV::Variable:
    return generateBuiltinVar(Call.get(), MIRBuilder, GR);
  case SPIRV::Atomic:
    return generateAtomicInst(Call.get(), MIRBuilder, GR);
  case SPIRV::AtomicFloating:
    return generateAtomicFloatingInst(Call.get(), MIRBuilder, GR);
  case SPIRV::Barrier:
    return generateBarrierInst(Call.get(), MIRBuilder, GR);
  case SPIRV::CastToPtr:
    return generateCastToPtrInst(Call.get(), MIRBuilder, GR);
  case SPIRV::Dot:
  case SPIRV::IntegerDot:

Review comment (suggestion):
I would extend this message to say that we're treating it as a regular function. Also, if we go with @vmaksimo's suggestion of also checking max args, we could go with something like "Unexpected number of arguments for builtin. Expected X, got Y. Treating FuncName as a regular function call."

Code after:

std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
                                 SPIRV::InstructionSet::InstructionSet Set,
                                 MachineIRBuilder &MIRBuilder,
                                 const Register OrigRet, const Type *OrigRetTy,
                                 const SmallVectorImpl<Register> &Args,
                                 SPIRVGlobalRegistry *GR, const CallBase &CB) {
  LLVM_DEBUG(dbgs() << "Lowering builtin call: " << DemangledCall << "\n");

  // Lookup the builtin in the TableGen records.
  SPIRVTypeInst SpvType = GR->getSPIRVTypeForVReg(OrigRet);
  assert(SpvType && "Inconsistent return register: expected valid type info");
  std::unique_ptr<const IncomingCall> Call =
      lookupBuiltin(DemangledCall, Set, OrigRet, SpvType, Args);

  if (!Call) {
    LLVM_DEBUG(dbgs() << "Builtin record was not found!\n");
    return std::nullopt;
  }

  // Check if the provided args meet the builtin requirements. If not, treat
  // the call as a regular function call rather than crashing.
  if (Args.size() < Call->Builtin->MinNumArgs) {
    LLVM_DEBUG(dbgs() << "Too few arguments for builtin " << DemangledCall
                      << ": expected at least " << Call->Builtin->MinNumArgs
                      << ", got " << Args.size()
                      << "; treating as a normal function\n");
    return std::nullopt;
  }
  if (Call->Builtin->MaxNumArgs && Args.size() > Call->Builtin->MaxNumArgs) {
    LLVM_DEBUG(dbgs() << "Too many arguments for builtin " << DemangledCall
                      << ": expected at most " << Call->Builtin->MaxNumArgs
                      << ", got " << Args.size()
                      << "; treating as a normal function\n");
    return std::nullopt;
  }

  // Match the builtin with implementation based on the grouping.
  switch (Call->Builtin->Group) {
  case SPIRV::Extended:
    return generateExtInst(Call.get(), MIRBuilder, GR, CB);
  case SPIRV::Relational:
    return generateRelationalInst(Call.get(), MIRBuilder, GR);
  case SPIRV::Group:
    return generateGroupInst(Call.get(), MIRBuilder, GR);
  case SPIRV::Variable:
    return generateBuiltinVar(Call.get(), MIRBuilder, GR);
  case SPIRV::Atomic:
    return generateAtomicInst(Call.get(), MIRBuilder, GR);
  case SPIRV::AtomicFloating:
    return generateAtomicFloatingInst(Call.get(), MIRBuilder, GR);