37#include "mlir/ABI/ABIRewriteContext.h"
38#include "mlir/ABI/ABITypeMapper.h"
39#include "mlir/ABI/Targets/Test/TestTarget.h"
40#include "mlir/Dialect/DLTI/DLTI.h"
41#include "mlir/IR/Builders.h"
42#include "mlir/IR/BuiltinOps.h"
43#include "mlir/IR/SymbolTable.h"
44#include "mlir/Interfaces/DataLayoutInterfaces.h"
45#include "mlir/Pass/Pass.h"
49#include "llvm/ABI/FunctionInfo.h"
50#include "llvm/ABI/TargetInfo.h"
51#include "llvm/ABI/Types.h"
52#include "llvm/ADT/ScopeExit.h"
53#include "llvm/ADT/StringExtras.h"
54#include "llvm/ADT/TypeSwitch.h"
55#include "llvm/IR/CallingConv.h"
56#include "llvm/Support/MathExtras.h"
62using namespace mlir::abi;
66#define GEN_PASS_DEF_CALLCONVLOWERING
67#include "clang/CIR/Dialect/Passes.h.inc"
88 return layout.getArgPassingKind() == cir::ArgPassingKind::CanPassInRegs;
95 if (isa<cir::VectorType>(ty))
96 return llvm::PowerOf2Ceil(dl.getTypeSizeInBits(ty).getFixedValue()) >= 128;
97 if (
auto fpTy = dyn_cast<cir::FPTypeInterface>(ty))
98 return &fpTy.getFloatSemantics() == &llvm::APFloat::IEEEquad();
99 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
101 if (
auto recTy = dyn_cast<cir::RecordType>(ty))
102 return recTy.isComplete() &&
103 llvm::any_of(recTy.getMembers(),
104 [&](mlir::Type m) { return mayReachSseUp(m, dl); });
107 assert((isa<cir::IntType, cir::BoolType, cir::PointerType, cir::VPtrType,
108 cir::VoidType, cir::ComplexType, cir::BitFieldType>(ty)) &&
109 "unhandled type in the SSEUP walk");
118 const DataLayout &dl) {
119 if (recordBits == 128 || recordBits == 256 || recordBits == 512)
121 if (recordBits < 128 || recordBits > 512)
123 return llvm::any_of(members,
130 while (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
131 ty = arrTy.getElementType();
132 auto recTy = dyn_cast<cir::RecordType>(ty);
133 return recTy && recTy.isEmptyForABI();
143 const DataLayout &dl) {
146 return llvm::Align(dl.getTypeABIAlignment(recTy));
147 return llvm::Align(layout.getRecordAlign());
154 if (
auto recTy = dyn_cast<cir::RecordType>(ty))
155 return !recTy.isComplete() ||
157 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
173 if (
auto ptrTy = dyn_cast<cir::PointerType>(ty))
174 return !ptrTy.getAddrSpace() ||
175 mlir::isa<cir::TargetAddressSpaceAttr>(ptrTy.getAddrSpace());
179 if (isa<cir::VPtrType>(ty)) {
183 if (isa<cir::VoidType, cir::BoolType>(ty))
187 if (isa<cir::FPTypeInterface>(ty))
189 if (
auto intTy = dyn_cast<cir::IntType>(ty)) {
197 if (intTy.getIsBitInt())
199 return intTy.getWidth() <= 64 || intTy.getWidth() == 128;
201 if (
auto complexTy = dyn_cast<cir::ComplexType>(ty))
203 if (
auto vecTy = dyn_cast<cir::VectorType>(ty)) {
206 if (vecTy.isScalable())
211 mlir::Type elemTy = vecTy.getElementType();
212 if (
auto elemInt = dyn_cast<cir::IntType>(elemTy)) {
213 if (elemInt.getWidth() % 8)
215 }
else if (!isa<cir::FPTypeInterface, cir::BoolType>(elemTy)) {
220 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
225 if (
auto bfTy = dyn_cast<cir::BitFieldType>(ty)) {
226 if (mlir::Type storageTy = bfTy.getStorageType())
229 return llvm::all_of(bfTy.getFields(), [&](cir::BitFieldDeclAttr decl) {
230 return isSupportedType(decl.getDeclaredType(), dl);
233 if (
auto recTy = dyn_cast<cir::RecordType>(ty)) {
235 if (!recTy.isComplete())
239 if (!llvm::all_of(recTy.getMembers(),
240 [&](mlir::Type m) { return isSupportedType(m, dl); }))
242 if (recTy.isUnion()) {
244 uint64_t recordBits = dl.getTypeSizeInBits(recTy).getFixedValue();
252 if (members.empty() && recordBits > 128)
257 if (llvm::any_of(members, [&](mlir::Type m) {
258 auto bfTy = dyn_cast<cir::BitFieldType>(m);
259 if (!bfTy || dl.getTypeSizeInBits(bfTy).getFixedValue() <= 64)
261 return llvm::any_of(bfTy.getFields(), [](cir::BitFieldDeclAttr d) {
262 auto intTy = dyn_cast<cir::IntType>(d.getDeclaredType());
263 return intTy && intTy.getIsBitInt();
276 for (
auto [idx, memberTy,
kind] :
277 llvm::enumerate(recTy.getMembers(), recTy.getMemberKinds())) {
278 if (
kind != cir::RecordMemberKind::Empty)
280 if (dl.getTypeSizeInBits(memberTy).getFixedValue()) {
283 }
else if (recTy.getElementOffset(dl, idx) %
284 dl.getTypeABIAlignment(memberTy)) {
295static mlir::Type
abiTypeToCIR(
const llvm::abi::Type *ty, MLIRContext *ctx) {
298 return llvm::TypeSwitch<const llvm::abi::Type *, mlir::Type>(ty)
300 [&](
const llvm::abi::VoidType *) {
return cir::VoidType::get(ctx); })
301 .Case([&](
const llvm::abi::IntegerType *intTy) -> mlir::Type {
304 return cir::BoolType::get(ctx);
305 return cir::IntType::get(ctx, intTy->getSizeInBits().getFixedValue(),
306 intTy->isSigned(), intTy->isBitInt());
308 .Case([&](
const llvm::abi::FloatType *fltTy) {
311 .Case([&](
const llvm::abi::PointerType *ptrTy) {
312 auto voidTy = cir::VoidType::get(ctx);
313 if (
unsigned as = ptrTy->getAddrSpace())
314 return cir::PointerType::get(
315 voidTy, cir::TargetAddressSpaceAttr::get(ctx, as));
316 return cir::PointerType::get(voidTy);
318 .Case([&](
const llvm::abi::VectorType *vecTy) -> mlir::Type {
319 mlir::Type elemCIR =
abiTypeToCIR(vecTy->getElementType(), ctx);
322 return cir::VectorType::getFixed(
323 elemCIR, vecTy->getNumElements().getFixedValue());
325 .Case([&](
const llvm::abi::ArrayType *arrTy) -> mlir::Type {
326 mlir::Type elemCIR =
abiTypeToCIR(arrTy->getElementType(), ctx);
329 return cir::ArrayType::get(elemCIR, arrTy->getNumElements());
331 .Case([&](
const llvm::abi::RecordType *recTy) -> mlir::Type {
333 fieldTypes.reserve(recTy->getFields().size());
334 for (
const auto &field : recTy->getFields()) {
335 mlir::Type fieldCIR =
abiTypeToCIR(field.FieldType, ctx);
338 fieldTypes.push_back(fieldCIR);
341 return cir::StructType::get(
342 ctx, fieldTypes,
false,
345 .Default([](
const llvm::abi::Type *) -> mlir::Type {
return nullptr; });
352 if (
auto vecTy = dyn_cast<cir::VectorType>(ty)) {
353 if (
auto longDoubleTy =
354 dyn_cast<cir::LongDoubleType>(vecTy.getElementType()))
355 return cir::VectorType::get(longDoubleTy.getUnderlying(),
365 mlir::abi::ABITypeMapper &typeMapper,
366 const DataLayout &dl, ModuleOp modOp) {
367 llvm::abi::TypeBuilder &tb = typeMapper.getTypeBuilder();
368 return llvm::TypeSwitch<mlir::Type, const llvm::abi::Type *>(type)
369 .Case([&](cir::IntType intTy) {
370 return tb.getIntegerType(intTy.getWidth(),
371 llvm::Align(dl.getTypeABIAlignment(type)),
372 intTy.isSigned(), intTy.getIsBitInt());
374 .Case([&](cir::PointerType ptrTy) {
375 unsigned addrSpace = 0;
376 if (
auto targetAsAttr =
377 dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
378 ptrTy.getAddrSpace()))
379 addrSpace = targetAsAttr.getValue();
381 bool hasAddressSpaceQualifier = ptrTy.getAddrSpace() !=
nullptr;
382 return tb.getPointerType(dl.getTypeSizeInBits(type),
383 llvm::Align(dl.getTypeABIAlignment(type)),
384 addrSpace, hasAddressSpaceQualifier);
386 .Case([&](cir::VPtrType) {
390 return tb.getPointerType(dl.getTypeSizeInBits(type),
391 llvm::Align(dl.getTypeABIAlignment(type)));
393 .Case([&](cir::BoolType) {
396 return tb.getIntegerType(1, llvm::Align(dl.getTypeABIAlignment(type)),
399 .Case([&](cir::VoidType) {
return tb.getVoidType(); })
400 .Case([&](cir::FPTypeInterface fpTy) {
403 return tb.getFloatType(fpTy.getFloatSemantics(),
404 llvm::Align(dl.getTypeABIAlignment(type)));
406 .Case([&](cir::ComplexType complexTy) {
407 return tb.getComplexType(
408 mapCIRType(complexTy.getElementType(), typeMapper, dl, modOp),
409 llvm::Align(dl.getTypeABIAlignment(type)));
411 .Case([&](cir::VectorType vecTy) {
414 return tb.getVectorType(
415 mapCIRType(vecTy.getElementType(), typeMapper, dl, modOp),
416 vecTy.getSize(), llvm::Align(dl.getTypeABIAlignment(type)));
418 .Case([&](cir::ArrayType arrTy) {
419 const llvm::abi::Type *elemAbi =
420 mapCIRType(arrTy.getElementType(), typeMapper, dl, modOp);
421 return tb.getArrayType(elemAbi, arrTy.getSize(),
422 dl.getTypeSizeInBits(type).getFixedValue());
425 llvm::abi::RecordFlags flags = llvm::abi::RecordFlags::None;
427 flags = flags | llvm::abi::RecordFlags::CanPassInRegisters;
428 llvm::TypeSize sizeBits = llvm::TypeSize::getFixed(
429 dl.getTypeSizeInBits(type).getFixedValue());
438 return tb.getRecordType(
439 {}, sizeBits, align, align,
440 llvm::abi::StructPacking::Default,
465 auto addAccessUnit = [&](cir::BitFieldType bfTy,
466 uint64_t unitOffsetBits) {
467 mlir::Type unitTy = bfTy.getStorageType();
469 unitTy ? dl.getTypeSizeInBits(unitTy).getFixedValue() : 0;
470 for (
auto [idx, decl] : llvm::enumerate(bfTy.getFields())) {
471 const uint64_t offsetBits =
472 unitOffsetBits + bfTy.getFieldBitOffset(idx);
473 const bool holdsUnit = idx == 0 && unitTy;
475 fields.push_back(llvm::abi::FieldInfo(
476 mapCIRType(unitTy, typeMapper, dl, modOp), offsetBits,
477 true, decl.getWidth(),
478 decl.getIsUnnamed()));
479 mlir::Type declaredTy = decl.getDeclaredType();
481 dl.getTypeSizeInBits(declaredTy).getFixedValue() > unitBits)
482 fields.push_back(llvm::abi::FieldInfo(
483 mapCIRType(declaredTy, typeMapper, dl, modOp), offsetBits,
484 true, holdsUnit ? 0 : decl.getWidth(),
485 holdsUnit || decl.getIsUnnamed()));
500 cir::RecordMemberKind::Pad) &&
501 "a union member cannot be marked pad");
502 for (mlir::Type variantTy : recTy.
getMembers()) {
503 if (
auto bfTy = dyn_cast<cir::BitFieldType>(variantTy)) {
507 addAccessUnit(bfTy, 0);
510 if (dl.getTypeSizeInBits(variantTy).getFixedValue() == 0 ||
513 fields.push_back(llvm::abi::FieldInfo(
514 mapCIRType(variantTy, typeMapper, dl, modOp)));
516 return tb.getUnionType(fields, sizeBits, align,
518 llvm::abi::StructPacking::Default, flags);
527 for (
auto [idx, fieldTy,
kind] :
529 if (
kind == cir::RecordMemberKind::Pad)
531 if (
auto bfTy = dyn_cast<cir::BitFieldType>(fieldTy)) {
537 bool isUnnamed =
kind == cir::RecordMemberKind::Empty;
538 uint64_t widthBits = dl.getTypeSizeInBits(fieldTy).getFixedValue();
539 if (isUnnamed && widthBits == 0)
542 "an empty-for-ABI member must not reach the classifier as an "
543 "unnamed bit-field");
544 fields.push_back(llvm::abi::FieldInfo(
547 isUnnamed, isUnnamed ? widthBits : 0,
551 return tb.getRecordType(
552 fields, sizeBits, align, align,
553 llvm::abi::StructPacking::Default,
556 .Default([](mlir::Type) ->
const llvm::abi::Type * {
558 "mapCIRType: type not pre-filtered by classifySignature");
591static std::optional<ArgClassification>
594 if (info.isDirect()) {
595 unsigned offset = info.getDirectOffset();
598 const llvm::abi::Type *coerceAbi = info.getCoerceToType();
600 auto recTy = dyn_cast_if_present<cir::RecordType>(origTy);
601 if (!recTy || !recTy.isStruct() || !info.getCanBeFlattened())
602 return ArgClassification::getDirect();
603 ArgClassification classified =
604 ArgClassification::getDirect(recTy, 0);
605 classified.canFlatten =
true;
608 bool isAggregate = isa_and_present<cir::RecordType, cir::ArrayType>(origTy);
611 bool comparesAgainstCoerce =
612 isa_and_present<cir::ComplexType, cir::VectorType>(origTy);
613 bool coerceIsRegisterTuple =
614 isa_and_present<llvm::abi::RecordType>(coerceAbi);
617 if (offset && coerceIsRegisterTuple)
621 auto origPtr = dyn_cast_if_present<cir::PointerType>(origTy);
622 const auto *coercePtr =
623 dyn_cast_if_present<llvm::abi::PointerType>(coerceAbi);
624 if (origPtr && coercePtr && !offset) {
627 auto origAS = dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
628 origPtr.getAddrSpace());
629 if (coercePtr->getAddrSpace() != (origAS ? origAS.getValue() : 0)) {
630 auto coercedPtr = cast<cir::PointerType>(
abiTypeToCIR(coerceAbi, ctx));
631 ArgClassification classified = ArgClassification::getDirect(
632 cir::PointerType::get(origPtr.getPointee(),
633 coercedPtr.getAddrSpace()),
635 classified.canFlatten = info.getCanBeFlattened();
641 auto origInt = dyn_cast_if_present<cir::IntType>(origTy);
642 const auto *coerceInt =
643 dyn_cast_if_present<llvm::abi::IntegerType>(coerceAbi);
644 bool coerceWidensScalar =
645 origInt && coerceInt &&
646 coerceInt->getSizeInBits().getFixedValue() > origInt.getWidth();
652 if (!offset && !isAggregate && !comparesAgainstCoerce &&
653 !coerceIsRegisterTuple && !coerceWidensScalar)
654 return ArgClassification::getDirect();
661 if (offset && coerceIsNatural)
665 if (comparesAgainstCoerce && coerceIsNatural)
666 return ArgClassification::getDirect();
667 ArgClassification classified =
668 ArgClassification::getDirect(coerced, offset);
669 classified.canFlatten = info.getCanBeFlattened();
674 if (info.isExtend()) {
675 if (isa_and_present<cir::BoolType>(origTy))
676 return ArgClassification::getExtend(
nullptr, info.isSignExt());
677 assert((!origTy || isa<cir::IntType>(origTy)) &&
678 "the x86_64 classifier only returns Extend for integers and bool");
679 mlir::Type extendedTy =
abiTypeToCIR(info.getCoerceToType(), ctx);
680 return ArgClassification::getExtend(extendedTy, info.isSignExt());
683 if (info.isIndirectAliased() ||
684 (info.isIndirect() && info.getIndirectAddrSpace() != 0))
686 if (info.isIndirect())
687 return ArgClassification::getIndirect(info.getIndirectAlign(),
688 info.getIndirectByVal(),
689 info.getIndirectAddrSpace());
692 assert(!info.isCoerceAndExpand() &&
693 "CoerceAndExpand is not expected for x86_64");
694 assert(info.isIgnore() &&
"Unexpected classification");
695 return ArgClassification::getIgnore();
703 if (!fnTy.isVarArg())
704 return llvm::abi::RequiredArgs::All;
705 return llvm::abi::RequiredArgs(fnTy.getNumInputs());
717std::optional<FunctionClassification> CIRABIClassifierCommon::classifySignature(
718 mlir::Type retCIR, mlir::TypeRange inputs, llvm::abi::RequiredArgs required,
719 const llvm::abi::TargetInfo &targetInfo, llvm::CallingConv::ID callConv,
720 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
721 assert(retCIR &&
"signature return type must be non-null");
722 assert((!required.allowsOptionalArgs() ||
723 required.getNumRequiredArgs() <= inputs.size()) &&
724 "declared parameters cannot outnumber the classified arguments");
725 MLIRContext *ctx =
modOp->getContext();
726 bool voidRet = isa<cir::VoidType>(retCIR);
728 auto reject = [&](mlir::Type t) ->
bool {
731 emitError() <<
"calling-convention lowering not yet implemented for type "
735 if (!voidRet && reject(retCIR))
737 for (mlir::Type a : inputs)
741 const llvm::abi::Type *retAbi =
742 voidRet ?
typeMapper.getTypeBuilder().getVoidType()
744 SmallVector<const llvm::abi::Type *> argAbi;
745 for (mlir::Type a : inputs)
748 std::unique_ptr<llvm::abi::FunctionInfo> fi =
749 llvm::abi::FunctionInfo::create(callConv, retAbi, argAbi, required);
750 targetInfo.computeInfo(*fi);
754 auto nyiCoercion = [&](mlir::Type t) {
755 emitError() <<
"calling-convention lowering not yet "
756 "implemented for the ABI coercion of type "
760 FunctionClassification fc;
761 fc.returnsVoid = voidRet;
762 mlir::Type origRet = voidRet ? mlir::Type() : retCIR;
763 std::optional<ArgClassification> retAc =
769 fc.returnInfo = *retAc;
770 for (
unsigned i = 0, e = fi->arg_size(); i < e; ++i) {
771 mlir::Type origArg = i < inputs.size() ? inputs[i] : mlir::Type();
772 const llvm::abi::ArgInfo &argInfo = fi->getArgInfo(i).Info;
773 std::optional<ArgClassification> ac =
776 nyiCoercion(origArg);
779 ac->neededIntRegs = argInfo.getNeededIntRegs();
780 ac->neededSseRegs = argInfo.getNeededSseRegs();
781 fc.argInfos.push_back(*ac);
789 llvm::abi::X86AVXABILevel base) {
794 auto features = func->getAttrOfType<mlir::StringAttr>(
"cir.target-features");
801 for (llvm::StringRef feature : llvm::split(features.getValue(),
',')) {
802 if (!feature.consume_front(
"+"))
804 if (feature ==
"avx512f")
805 return std::max(base, llvm::abi::X86AVXABILevel::AVX512);
806 avx |= feature ==
"avx";
808 return avx ? std::max(base, llvm::abi::X86AVXABILevel::AVX) : base;
814std::optional<FunctionClassification>
816 cir::FuncType fnTy = func.getFunctionType();
817 return classifySignature(fnTy.getReturnType(), fnTy.getInputs(),
820 [&]() { return func.emitOpError(); });
827 mlir::Type ty,
const llvm::abi::TargetInfo &targetInfo,
828 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
829 MLIRContext *ctx =
modOp->getContext();
830 std::optional<FunctionClassification> fc = classifySignature(
831 cir::VoidType::get(ctx), mlir::TypeRange(ty), llvm::abi::RequiredArgs(0),
832 targetInfo, llvm::CallingConv::C, emitError);
835 return fc->argInfos[0];
845std::optional<FunctionClassification>
847 cir::CIRCallOpInterface call, cir::FuncType calleeTy,
848 const llvm::abi::TargetInfo &targetInfo, llvm::CallingConv::ID callConv) {
849 assert(calleeTy.isVarArg() &&
850 "only a variadic callee can take more operands than it declares");
851 Operation *op = call.getOperation();
852 return classifySignature(calleeTy.getReturnType(),
853 call.getArgOperands().getTypes(),
855 [&]() {
return op->emitOpError(); });
861 if (fc.returnInfo.kind == ArgKind::Indirect)
863 return llvm::any_of(fc.argInfos, [](
const ArgClassification &ac) {
864 return ac.kind == ArgKind::Indirect;
872 cir::MemoryEffectsAttr effects = op.getMemoryEffectsAttr();
875 op.setMemoryEffectsAttr(cir::MemoryEffectsAttr::get(
876 effects.getContext(), effects.getOther(), cir::ModRefInfo::ModRef,
877 effects.getInaccessibleMem(), effects.getErrnoMem(),
878 effects.getTargetMem0(), effects.getTargetMem1()));
889 const FunctionClassification &callFc) {
890 if (callFc.argInfos.size() < calleeFc.argInfos.size())
892 return calleeFc.returnInfo == callFc.returnInfo &&
893 std::equal(calleeFc.argInfos.begin(), calleeFc.argInfos.end(),
894 callFc.argInfos.begin());
900struct CallConvLoweringPass
901 :
public impl::CallConvLoweringBase<CallConvLoweringPass> {
902 using CallConvLoweringBase::CallConvLoweringBase;
904 CallConvLoweringPass(
const CallConvLoweringOptions &options,
905 const llvm::abi::X86ABICompatInfo &x86AbiCompat)
906 : CallConvLoweringBase(options), x86AbiCompat(x86AbiCompat) {}
908 void runOnOperation()
override;
914 llvm::abi::X86ABICompatInfo x86AbiCompat;
925std::optional<FunctionClassification>
927 mlir::Type returnType) {
929 fc->returnsVoid = mlir::isa<cir::VoidType>(returnType);
937std::optional<FunctionClassification>
940 StringRef classificationAttrName) {
941 ArrayRef<Type> argTypes = func.getFunctionType().getInputs();
942 Type returnType = func.getFunctionType().getReturnType();
944 if (!classificationAttrName.empty()) {
945 auto attr = func->getAttrOfType<DictionaryAttr>(classificationAttrName);
948 <<
"missing classification attribute '" << classificationAttrName
949 <<
"' (CallConvLowering driver mode 'classification-attr')";
953 attr, [&]() {
return func.emitOpError(); }),
960 "classifyFunction only handles the test target");
968static std::unique_ptr<CIRABIClassifier>
970 StringRef classificationAttrName,
const DataLayout &dl,
972 if (!classificationAttrName.empty())
985 llvm_unreachable(
"an unset driver mode is rejected before this point");
995cir::FuncOp lookupCallee(Operation *callOp, SymbolTable &symbolTable) {
996 FlatSymbolRefAttr callee;
997 if (
auto call = dyn_cast<cir::CallOp>(callOp))
998 callee = call.getCalleeAttr();
999 else if (
auto tryCall = dyn_cast<cir::TryCallOp>(callOp))
1000 callee = tryCall.getCalleeAttr();
1005 return symbolTable.lookup<cir::FuncOp>(callee.getValue());
1008void CallConvLoweringPass::runOnOperation() {
1009 ModuleOp moduleOp = getOperation();
1010 MLIRContext *ctx = &getContext();
1013 bool haveAttr = !classificationAttr.empty();
1014 if (haveTarget == haveAttr) {
1015 moduleOp.emitOpError() <<
"CallConvLowering requires exactly one of "
1016 "'target' or 'classification-attr' pass options";
1017 signalPassFailure();
1021 if (!moduleOp->hasAttr(DLTIDialect::kDataLayoutAttrName)) {
1022 moduleOp.emitOpError()
1023 <<
"CallConvLowering requires a DataLayout (dlti.dl_spec attribute "
1025 signalPassFailure();
1029 DataLayout dl(moduleOp);
1035 llvm::scope_exit drainParamSlots(
1036 [&] { rewriteCtx.finalizeParameterSlots(); });
1037 SymbolTable symbolTable(moduleOp);
1039 cir::ABIClassifierOptions classifierOptions;
1044 target, classificationAttr, dl, moduleOp, classifierOptions);
1049 llvm::MapVector<cir::FuncOp, FunctionClassification> classifications;
1050 bool anyFailed =
false;
1051 moduleOp.walk([&](cir::FuncOp f) {
1056 cir::FuncType fnTy = f.getFunctionType();
1057 if (f.isDeclaration() &&
1061 std::optional<FunctionClassification> fc = classifier->classifyFunction(f);
1066 classifications.insert({f, std::move(*fc)});
1069 signalPassFailure();
1082 llvm::DenseMap<cir::FuncOp, SmallVector<Operation *>> callers;
1086 llvm::DenseMap<Operation *, FunctionClassification> variadicCallSites;
1087 moduleOp.walk([&](Operation *op) {
1088 auto call = dyn_cast<cir::CIRCallOpInterface>(op);
1091 cir::FuncOp callee = lookupCallee(op, symbolTable);
1094 callers[callee].push_back(op);
1096 cir::FuncType calleeTy = callee.getFunctionType();
1097 if (call.getNumArgOperands() <= calleeTy.getNumInputs())
1103 if (!calleeTy.isVarArg()) {
1104 op->emitOpError() <<
"extra arguments to a callee without a prototype "
1105 "not yet implemented in CallConvLowering";
1109 std::optional<FunctionClassification> fc =
1110 classifier->classifyVariadicCall(call, callee);
1115 variadicCallSites.insert({op, std::move(*fc)});
1118 signalPassFailure();
1128 llvm::DenseMap<cir::FuncOp, SmallVector<cir::GetGlobalOp>> addressTakers;
1129 moduleOp.walk([&](cir::GetGlobalOp getGlobal) {
1130 auto ptrTy = cast<cir::PointerType>(getGlobal.getAddr().getType());
1131 if (!isa<cir::FuncType>(ptrTy.getPointee()))
1136 auto callee = cast<cir::FuncOp>(symbolTable.lookup(getGlobal.getName()));
1137 addressTakers[callee].push_back(getGlobal);
1145 for (
auto &kv : classifications) {
1146 if (failed(rewriteCtx.prepareNonByvalParameters(kv.first, kv.second))) {
1147 signalPassFailure();
1156 for (
auto &kv : classifications) {
1157 cir::FuncOp func = kv.first;
1173 OpBuilder builder(ctx);
1174 for (
auto &kv : classifications) {
1175 cir::FuncOp func = kv.first;
1176 const FunctionClassification &fc = kv.second;
1177 if (failed(rewriteCtx.rewriteFunctionDefinition(func, fc, builder))) {
1178 signalPassFailure();
1181 for (Operation *callOp : callers.lookup(func)) {
1182 const FunctionClassification *callFc = &fc;
1183 if (
auto it = variadicCallSites.find(callOp);
1184 it != variadicCallSites.end()) {
1185 callFc = &it->second;
1187 "a call site's declared parameters must be classified the same "
1188 "way as the callee's");
1192 if (failed(rewriteCtx.rewriteCallSite(callOp, *callFc, builder))) {
1193 signalPassFailure();
1197 for (cir::GetGlobalOp addrOp : addressTakers.lookup(func))
1198 rewriteCtx.rewriteFunctionAddress(addrOp, func, builder);
1207 SmallVector<cir::CIRCallOpInterface> indirectCalls;
1208 moduleOp.walk([&](cir::CIRCallOpInterface c) {
1210 indirectCalls.push_back(c);
1212 for (cir::CIRCallOpInterface c : indirectCalls) {
1213 std::optional<FunctionClassification> fc =
1214 classifier->classifyIndirectCall(c);
1216 signalPassFailure();
1221 if (failed(rewriteCtx.rewriteCallSite(c.getOperation(), *fc, builder))) {
1222 signalPassFailure();
1229 SmallVector<cir::VAArgOp> vaArgs;
1230 moduleOp.walk([&](cir::VAArgOp v) { vaArgs.push_back(v); });
1231 for (cir::VAArgOp v : vaArgs) {
1232 std::optional<ArgClassification> ac = classifier->classifyVAArg(v);
1234 signalPassFailure();
1237 if (failed(rewriteCtx.rewriteVAArg(v.getOperation(), *ac, builder))) {
1238 signalPassFailure();
1247 return std::make_unique<CallConvLoweringPass>();
1253 const llvm::abi::X86ABICompatInfo &x86AbiCompat) {
1254 CallConvLoweringOptions options;
1255 options.target = target;
1256 options.x86AvxAbiLevel = x86AvxAbiLevel;
1258 return std::make_unique<CallConvLoweringPass>(options, x86AbiCompat);
static bool hasIndirectSlot(const FunctionClassification &fc)
Whether fc gives the callee access to memory through a pointer the ABI introduced: an sret slot for a...
static bool classifiesSamePrefix(const FunctionClassification &calleeFc, const FunctionClassification &callFc)
Whether callFc classifies a call's leading arguments and its return exactly as calleeFc classifies th...
static bool memberIsEmptyRecord(mlir::Type ty)
Whether a member is an empty record, looking through arrays, since an array of empty records supplies...
static llvm::Align recordDeclaredAlign(ModuleOp modOp, cir::RecordType recTy, const DataLayout &dl)
A record's declared alignment, which the ABI uses for the byval and sret alignment of an indirect arg...
static bool recordCanPassInRegs(ModuleOp modOp, cir::RecordType recTy)
Whether a struct's declared argument-passing kind (from the module's record-layout metadata) allows i...
static const llvm::abi::Type * mapCIRType(mlir::Type type, mlir::abi::ABITypeMapper &typeMapper, const DataLayout &dl, ModuleOp modOp)
Map a CIR type to an llvm::abi::Type.
static std::optional< ArgClassification > convertABIArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx, mlir::Type origTy)
Convert an llvm::abi::ArgInfo into the ArgClassification consumed by CIRABIRewriteContext.
static mlir::Type unwrapLongDoubleVectorElement(mlir::Type ty)
Returns ty with a LongDoubleType vector element replaced by its underlying format,...
static bool mayReachSseUp(mlir::Type ty, const DataLayout &dl)
Whether the classifier could give this type the SSEUP class, looking through arrays and records at th...
static bool hasIncompleteRecordByValue(mlir::Type ty)
Whether ty, or an aggregate member/element reached by value (never through a pointer),...
static bool sseUpCoerceSizeUnsupported(uint64_t recordBits, llvm::ArrayRef< mlir::Type > members, const DataLayout &dl)
Whether the record's size has no SSEUP coerce.
static void widenForArgMemory(OpTy op)
Record on op that the memory its pointer arguments address may be read and written.
static bool isSupportedType(mlir::Type ty, const DataLayout &dl)
The CIR types the x86_64 bridge handles.
static mlir::Type abiTypeToCIR(const llvm::abi::Type *ty, MLIRContext *ctx)
Convert an llvm::abi::Type coercion type back to a scalar CIR type.
static std::unique_ptr< CIRABIClassifier > createABIClassifier(cir::CallConvTarget target, StringRef classificationAttrName, const DataLayout &dl, ModuleOp modOp, const ABIClassifierOptions &options)
Build the classifier the pass options select.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
std::optional< mlir::abi::FunctionClassification > classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp callee) override
The call is classified at the callee's features, not the caller's, because the pass rewrites the defi...
const mlir::DataLayout & dl
std::optional< mlir::abi::FunctionClassification > classifyFunction(cir::FuncOp func) override
Classify a cir.func using the LLVM ABI library.
virtual const llvm::abi::TargetInfo & getTargetInfo(cir::FuncOp featureSource)=0
The library classifier for a function whose recorded target features may refine the ABI rules.
mlir::abi::ABITypeMapper typeMapper
std::optional< mlir::abi::ArgClassification > classifyVarArgType(mlir::Type ty, const llvm::abi::TargetInfo &targetInfo, llvm::function_ref< mlir::InFlightDiagnostic()> emitError)
Classify ty, the type fetched by a cir.va_arg, as an unnamed argument with every argument register fr...
CIR-specific implementation of mlir::abi::ABIRewriteContext.
C++ view class that accepts both !cir.struct and !cir.union types.
bool isEmptyForABI() const
Whether no member holds data.
llvm::ArrayRef< mlir::Type > getMembers() const
static llvm::SmallVector< RecordMemberKind > getAllDataKinds(llvm::ArrayRef< mlir::Type > members)
One Data kind per member.
mlir::StringAttr getName() const
llvm::ArrayRef< RecordMemberKind > getMemberKinds() const
uint64_t getElementOffset(const mlir::DataLayout &dataLayout, unsigned idx) const
RecordLayoutAttr tryGetRecordLayout(mlir::ModuleOp mod, mlir::StringAttr name)
Same lookup as getRecordLayout, but returns a null attribute instead of asserting when the record has...
std::optional< mlir::abi::FunctionClassification > withReturnVoidness(std::optional< mlir::abi::FunctionClassification > fc, mlir::Type returnType)
Record on fc whether returnType is CIR's void.
static bool allowsX86TargetAttrAvx(const llvm::Triple &triple, clang::LangOptions::ClangABI compat)
Whether __attribute__((target(...))) on a function may raise its AVX ABI level above the command line...
std::unique_ptr< CIRABIClassifier > createAMDGPUABIClassifier(const mlir::DataLayout &dl, mlir::ModuleOp modOp)
The AMDGPU classifier.
llvm::abi::X86AVXABILevel funcAvxLevel(cir::FuncOp func, llvm::abi::X86AVXABILevel base)
The AVX level to classify func at: base, raised if the function's own recorded feature list enables a...
std::unique_ptr< CIRABIClassifier > createX86_64ABIClassifier(const mlir::DataLayout &dl, mlir::ModuleOp modOp, const ABIClassifierOptions &options)
The x86_64 System V classifier.
llvm::CallingConv::ID convertCallingConv(cir::CallingConv cc)
Map a CIR calling convention to the llvm::CallingConv the ABI classifier uses.
cir::FPTypeInterface getFloatingPointType(const llvm::fltSemantics &sem, mlir::MLIRContext *ctx)
Returns the CIR floating-point type for the given semantics, or a null type if CIR has no type for it...
std::optional< mlir::abi::FunctionClassification > classifyFunction(cir::FuncOp func, const mlir::DataLayout &dl, cir::CallConvTarget target, llvm::StringRef classificationAttrName)
Classify func with the test target, or from the attribute named classificationAttrName when that is n...
std::unique_ptr< CIRABIClassifier > createInjectedABIClassifier(const mlir::DataLayout &dl, llvm::StringRef attrName)
A classifier that reads each function's classification from the DictionaryAttr named attrName.
std::unique_ptr< CIRABIClassifier > createTestTargetABIClassifier(const mlir::DataLayout &dl)
The MLIR test ABI target's classifier, whose predictable rules approximate x86_64 SysV.
CallConvTarget
The ABI target whose calling-convention rules drive CallConvLowering.
llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy)
Where fnTy's declared parameters end and its ellipsis arguments begin.
const internal::VariadicAllOfMatcher< Attr > attr
std::unique_ptr< Pass > createCallConvLoweringPass()
The target-specific settings a classifier needs beyond what it can read from the module.
bool allowsX86TargetAttrAvx
Whether a function's own recorded target features may raise its x86_64 AVX level above x86AvxAbiLevel...
llvm::abi::X86ABICompatInfo x86AbiCompat
The x86_64 flags whose value depends on the target and the requested ABI compatibility version.
llvm::abi::X86AVXABILevel x86AvxAbiLevel
The AVX level the x86_64 classifier sizes a native vector at.
static bool addressSpace()
static bool opFuncMultiVersioning()