36#include "mlir/ABI/ABIRewriteContext.h"
37#include "mlir/ABI/ABITypeMapper.h"
38#include "mlir/ABI/Targets/Test/TestTarget.h"
39#include "mlir/Dialect/DLTI/DLTI.h"
40#include "mlir/IR/Builders.h"
41#include "mlir/IR/BuiltinOps.h"
42#include "mlir/IR/SymbolTable.h"
43#include "mlir/Interfaces/DataLayoutInterfaces.h"
44#include "mlir/Pass/Pass.h"
48#include "llvm/ABI/FunctionInfo.h"
49#include "llvm/ABI/TargetInfo.h"
50#include "llvm/ABI/Types.h"
51#include "llvm/ADT/ScopeExit.h"
52#include "llvm/ADT/StringExtras.h"
53#include "llvm/ADT/TypeSwitch.h"
54#include "llvm/IR/CallingConv.h"
55#include "llvm/Support/MathExtras.h"
61using namespace mlir::abi;
65#define GEN_PASS_DEF_CALLCONVLOWERING
66#include "clang/CIR/Dialect/Passes.h.inc"
89 return layout.getArgPassingKind() == cir::ArgPassingKind::CanPassInRegs;
94static bool mayReachSseUp(mlir::Type ty,
const DataLayout &dl) {
96 if (isa<cir::VectorType>(ty))
97 return llvm::PowerOf2Ceil(dl.getTypeSizeInBits(ty).getFixedValue()) >= 128;
98 if (
auto fpTy = dyn_cast<cir::FPTypeInterface>(ty))
99 return &fpTy.getFloatSemantics() == &llvm::APFloat::IEEEquad();
100 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
101 return mayReachSseUp(arrTy.getElementType(), dl);
102 if (
auto recTy = dyn_cast<cir::RecordType>(ty))
105 [&](mlir::Type m) { return mayReachSseUp(m, dl); });
108 assert((isa<cir::IntType, cir::BoolType, cir::PointerType, cir::VPtrType,
109 cir::VoidType, cir::ComplexType, cir::BitFieldType>(ty)) &&
110 "unhandled type in the SSEUP walk");
117static bool sseUpCoerceSizeUnsupported(uint64_t recordBits,
119 const DataLayout &dl) {
120 if (recordBits == 128 || recordBits == 256 || recordBits == 512)
122 if (recordBits < 128 || recordBits > 512)
124 return llvm::any_of(members,
125 [&](mlir::Type m) {
return mayReachSseUp(m, dl); });
130static bool memberIsEmptyRecord(mlir::Type ty) {
131 while (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
132 ty = arrTy.getElementType();
133 auto recTy = dyn_cast<cir::RecordType>(ty);
143static llvm::Align recordDeclaredAlign(ModuleOp modOp,
cir::RecordType recTy,
144 const DataLayout &dl) {
147 return llvm::Align(dl.getTypeABIAlignment(recTy));
148 return llvm::Align(layout.getRecordAlign());
154static bool hasIncompleteRecordByValue(mlir::Type ty) {
155 if (
auto recTy = dyn_cast<cir::RecordType>(ty))
157 llvm::any_of(recTy.
getMembers(), hasIncompleteRecordByValue);
158 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
159 return hasIncompleteRecordByValue(arrTy.getElementType());
165static bool isX87DoubleExtended(mlir::Type ty) {
166 auto fpTy = dyn_cast<cir::FPTypeInterface>(ty);
168 &fpTy.getFloatSemantics() == &llvm::APFloat::x87DoubleExtended();
173static bool holdsX87DoubleExtended(mlir::Type ty) {
174 if (isa<cir::FPTypeInterface>(ty))
175 return isX87DoubleExtended(ty);
176 if (
auto complexTy = dyn_cast<cir::ComplexType>(ty))
177 return isX87DoubleExtended(complexTy.getElementType());
178 if (
auto vecTy = dyn_cast<cir::VectorType>(ty))
179 return isX87DoubleExtended(vecTy.getElementType());
180 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
181 return arrTy.getSize() && holdsX87DoubleExtended(arrTy.getElementType());
182 if (
auto recTy = dyn_cast<cir::RecordType>(ty))
183 return llvm::any_of(recTy.
getMembers(), holdsX87DoubleExtended);
191static uint64_t getDataExtentInBytes(mlir::Type ty,
const DataLayout &dl) {
192 if (
auto recTy = dyn_cast<cir::RecordType>(ty)) {
194 for (
auto [idx, memberTy,
kind] :
196 if (
kind == cir::RecordMemberKind::Pad)
199 getDataExtentInBytes(memberTy, dl));
203 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty)) {
204 if (!arrTy.getSize())
206 mlir::Type elemTy = arrTy.getElementType();
207 return (arrTy.getSize() - 1) * dl.getTypeSize(elemTy).getFixedValue() +
208 getDataExtentInBytes(elemTy, dl);
210 return dl.getTypeSize(ty).getFixedValue();
220static bool isSupportedType(mlir::Type ty,
const DataLayout &dl) {
224 if (
auto ptrTy = dyn_cast<cir::PointerType>(ty))
225 return !ptrTy.getAddrSpace() ||
226 mlir::isa<cir::TargetAddressSpaceAttr>(ptrTy.getAddrSpace());
230 if (isa<cir::VPtrType>(ty)) {
234 if (isa<cir::VoidType, cir::BoolType>(ty))
238 if (isa<cir::FPTypeInterface>(ty))
240 if (
auto intTy = dyn_cast<cir::IntType>(ty)) {
248 if (intTy.getIsBitInt())
250 return intTy.getWidth() <= 64 || intTy.getWidth() == 128;
252 if (
auto complexTy = dyn_cast<cir::ComplexType>(ty))
253 return isSupportedType(complexTy.getElementType(), dl);
254 if (
auto vecTy = dyn_cast<cir::VectorType>(ty)) {
257 if (vecTy.getIsScalable())
262 mlir::Type elemTy = vecTy.getElementType();
263 if (
auto elemInt = dyn_cast<cir::IntType>(elemTy)) {
264 if (elemInt.getWidth() % 8)
266 }
else if (!isa<cir::FPTypeInterface, cir::BoolType>(elemTy)) {
269 return isSupportedType(elemTy, dl);
271 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
272 return isSupportedType(arrTy.getElementType(), dl);
276 if (
auto bfTy = dyn_cast<cir::BitFieldType>(ty)) {
277 if (mlir::Type storageTy = bfTy.getStorageType())
278 if (!isSupportedType(storageTy, dl))
280 return llvm::all_of(bfTy.getFields(), [&](cir::BitFieldDeclAttr decl) {
281 return isSupportedType(decl.getDeclaredType(), dl);
284 if (
auto recTy = dyn_cast<cir::RecordType>(ty)) {
291 [&](mlir::Type m) { return isSupportedType(m, dl); }))
295 uint64_t recordBits = dl.getTypeSizeInBits(recTy).getFixedValue();
298 if (sseUpCoerceSizeUnsupported(recordBits, members, dl))
303 if (members.empty() && recordBits > 128)
313 if (members.size() > 1 && llvm::any_of(members, holdsX87DoubleExtended)) {
314 uint64_t x87StoreBytes = llvm::APFloat::semanticsSizeInBits(
315 llvm::APFloat::x87DoubleExtended()) /
317 if (!isX87DoubleExtended(
318 mlir::cast<cir::UnionType>(recTy).getUnionStorageType(dl)) ||
319 !llvm::all_of(members, [&](mlir::Type m) {
320 return isX87DoubleExtended(m) ||
321 getDataExtentInBytes(m, dl) <= x87StoreBytes;
328 if (llvm::any_of(members, [&](mlir::Type m) {
329 auto bfTy = dyn_cast<cir::BitFieldType>(m);
330 if (!bfTy || dl.getTypeSizeInBits(bfTy).getFixedValue() <= 64)
332 return llvm::any_of(bfTy.getFields(), [](cir::BitFieldDeclAttr d) {
333 auto intTy = dyn_cast<cir::IntType>(d.getDeclaredType());
334 return intTy && intTy.getIsBitInt();
347 for (
auto [idx, memberTy,
kind] :
349 if (
kind != cir::RecordMemberKind::Empty)
351 if (dl.getTypeSizeInBits(memberTy).getFixedValue()) {
352 if (memberIsEmptyRecord(memberTy))
355 dl.getTypeABIAlignment(memberTy)) {
366static mlir::Type abiTypeToCIR(
const llvm::abi::Type *ty, MLIRContext *ctx) {
369 return llvm::TypeSwitch<const llvm::abi::Type *, mlir::Type>(ty)
371 [&](
const llvm::abi::VoidType *) {
return cir::VoidType::get(ctx); })
372 .Case([&](
const llvm::abi::IntegerType *intTy) -> mlir::Type {
375 return cir::BoolType::get(ctx);
376 return cir::IntType::get(ctx, intTy->getSizeInBits().getFixedValue(),
377 intTy->isSigned(), intTy->isBitInt());
379 .Case([&](
const llvm::abi::FloatType *fltTy) {
382 .Case([&](
const llvm::abi::PointerType *) {
383 return cir::PointerType::get(cir::VoidType::get(ctx));
385 .Case([&](
const llvm::abi::VectorType *vecTy) -> mlir::Type {
386 mlir::Type elemCIR = abiTypeToCIR(vecTy->getElementType(), ctx);
389 return cir::VectorType::get(elemCIR,
390 vecTy->getNumElements().getFixedValue());
392 .Case([&](
const llvm::abi::RecordType *recTy) -> mlir::Type {
394 fieldTypes.reserve(recTy->getFields().size());
395 for (
const auto &field : recTy->getFields()) {
396 mlir::Type fieldCIR = abiTypeToCIR(field.FieldType, ctx);
399 fieldTypes.push_back(fieldCIR);
402 return cir::StructType::get(
403 ctx, fieldTypes,
false,
406 .
Default([](
const llvm::abi::Type *) -> mlir::Type {
return nullptr; });
412static mlir::Type unwrapLongDoubleVectorElement(mlir::Type ty) {
413 if (
auto vecTy = dyn_cast<cir::VectorType>(ty)) {
414 if (
auto longDoubleTy =
415 dyn_cast<cir::LongDoubleType>(vecTy.getElementType()))
416 return cir::VectorType::get(longDoubleTy.getUnderlying(), vecTy.getSize(),
417 vecTy.getIsScalable());
425static const llvm::abi::Type *mapCIRType(mlir::Type type,
426 mlir::abi::ABITypeMapper &typeMapper,
427 const DataLayout &dl, ModuleOp modOp) {
428 llvm::abi::TypeBuilder &tb = typeMapper.getTypeBuilder();
429 return llvm::TypeSwitch<mlir::Type, const llvm::abi::Type *>(type)
430 .Case([&](cir::IntType intTy) {
431 return tb.getIntegerType(intTy.getWidth(),
432 llvm::Align(dl.getTypeABIAlignment(type)),
433 intTy.isSigned(), intTy.getIsBitInt());
435 .Case([&](cir::PointerType ptrTy) {
436 unsigned addrSpace = 0;
437 if (
auto targetAsAttr =
438 dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
439 ptrTy.getAddrSpace()))
440 addrSpace = targetAsAttr.getValue();
441 return tb.getPointerType(dl.getTypeSizeInBits(type),
442 llvm::Align(dl.getTypeABIAlignment(type)),
445 .Case([&](cir::VPtrType) {
449 return tb.getPointerType(dl.getTypeSizeInBits(type),
450 llvm::Align(dl.getTypeABIAlignment(type)));
452 .Case([&](cir::BoolType) {
455 return tb.getIntegerType(1, llvm::Align(dl.getTypeABIAlignment(type)),
458 .Case([&](cir::VoidType) {
return tb.getVoidType(); })
459 .Case([&](cir::FPTypeInterface fpTy) {
462 return tb.getFloatType(fpTy.getFloatSemantics(),
463 llvm::Align(dl.getTypeABIAlignment(type)));
465 .Case([&](cir::ComplexType complexTy) {
466 return tb.getComplexType(
467 mapCIRType(complexTy.getElementType(), typeMapper, dl, modOp),
468 llvm::Align(dl.getTypeABIAlignment(type)));
470 .Case([&](cir::VectorType vecTy) {
473 return tb.getVectorType(
474 mapCIRType(vecTy.getElementType(), typeMapper, dl, modOp),
475 llvm::ElementCount::getFixed(vecTy.getSize()),
476 llvm::Align(dl.getTypeABIAlignment(type)));
478 .Case([&](cir::ArrayType arrTy) {
479 const llvm::abi::Type *elemAbi =
480 mapCIRType(arrTy.getElementType(), typeMapper, dl, modOp);
481 return tb.getArrayType(elemAbi, arrTy.getSize(),
482 dl.getTypeSizeInBits(type).getFixedValue());
485 llvm::abi::RecordFlags flags = llvm::abi::RecordFlags::None;
486 if (recordCanPassInRegs(modOp, recTy))
487 flags = flags | llvm::abi::RecordFlags::CanPassInRegisters;
488 llvm::TypeSize sizeBits = llvm::TypeSize::getFixed(
489 dl.getTypeSizeInBits(type).getFixedValue());
490 llvm::Align
align = recordDeclaredAlign(modOp, recTy, dl);
498 return tb.getRecordType(
500 llvm::abi::StructPacking::Default,
525 auto addAccessUnit = [&](cir::BitFieldType bfTy,
526 uint64_t unitOffsetBits) {
527 mlir::Type unitTy = bfTy.getStorageType();
529 unitTy ? dl.getTypeSizeInBits(unitTy).getFixedValue() : 0;
530 for (
auto [idx, decl] : llvm::enumerate(bfTy.getFields())) {
531 const uint64_t offsetBits =
532 unitOffsetBits + bfTy.getFieldBitOffset(idx);
533 const bool holdsUnit = idx == 0 && unitTy;
535 fields.push_back(llvm::abi::FieldInfo(
536 mapCIRType(unitTy, typeMapper, dl, modOp), offsetBits,
537 true,
decl.getWidth(),
538 decl.getIsUnnamed()));
539 mlir::Type declaredTy =
decl.getDeclaredType();
541 dl.getTypeSizeInBits(declaredTy).getFixedValue() > unitBits)
542 fields.push_back(llvm::abi::FieldInfo(
543 mapCIRType(declaredTy, typeMapper, dl, modOp), offsetBits,
544 true, holdsUnit ? 0 :
decl.getWidth(),
545 holdsUnit ||
decl.getIsUnnamed()));
560 cir::RecordMemberKind::Pad) &&
561 "a union member cannot be marked pad");
562 for (mlir::Type variantTy : recTy.
getMembers()) {
563 if (
auto bfTy = dyn_cast<cir::BitFieldType>(variantTy)) {
567 addAccessUnit(bfTy, 0);
570 if (dl.getTypeSizeInBits(variantTy).getFixedValue() == 0 ||
571 memberIsEmptyRecord(variantTy))
573 fields.push_back(llvm::abi::FieldInfo(
574 mapCIRType(variantTy, typeMapper, dl, modOp)));
576 return tb.getUnionType(fields, sizeBits, align,
578 llvm::abi::StructPacking::Default, flags);
587 for (
auto [idx, fieldTy,
kind] :
589 if (
kind == cir::RecordMemberKind::Pad)
591 if (
auto bfTy = dyn_cast<cir::BitFieldType>(fieldTy)) {
597 bool isUnnamed =
kind == cir::RecordMemberKind::Empty;
598 uint64_t widthBits = dl.getTypeSizeInBits(fieldTy).getFixedValue();
599 if (isUnnamed && widthBits == 0)
601 assert((!isUnnamed || !memberIsEmptyRecord(fieldTy)) &&
602 "an empty-for-ABI member must not reach the classifier as an "
603 "unnamed bit-field");
604 fields.push_back(llvm::abi::FieldInfo(
605 mapCIRType(fieldTy, typeMapper, dl, modOp),
607 isUnnamed, isUnnamed ? widthBits : 0,
611 return tb.getRecordType(
612 fields, sizeBits, align, align,
613 llvm::abi::StructPacking::Default,
616 .
Default([](mlir::Type) ->
const llvm::abi::Type * {
618 "mapCIRType: type not pre-filtered by classifyX86_64Function");
648static std::optional<ArgClassification>
649convertABIArgInfo(
const llvm::abi::ArgInfo &info, MLIRContext *ctx,
651 if (
info.isDirect()) {
652 unsigned offset =
info.getDirectOffset();
655 const llvm::abi::Type *coerceAbi =
info.getCoerceToType();
656 bool isAggregate = isa_and_present<cir::RecordType, cir::ArrayType>(origTy);
659 bool comparesAgainstCoerce =
660 coerceAbi && isa_and_present<cir::ComplexType, cir::VectorType>(origTy);
661 bool coerceIsRegisterTuple =
662 isa_and_present<llvm::abi::RecordType>(coerceAbi);
665 if (offset && coerceIsRegisterTuple)
669 auto origInt = dyn_cast_if_present<cir::IntType>(origTy);
670 const auto *coerceInt =
671 dyn_cast_if_present<llvm::abi::IntegerType>(coerceAbi);
672 bool coerceWidensScalar =
673 origInt && coerceInt &&
674 coerceInt->getSizeInBits().getFixedValue() > origInt.getWidth();
680 if (!offset && !isAggregate && !comparesAgainstCoerce &&
681 !coerceIsRegisterTuple && !coerceWidensScalar)
682 return ArgClassification::getDirect();
683 mlir::Type coerced = abiTypeToCIR(coerceAbi, ctx);
686 bool coerceIsNatural = coerced == unwrapLongDoubleVectorElement(origTy);
689 if (offset && coerceIsNatural)
693 if (comparesAgainstCoerce && coerceIsNatural)
694 return ArgClassification::getDirect();
695 ArgClassification classified =
696 ArgClassification::getDirect(coerced, offset);
697 classified.canFlatten =
info.getCanBeFlattened();
702 if (
info.isExtend()) {
703 if (isa_and_present<cir::BoolType>(origTy))
704 return ArgClassification::getExtend(
nullptr,
info.isSignExt());
705 assert((!origTy || isa<cir::IntType>(origTy)) &&
706 "the x86_64 classifier only returns Extend for integers and bool");
707 mlir::Type extendedTy = abiTypeToCIR(
info.getCoerceToType(), ctx);
708 return ArgClassification::getExtend(extendedTy,
info.isSignExt());
710 if (
info.isIndirect())
711 return ArgClassification::getIndirect(
info.getIndirectAlign(),
712 info.getIndirectByVal());
715 assert(!
info.isCoerceAndExpand() &&
716 "CoerceAndExpand is not expected for x86_64");
717 assert(
info.isIgnore() &&
"Unexpected classification");
718 return ArgClassification::getIgnore();
725static llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy) {
726 if (!fnTy.isVarArg())
727 return llvm::abi::RequiredArgs::All;
728 return llvm::abi::RequiredArgs(fnTy.getNumInputs());
739static std::optional<FunctionClassification> classifyX86_64Signature(
740 mlir::Type retCIR, mlir::TypeRange inputs, llvm::abi::RequiredArgs required,
741 MLIRContext *ctx,
const DataLayout &dl,
742 mlir::abi::ABITypeMapper &typeMapper,
743 const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp,
744 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
745 assert(retCIR &&
"signature return type must be non-null");
746 assert((!required.allowsOptionalArgs() ||
747 required.getNumRequiredArgs() <= inputs.size()) &&
748 "declared parameters cannot outnumber the classified arguments");
749 bool voidRet = isa<cir::VoidType>(retCIR);
751 auto reject = [&](mlir::Type t) ->
bool {
752 if (isSupportedType(t, dl))
755 <<
"x86_64 calling-convention lowering not yet implemented for type "
759 if (!voidRet && reject(retCIR))
761 for (mlir::Type a : inputs)
765 const llvm::abi::Type *retAbi =
766 voidRet ? typeMapper.getTypeBuilder().getVoidType()
767 : mapCIRType(retCIR, typeMapper, dl, modOp);
769 for (mlir::Type a : inputs)
770 argAbi.push_back(mapCIRType(a, typeMapper, dl, modOp));
772 std::unique_ptr<llvm::abi::FunctionInfo> fi = llvm::abi::FunctionInfo::create(
773 llvm::CallingConv::C, retAbi, argAbi, required);
774 targetInfo.computeInfo(*fi);
778 auto nyiCoercion = [&](mlir::Type t) {
779 emitError() <<
"x86_64 calling-convention lowering not yet "
780 "implemented for the ABI coercion of type "
784 FunctionClassification fc;
785 fc.returnsVoid = voidRet;
786 mlir::Type origRet = voidRet ? mlir::Type() : retCIR;
787 std::optional<ArgClassification> retAc =
788 convertABIArgInfo(fi->getReturnInfo(), ctx, origRet);
793 fc.returnInfo = *retAc;
794 for (
unsigned i = 0, e = fi->arg_size(); i < e; ++i) {
795 mlir::Type origArg = i < inputs.size() ? inputs[i] : mlir::Type();
796 const llvm::abi::ArgInfo &argInfo = fi->getArgInfo(i).Info;
797 std::optional<ArgClassification> ac =
798 convertABIArgInfo(argInfo, ctx, origArg);
800 nyiCoercion(origArg);
803 ac->neededIntRegs = argInfo.getNeededIntRegs();
804 ac->neededSseRegs = argInfo.getNeededSseRegs();
805 fc.argInfos.push_back(*ac);
812static llvm::abi::X86AVXABILevel funcAvxLevel(cir::FuncOp func,
813 llvm::abi::X86AVXABILevel base) {
818 auto features = func->getAttrOfType<mlir::StringAttr>(
"cir.target-features");
825 for (llvm::StringRef feature : llvm::split(features.getValue(),
',')) {
826 if (!feature.consume_front(
"+"))
828 if (feature ==
"avx512f")
829 return std::max(base, llvm::abi::X86AVXABILevel::AVX512);
830 avx |= feature ==
"avx";
832 return avx ? std::max(base, llvm::abi::X86AVXABILevel::AVX) : base;
838static std::optional<FunctionClassification>
839classifyX86_64Function(cir::FuncOp func,
const DataLayout &dl,
840 mlir::abi::ABITypeMapper &typeMapper,
841 const llvm::abi::TargetInfo &targetInfo,
843 cir::FuncType fnTy = func.getFunctionType();
844 return classifyX86_64Signature(fnTy.getReturnType(), fnTy.getInputs(),
845 requiredArgs(fnTy), func->getContext(), dl,
846 typeMapper, targetInfo, modOp,
847 [&]() { return func.emitOpError(); });
853static std::optional<ArgClassification> classifyX86_64VarArgType(
854 mlir::Type ty, MLIRContext *ctx,
const DataLayout &dl,
855 mlir::abi::ABITypeMapper &typeMapper,
856 const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp,
857 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
858 std::optional<FunctionClassification> fc = classifyX86_64Signature(
859 cir::VoidType::get(ctx), mlir::TypeRange(ty), llvm::abi::RequiredArgs(0),
860 ctx, dl, typeMapper, targetInfo, modOp, emitError);
863 return fc->argInfos[0];
873static std::optional<FunctionClassification> classifyX86_64VariadicCall(
874 cir::CIRCallOpInterface call, cir::FuncType calleeTy,
const DataLayout &dl,
875 mlir::abi::ABITypeMapper &typeMapper,
876 const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp) {
877 assert(calleeTy.isVarArg() &&
878 "only a variadic callee can take more operands than it declares");
879 Operation *op = call.getOperation();
880 return classifyX86_64Signature(
881 calleeTy.getReturnType(), call.getArgOperands().getTypes(),
882 requiredArgs(calleeTy), op->getContext(), dl, typeMapper, targetInfo,
883 modOp, [&]() { return op->emitOpError(); });
888static bool hasIndirectSlot(
const FunctionClassification &fc) {
889 if (fc.returnInfo.kind == ArgKind::Indirect)
891 return llvm::any_of(fc.argInfos, [](
const ArgClassification &ac) {
892 return ac.kind == ArgKind::Indirect;
899template <
typename OpTy>
static void widenForArgMemory(OpTy op) {
900 cir::MemoryEffectsAttr effects = op.getMemoryEffectsAttr();
903 op.setMemoryEffectsAttr(cir::MemoryEffectsAttr::get(
904 effects.getContext(), effects.getOther(), cir::ModRefInfo::ModRef,
905 effects.getInaccessibleMem(), effects.getErrnoMem(),
906 effects.getTargetMem0(), effects.getTargetMem1()));
916static bool classifiesSamePrefix(
const FunctionClassification &calleeFc,
917 const FunctionClassification &callFc) {
918 if (callFc.argInfos.size() < calleeFc.argInfos.size())
920 return calleeFc.returnInfo == callFc.returnInfo &&
921 std::equal(calleeFc.argInfos.begin(), calleeFc.argInfos.end(),
922 callFc.argInfos.begin());
926struct CallConvLoweringPass
927 :
public impl::CallConvLoweringBase<CallConvLoweringPass> {
928 using CallConvLoweringBase::CallConvLoweringBase;
930 CallConvLoweringPass(
const CallConvLoweringOptions &options,
931 const llvm::abi::X86ABICompatInfo &x86AbiCompat)
932 : CallConvLoweringBase(options), x86AbiCompat(x86AbiCompat) {}
934 void runOnOperation()
override;
940 llvm::abi::X86ABICompatInfo x86AbiCompat;
949static std::optional<FunctionClassification>
950withReturnVoidness(std::optional<FunctionClassification> fc,
951 mlir::Type returnType) {
953 fc->returnsVoid = mlir::isa<cir::VoidType>(returnType);
961std::optional<FunctionClassification>
962classifyFunction(cir::FuncOp func,
const DataLayout &dl,
965 Type returnType = func.getFunctionType().getReturnType();
967 if (!classificationAttrName.empty()) {
968 auto attr = func->getAttrOfType<DictionaryAttr>(classificationAttrName);
971 <<
"missing classification attribute '" << classificationAttrName
972 <<
"' (CallConvLowering driver mode 'classification-attr')";
975 return withReturnVoidness(mlir::abi::test::parseClassificationAttr(
976 attr, [&]() {
return func.emitOpError(); }),
983 "classifyFunction only handles the test target");
984 return withReturnVoidness(mlir::abi::test::classify(argTypes, returnType, dl),
993cir::FuncOp lookupCallee(Operation *callOp, SymbolTable &symbolTable) {
994 FlatSymbolRefAttr callee;
995 if (
auto call = dyn_cast<cir::CallOp>(callOp))
996 callee = call.getCalleeAttr();
997 else if (
auto tryCall = dyn_cast<cir::TryCallOp>(callOp))
998 callee = tryCall.getCalleeAttr();
1003 return symbolTable.lookup<cir::FuncOp>(callee.getValue());
1006void CallConvLoweringPass::runOnOperation() {
1007 ModuleOp moduleOp = getOperation();
1008 MLIRContext *ctx = &getContext();
1011 bool haveAttr = !classificationAttr.empty();
1012 if (haveTarget == haveAttr) {
1013 moduleOp.emitOpError() <<
"CallConvLowering requires exactly one of "
1014 "'target' or 'classification-attr' pass options";
1015 signalPassFailure();
1019 if (!moduleOp->hasAttr(DLTIDialect::kDataLayoutAttrName)) {
1020 moduleOp.emitOpError()
1021 <<
"CallConvLowering requires a DataLayout (dlti.dl_spec attribute "
1023 signalPassFailure();
1027 DataLayout dl(moduleOp);
1028 CIRABIRewriteContext rewriteCtx(moduleOp, dl);
1033 llvm::scope_exit drainParamSlots(
1034 [&] { rewriteCtx.finalizeParameterSlots(); });
1035 SymbolTable symbolTable(moduleOp);
1039 static constexpr unsigned numAvxLevels =
1040 static_cast<unsigned>(llvm::abi::X86AVXABILevel::Last) + 1;
1042 std::optional<mlir::abi::ABITypeMapper> x86TypeMapper;
1043 std::array<std::unique_ptr<llvm::abi::TargetInfo>, numAvxLevels> x86Targets;
1045 x86TypeMapper.emplace(dl);
1047 [&](llvm::abi::X86AVXABILevel level) ->
const llvm::abi::TargetInfo & {
1048 assert(
static_cast<unsigned>(level) < numAvxLevels &&
1049 "a new X86AVXABILevel must move X86AVXABILevel::Last");
1050 std::unique_ptr<llvm::abi::TargetInfo> &slot =
1051 x86Targets[
static_cast<unsigned>(level)];
1053 slot = llvm::abi::createX86_64TargetInfo(
1054 x86TypeMapper->getTypeBuilder(), level,
1055 true, x86AbiCompat);
1058 llvm::abi::X86AVXABILevel baseAvxLevel = x86AvxAbiLevel.getValue();
1059 auto avxLevelFor = [&](cir::FuncOp func) -> llvm::abi::X86AVXABILevel {
1061 return baseAvxLevel;
1062 return funcAvxLevel(func, baseAvxLevel);
1068 llvm::MapVector<cir::FuncOp, FunctionClassification> classifications;
1069 bool anyFailed =
false;
1070 moduleOp.walk([&](cir::FuncOp f) {
1075 cir::FuncType fnTy = f.getFunctionType();
1076 if (f.isDeclaration() &&
1077 (hasIncompleteRecordByValue(fnTy.getReturnType()) ||
1078 llvm::any_of(fnTy.getInputs(), hasIncompleteRecordByValue)))
1080 std::optional<FunctionClassification> fc;
1082 fc = classifyX86_64Function(f, dl, *x86TypeMapper,
1083 x86TargetFor(avxLevelFor(f)), moduleOp);
1085 fc = classifyFunction(f, dl, target, classificationAttr);
1090 classifications.insert({f, std::move(*fc)});
1093 signalPassFailure();
1106 llvm::DenseMap<cir::FuncOp, SmallVector<Operation *>> callers;
1110 llvm::DenseMap<Operation *, FunctionClassification> variadicCallSites;
1111 moduleOp.walk([&](Operation *op) {
1112 auto call = dyn_cast<cir::CIRCallOpInterface>(op);
1115 cir::FuncOp callee = lookupCallee(op, symbolTable);
1118 callers[callee].push_back(op);
1123 cir::FuncType calleeTy = callee.getFunctionType();
1124 if (!isX86 || call.getNumArgOperands() <= calleeTy.getNumInputs())
1130 if (!calleeTy.isVarArg()) {
1131 op->emitOpError() <<
"extra arguments to a callee without a prototype "
1132 "not yet implemented in CallConvLowering";
1141 std::optional<FunctionClassification> fc =
1142 classifyX86_64VariadicCall(call, calleeTy, dl, *x86TypeMapper,
1143 x86TargetFor(avxLevelFor(callee)), moduleOp);
1148 variadicCallSites.insert({op, std::move(*fc)});
1151 signalPassFailure();
1161 llvm::DenseMap<cir::FuncOp, SmallVector<cir::GetGlobalOp>> addressTakers;
1162 moduleOp.walk([&](cir::GetGlobalOp getGlobal) {
1163 auto ptrTy = cast<cir::PointerType>(getGlobal.getAddr().getType());
1164 if (!isa<cir::FuncType>(ptrTy.getPointee()))
1169 auto callee = cast<cir::FuncOp>(symbolTable.lookup(getGlobal.getName()));
1170 addressTakers[callee].push_back(getGlobal);
1178 for (
auto &kv : classifications) {
1179 if (failed(rewriteCtx.prepareNonByvalParameters(kv.first, kv.second))) {
1180 signalPassFailure();
1189 for (
auto &kv : classifications) {
1190 cir::FuncOp func = kv.first;
1191 if (hasIndirectSlot(kv.second) || func.getFunctionType().isVarArg())
1192 widenForArgMemory(func);
1206 OpBuilder builder(ctx);
1207 for (
auto &kv : classifications) {
1208 cir::FuncOp func = kv.first;
1209 const FunctionClassification &fc = kv.second;
1210 if (failed(rewriteCtx.rewriteFunctionDefinition(func, fc, builder))) {
1211 signalPassFailure();
1214 for (Operation *callOp : callers.lookup(func)) {
1215 const FunctionClassification *callFc = &fc;
1216 if (
auto it = variadicCallSites.find(callOp);
1217 it != variadicCallSites.end()) {
1218 callFc = &it->second;
1219 assert(classifiesSamePrefix(fc, *callFc) &&
1220 "a call site's declared parameters must be classified the same "
1221 "way as the callee's");
1223 if (hasIndirectSlot(*callFc))
1224 widenForArgMemory(cast<cir::CIRCallOpInterface>(callOp));
1225 if (failed(rewriteCtx.rewriteCallSite(callOp, *callFc, builder))) {
1226 signalPassFailure();
1230 for (cir::GetGlobalOp addrOp : addressTakers.lookup(func))
1231 rewriteCtx.rewriteFunctionAddress(addrOp, func, builder);
1240 SmallVector<cir::CIRCallOpInterface> indirectCalls;
1241 moduleOp.walk([&](cir::CIRCallOpInterface c) {
1243 indirectCalls.push_back(c);
1245 for (cir::CIRCallOpInterface c : indirectCalls) {
1249 if (!classificationAttr.empty()) {
1250 c->emitOpError() <<
"indirect call cannot be classified in the "
1251 "'classification-attr' driver mode";
1252 signalPassFailure();
1256 auto classifySignature =
1257 [&](mlir::TypeRange argTypes) -> std::optional<FunctionClassification> {
1262 return classifyX86_64Signature(
1263 funcTy.getReturnType(), argTypes, requiredArgs(funcTy), ctx, dl,
1265 x86TargetFor(avxLevelFor(c->getParentOfType<cir::FuncOp>())),
1266 moduleOp, [&]() { return c->emitOpError(); });
1267 return withReturnVoidness(
1268 mlir::abi::test::classify(argTypes, funcTy.getReturnType(), dl),
1269 funcTy.getReturnType());
1276 bool classifyCallSite =
1277 isX86 && c.getNumArgOperands() > funcTy.getNumInputs();
1278 std::optional<FunctionClassification> fc =
1280 ? classifyX86_64VariadicCall(
1281 c, funcTy, dl, *x86TypeMapper,
1282 x86TargetFor(avxLevelFor(c->getParentOfType<cir::FuncOp>())),
1284 : classifySignature(funcTy.getInputs());
1286 signalPassFailure();
1289 if (hasIndirectSlot(*fc))
1290 widenForArgMemory(c);
1291 if (failed(rewriteCtx.rewriteCallSite(c.getOperation(), *fc, builder))) {
1292 signalPassFailure();
1300 SmallVector<cir::VAArgOp> vaArgs;
1301 moduleOp.walk([&](cir::VAArgOp v) { vaArgs.push_back(v); });
1302 for (cir::VAArgOp v : vaArgs) {
1303 cir::FuncOp enclosing = v->getParentOfType<cir::FuncOp>();
1304 std::optional<ArgClassification> ac = classifyX86_64VarArgType(
1305 v.getType(), ctx, dl, *x86TypeMapper,
1306 x86TargetFor(avxLevelFor(enclosing)), moduleOp,
1307 [&]() {
return v->emitOpError(); });
1309 signalPassFailure();
1312 if (failed(rewriteCtx.rewriteVAArg(v.getOperation(), *ac, builder))) {
1313 signalPassFailure();
1323 return std::make_unique<CallConvLoweringPass>();
1329 const llvm::abi::X86ABICompatInfo &x86AbiCompat) {
1330 CallConvLoweringOptions options;
1331 options.target = target;
1332 options.x86AvxAbiLevel = x86AvxAbiLevel;
1334 return std::make_unique<CallConvLoweringPass>(options, x86AbiCompat);
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
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...
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...
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...
cir::FuncType getIndirectCalleeType(cir::CIRCallOpInterface call)
The signature the indirect call call reaches its callee through.
CallConvTarget
The ABI target whose calling-convention rules drive CallConvLowering.
const internal::VariadicAllOfMatcher< Attr > attr
const internal::VariadicAllOfMatcher< Decl > decl
Matches declarations.
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
void info(bool Verbose, unsigned Level, const char *Fmt, Ts &&...Args)
Prints an indented note to stderr when Verbose is set.
@ Default
Set to the current date and time.
std::unique_ptr< Pass > createCallConvLoweringPass()
static bool addressSpace()
static bool opFuncMultiVersioning()