Skip to content

Commit e2f0a77

Browse files
andykayloraokblast
authored andcommitted
[CIR][NFC] Add infrastructure for handling X86 builtins (llvm#164465)
This adds the infrastructure for handling x86-specific builtin calls. It does not add any actual handling, just the code structure and a large switch statement containing all of the builtins that will eventually need to be handled. Target-specific builtins for other targets will be added later.
1 parent 5cb1bbe commit e2f0a77

File tree

5 files changed

+918
-1
lines changed

5 files changed

+918
-1
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ struct MissingFeatures {
257257
static bool generateDebugInfo() { return false; }
258258
static bool globalViewIndices() { return false; }
259259
static bool globalViewIntLowering() { return false; }
260+
static bool handleBuiltinICEArguments() { return false; }
260261
static bool hip() { return false; }
261262
static bool incrementProfileCounter() { return false; }
262263
static bool innermostEHScope() { return false; }

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,12 +463,107 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
463463
return emitLibraryCall(*this, fd, e,
464464
cgm.getBuiltinLibFunction(fd, builtinID));
465465

466+
// Some target-specific builtins can have aggregate return values, e.g.
467+
// __builtin_arm_mve_vld2q_u32. So if the result is an aggregate, force
468+
// returnValue to be non-null, so that the target-specific emission code can
469+
// always just emit into it.
470+
cir::TypeEvaluationKind evalKind = getEvaluationKind(e->getType());
471+
if (evalKind == cir::TEK_Aggregate && returnValue.isNull()) {
472+
cgm.errorNYI(e->getSourceRange(), "aggregate return value from builtin");
473+
return getUndefRValue(e->getType());
474+
}
475+
476+
// Now see if we can emit a target-specific builtin.
477+
if (mlir::Value v = emitTargetBuiltinExpr(builtinID, e, returnValue)) {
478+
switch (evalKind) {
479+
case cir::TEK_Scalar:
480+
if (mlir::isa<cir::VoidType>(v.getType()))
481+
return RValue::get(nullptr);
482+
return RValue::get(v);
483+
case cir::TEK_Aggregate:
484+
cgm.errorNYI(e->getSourceRange(), "aggregate return value from builtin");
485+
return getUndefRValue(e->getType());
486+
case cir::TEK_Complex:
487+
llvm_unreachable("No current target builtin returns complex");
488+
}
489+
llvm_unreachable("Bad evaluation kind in EmitBuiltinExpr");
490+
}
491+
466492
cgm.errorNYI(e->getSourceRange(),
467493
std::string("unimplemented builtin call: ") +
468494
getContext().BuiltinInfo.getName(builtinID));
469495
return getUndefRValue(e->getType());
470496
}
471497

498+
static mlir::Value emitTargetArchBuiltinExpr(CIRGenFunction *cgf,
499+
unsigned builtinID,
500+
const CallExpr *e,
501+
ReturnValueSlot &returnValue,
502+
llvm::Triple::ArchType arch) {
503+
// When compiling in HipStdPar mode we have to be conservative in rejecting
504+
// target specific features in the FE, and defer the possible error to the
505+
// AcceleratorCodeSelection pass, wherein iff an unsupported target builtin is
506+
// referenced by an accelerator executable function, we emit an error.
507+
// Returning nullptr here leads to the builtin being handled in
508+
// EmitStdParUnsupportedBuiltin.
509+
if (cgf->getLangOpts().HIPStdPar && cgf->getLangOpts().CUDAIsDevice &&
510+
arch != cgf->getTarget().getTriple().getArch())
511+
return {};
512+
513+
switch (arch) {
514+
case llvm::Triple::arm:
515+
case llvm::Triple::armeb:
516+
case llvm::Triple::thumb:
517+
case llvm::Triple::thumbeb:
518+
case llvm::Triple::aarch64:
519+
case llvm::Triple::aarch64_32:
520+
case llvm::Triple::aarch64_be:
521+
case llvm::Triple::bpfeb:
522+
case llvm::Triple::bpfel:
523+
// These are actually NYI, but that will be reported by emitBuiltinExpr.
524+
// At this point, we don't even know that the builtin is target-specific.
525+
return nullptr;
526+
527+
case llvm::Triple::x86:
528+
case llvm::Triple::x86_64:
529+
return cgf->emitX86BuiltinExpr(builtinID, e);
530+
531+
case llvm::Triple::ppc:
532+
case llvm::Triple::ppcle:
533+
case llvm::Triple::ppc64:
534+
case llvm::Triple::ppc64le:
535+
case llvm::Triple::r600:
536+
case llvm::Triple::amdgcn:
537+
case llvm::Triple::systemz:
538+
case llvm::Triple::nvptx:
539+
case llvm::Triple::nvptx64:
540+
case llvm::Triple::wasm32:
541+
case llvm::Triple::wasm64:
542+
case llvm::Triple::hexagon:
543+
case llvm::Triple::riscv32:
544+
case llvm::Triple::riscv64:
545+
// These are actually NYI, but that will be reported by emitBuiltinExpr.
546+
// At this point, we don't even know that the builtin is target-specific.
547+
return {};
548+
default:
549+
return {};
550+
}
551+
}
552+
553+
mlir::Value
554+
CIRGenFunction::emitTargetBuiltinExpr(unsigned builtinID, const CallExpr *e,
555+
ReturnValueSlot &returnValue) {
556+
if (getContext().BuiltinInfo.isAuxBuiltinID(builtinID)) {
557+
assert(getContext().getAuxTargetInfo() && "Missing aux target info");
558+
return emitTargetArchBuiltinExpr(
559+
this, getContext().BuiltinInfo.getAuxBuiltinID(builtinID), e,
560+
returnValue, getContext().getAuxTargetInfo()->getTriple().getArch());
561+
}
562+
563+
return emitTargetArchBuiltinExpr(this, builtinID, e, returnValue,
564+
getTarget().getTriple().getArch());
565+
}
566+
472567
/// Given a builtin id for a function like "__builtin_fabsf", return a Function*
473568
/// for "fabsf".
474569
cir::FuncOp CIRGenModule::getBuiltinLibFunction(const FunctionDecl *fd,

0 commit comments

Comments
 (0)