18#include "mlir/ABI/Targets/Test/TestTarget.h"
21#include "llvm/ABI/Types.h"
22#include "llvm/ADT/TypeSwitch.h"
23#include "llvm/Support/MathExtras.h"
26using namespace mlir::abi;
49 return layout.getArgPassingKind() == cir::ArgPassingKind::CanPassInRegs;
54 return layout && layout.getTransparentUnion();
61 if (isa<cir::VectorType>(ty))
62 return llvm::PowerOf2Ceil(dl.getTypeSizeInBits(ty).getFixedValue()) >= 128;
63 if (
auto fpTy = dyn_cast<cir::FPTypeInterface>(ty))
64 return &fpTy.getFloatSemantics() == &llvm::APFloat::IEEEquad();
65 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
67 if (
auto recTy = dyn_cast<cir::RecordType>(ty))
68 return recTy.isComplete() &&
69 llvm::any_of(recTy.getMembers(),
70 [&](mlir::Type m) { return mayReachSseUp(m, dl); });
73 assert((isa<cir::IntType, cir::BoolType, cir::PointerType, cir::VPtrType,
74 cir::VoidType, cir::ComplexType, cir::BitFieldType>(ty)) &&
75 "unhandled type in the SSEUP walk");
84 const DataLayout &dl) {
85 if (recordBits == 128 || recordBits == 256 || recordBits == 512)
87 if (recordBits < 128 || recordBits > 512)
89 return llvm::any_of(members,
96 while (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
97 ty = arrTy.getElementType();
98 auto recTy = dyn_cast<cir::RecordType>(ty);
99 return recTy && recTy.isEmptyForABI();
109 const DataLayout &dl) {
112 return llvm::Align(dl.getTypeABIAlignment(recTy));
113 return llvm::Align(layout.getRecordAlign());
121 const DataLayout &dl) {
124 return llvm::Align(dl.getTypeABIAlignment(recTy));
125 return llvm::Align(layout.getUnadjustedAlign());
139 if (
auto ptrTy = dyn_cast<cir::PointerType>(ty))
140 return !ptrTy.getAddrSpace() ||
141 mlir::isa<cir::TargetAddressSpaceAttr>(ptrTy.getAddrSpace());
145 if (isa<cir::VPtrType>(ty)) {
149 if (isa<cir::VoidType, cir::BoolType>(ty))
153 if (isa<cir::FPTypeInterface>(ty))
155 if (
auto intTy = dyn_cast<cir::IntType>(ty)) {
163 if (intTy.getIsBitInt())
165 return intTy.getWidth() <= 64 || intTy.getWidth() == 128;
167 if (
auto complexTy = dyn_cast<cir::ComplexType>(ty))
169 if (
auto vecTy = dyn_cast<cir::VectorType>(ty)) {
172 if (vecTy.isScalable())
177 mlir::Type elemTy = vecTy.getElementType();
178 if (
auto elemInt = dyn_cast<cir::IntType>(elemTy)) {
179 if (elemInt.getWidth() % 8)
181 }
else if (!isa<cir::FPTypeInterface, cir::BoolType>(elemTy)) {
186 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
191 if (
auto bfTy = dyn_cast<cir::BitFieldType>(ty)) {
192 if (mlir::Type storageTy = bfTy.getStorageType())
195 return llvm::all_of(bfTy.getFields(), [&](cir::BitFieldDeclAttr decl) {
196 return isSupportedType(decl.getDeclaredType(), dl);
199 if (
auto recTy = dyn_cast<cir::RecordType>(ty)) {
201 if (!recTy.isComplete())
205 if (!llvm::all_of(recTy.getMembers(),
206 [&](mlir::Type m) { return isSupportedType(m, dl); }))
208 if (recTy.isUnion()) {
210 uint64_t recordBits = dl.getTypeSizeInBits(recTy).getFixedValue();
218 if (members.empty() && recordBits > 128)
223 if (llvm::any_of(members, [&](mlir::Type m) {
224 auto bfTy = dyn_cast<cir::BitFieldType>(m);
225 if (!bfTy || dl.getTypeSizeInBits(bfTy).getFixedValue() <= 64)
227 return llvm::any_of(bfTy.getFields(), [](cir::BitFieldDeclAttr d) {
228 auto intTy = dyn_cast<cir::IntType>(d.getDeclaredType());
229 return intTy && intTy.getIsBitInt();
242 for (
auto [idx, memberTy,
kind] :
243 llvm::enumerate(recTy.getMembers(), recTy.getMemberKinds())) {
244 if (
kind != cir::RecordMemberKind::Empty)
246 if (dl.getTypeSizeInBits(memberTy).getFixedValue()) {
249 }
else if (recTy.getElementOffset(dl, idx) %
250 dl.getTypeABIAlignment(memberTy)) {
261static mlir::Type
abiTypeToCIR(
const llvm::abi::Type *ty, MLIRContext *ctx) {
264 return llvm::TypeSwitch<const llvm::abi::Type *, mlir::Type>(ty)
266 [&](
const llvm::abi::VoidType *) {
return cir::VoidType::get(ctx); })
267 .Case([&](
const llvm::abi::IntegerType *intTy) -> mlir::Type {
270 return cir::BoolType::get(ctx);
271 return cir::IntType::get(ctx, intTy->getSizeInBits().getFixedValue(),
272 intTy->isSigned(), intTy->isBitInt());
274 .Case([&](
const llvm::abi::FloatType *fltTy) {
277 .Case([&](
const llvm::abi::PointerType *ptrTy) {
278 auto voidTy = cir::VoidType::get(ctx);
279 if (
unsigned as = ptrTy->getAddrSpace())
280 return cir::PointerType::get(
281 voidTy, cir::TargetAddressSpaceAttr::get(ctx, as));
282 return cir::PointerType::get(voidTy);
284 .Case([&](
const llvm::abi::VectorType *vecTy) -> mlir::Type {
285 mlir::Type elemCIR =
abiTypeToCIR(vecTy->getElementType(), ctx);
288 return cir::VectorType::getFixed(
289 elemCIR, vecTy->getNumElements().getFixedValue());
291 .Case([&](
const llvm::abi::ArrayType *arrTy) -> mlir::Type {
292 mlir::Type elemCIR =
abiTypeToCIR(arrTy->getElementType(), ctx);
295 return cir::ArrayType::get(elemCIR, arrTy->getNumElements());
297 .Case([&](
const llvm::abi::RecordType *recTy) -> mlir::Type {
299 fieldTypes.reserve(recTy->getFields().size());
300 for (
const auto &field : recTy->getFields()) {
301 mlir::Type fieldCIR =
abiTypeToCIR(field.FieldType, ctx);
304 fieldTypes.push_back(fieldCIR);
307 return cir::StructType::get(
308 ctx, fieldTypes,
false,
311 .Default([](
const llvm::abi::Type *) -> mlir::Type {
return nullptr; });
318 if (
auto vecTy = dyn_cast<cir::VectorType>(ty)) {
319 if (
auto longDoubleTy =
320 dyn_cast<cir::LongDoubleType>(vecTy.getElementType()))
321 return cir::VectorType::get(longDoubleTy.getUnderlying(),
331 mlir::abi::ABITypeMapper &typeMapper,
332 const DataLayout &dl, ModuleOp modOp) {
333 llvm::abi::TypeBuilder &tb = typeMapper.getTypeBuilder();
334 return llvm::TypeSwitch<mlir::Type, const llvm::abi::Type *>(type)
335 .Case([&](cir::IntType intTy) {
336 return tb.getIntegerType(intTy.getWidth(),
337 llvm::Align(dl.getTypeABIAlignment(type)),
338 intTy.isSigned(), intTy.getIsBitInt());
340 .Case([&](cir::PointerType ptrTy) {
341 unsigned addrSpace = 0;
342 if (
auto targetAsAttr =
343 dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
344 ptrTy.getAddrSpace()))
345 addrSpace = targetAsAttr.getValue();
347 bool hasAddressSpaceQualifier = ptrTy.getAddrSpace() !=
nullptr;
348 return tb.getPointerType(dl.getTypeSizeInBits(type),
349 llvm::Align(dl.getTypeABIAlignment(type)),
350 addrSpace, hasAddressSpaceQualifier);
352 .Case([&](cir::VPtrType) {
356 return tb.getPointerType(dl.getTypeSizeInBits(type),
357 llvm::Align(dl.getTypeABIAlignment(type)));
359 .Case([&](cir::BoolType) {
362 return tb.getIntegerType(1, llvm::Align(dl.getTypeABIAlignment(type)),
365 .Case([&](cir::VoidType) {
return tb.getVoidType(); })
366 .Case([&](cir::FPTypeInterface fpTy) {
369 return tb.getFloatType(fpTy.getFloatSemantics(),
370 llvm::Align(dl.getTypeABIAlignment(type)));
372 .Case([&](cir::ComplexType complexTy) {
373 return tb.getComplexType(
374 mapCIRType(complexTy.getElementType(), typeMapper, dl, modOp),
375 llvm::Align(dl.getTypeABIAlignment(type)));
377 .Case([&](cir::VectorType vecTy) {
380 return tb.getVectorType(
381 mapCIRType(vecTy.getElementType(), typeMapper, dl, modOp),
382 vecTy.getSize(), llvm::Align(dl.getTypeABIAlignment(type)));
384 .Case([&](cir::ArrayType arrTy) {
385 const llvm::abi::Type *elemAbi =
386 mapCIRType(arrTy.getElementType(), typeMapper, dl, modOp);
387 return tb.getArrayType(elemAbi, arrTy.getSize(),
388 dl.getTypeSizeInBits(type).getFixedValue());
391 llvm::abi::RecordFlags flags = llvm::abi::RecordFlags::None;
393 flags = flags | llvm::abi::RecordFlags::CanPassInRegisters;
395 flags = flags | llvm::abi::RecordFlags::IsTransparent;
396 llvm::TypeSize sizeBits = llvm::TypeSize::getFixed(
397 dl.getTypeSizeInBits(type).getFixedValue());
405 return tb.getRecordType(
406 {}, sizeBits, align, unadjustedAlign,
407 llvm::abi::StructPacking::Default,
432 auto addAccessUnit = [&](cir::BitFieldType bfTy,
433 uint64_t unitOffsetBits) {
434 mlir::Type unitTy = bfTy.getStorageType();
436 unitTy ? dl.getTypeSizeInBits(unitTy).getFixedValue() : 0;
437 for (
auto [idx, decl] : llvm::enumerate(bfTy.getFields())) {
438 const uint64_t offsetBits =
439 unitOffsetBits + bfTy.getFieldBitOffset(idx);
440 const bool holdsUnit = idx == 0 && unitTy;
442 fields.push_back(llvm::abi::FieldInfo(
443 mapCIRType(unitTy, typeMapper, dl, modOp), offsetBits,
444 true, decl.getWidth(),
445 decl.getIsUnnamed()));
446 mlir::Type declaredTy = decl.getDeclaredType();
448 dl.getTypeSizeInBits(declaredTy).getFixedValue() > unitBits)
449 fields.push_back(llvm::abi::FieldInfo(
450 mapCIRType(declaredTy, typeMapper, dl, modOp), offsetBits,
451 true, holdsUnit ? 0 : decl.getWidth(),
452 holdsUnit || decl.getIsUnnamed()));
467 cir::RecordMemberKind::Pad) &&
468 "a union member cannot be marked pad");
469 for (mlir::Type variantTy : recTy.
getMembers()) {
470 if (
auto bfTy = dyn_cast<cir::BitFieldType>(variantTy)) {
474 addAccessUnit(bfTy, 0);
477 if (dl.getTypeSizeInBits(variantTy).getFixedValue() == 0 ||
480 fields.push_back(llvm::abi::FieldInfo(
481 mapCIRType(variantTy, typeMapper, dl, modOp)));
483 return tb.getUnionType(fields, sizeBits, align, unadjustedAlign,
484 llvm::abi::StructPacking::Default, flags);
493 for (
auto [idx, fieldTy,
kind] :
495 if (
kind == cir::RecordMemberKind::Pad)
497 if (
auto bfTy = dyn_cast<cir::BitFieldType>(fieldTy)) {
503 bool isUnnamed =
kind == cir::RecordMemberKind::Empty;
504 uint64_t widthBits = dl.getTypeSizeInBits(fieldTy).getFixedValue();
505 if (isUnnamed && widthBits == 0)
508 "an empty-for-ABI member must not reach the classifier as an "
509 "unnamed bit-field");
510 fields.push_back(llvm::abi::FieldInfo(
513 isUnnamed, isUnnamed ? widthBits : 0,
517 return tb.getRecordType(fields, sizeBits, align, unadjustedAlign,
518 llvm::abi::StructPacking::Default,
522 .Default([](mlir::Type) ->
const llvm::abi::Type * {
524 "mapCIRType: type not pre-filtered by classifySignature");
533 const llvm::abi::Type *coercedAbiTy) {
534 if (
auto intTy = dyn_cast<cir::IntType>(origTy)) {
535 const auto *abiInt = dyn_cast<llvm::abi::IntegerType>(coercedAbiTy);
537 abiInt->getSizeInBits().getFixedValue() == intTy.getWidth();
539 if (isa<cir::BoolType>(origTy))
540 return isa<llvm::abi::IntegerType>(coercedAbiTy);
541 if (
auto fpTy = dyn_cast<cir::FPTypeInterface>(origTy)) {
542 const auto *abiFloat = dyn_cast<llvm::abi::FloatType>(coercedAbiTy);
543 return abiFloat && abiFloat->getSemantics() == &fpTy.getFloatSemantics();
545 if (isa<cir::PointerType, cir::VPtrType>(origTy))
546 return isa<llvm::abi::PointerType>(coercedAbiTy);
555static mlir::FailureOr<ArgClassification>
558 assert(origTy &&
"a Direct value must have a type");
559 unsigned offset = info.getDirectOffset();
560 llvm::MaybeAlign align = info.getDirectAlign();
561 auto passUnchanged = [&] {
562 return ArgClassification::getDirect(
nullptr, 0,
565 auto passCoerced = [&](mlir::Type coerced,
unsigned coercedOffset) {
566 ArgClassification classified =
567 ArgClassification::getDirect(coerced, coercedOffset, align);
568 classified.canFlatten = info.getCanBeFlattened();
572 const llvm::abi::Type *coercedAbiTy = info.getCoerceToType();
576 auto recTy = dyn_cast<cir::RecordType>(origTy);
577 if (recTy && recTy.isStruct() && info.getCanBeFlattened())
578 return passCoerced(recTy, 0);
579 return passUnchanged();
586 bool coercedIsStruct = isa<llvm::abi::RecordType>(coercedAbiTy);
587 if (offset && coercedIsStruct)
588 return mlir::failure();
597 !isa<cir::VectorType, cir::RecordType, cir::ArrayType, cir::ComplexType>(
599 if (isScalar && !offset && !coercedIsStruct) {
600 auto origPtr = dyn_cast<cir::PointerType>(origTy);
601 const auto *coercedAbiPtr = dyn_cast<llvm::abi::PointerType>(coercedAbiTy);
602 if (origPtr && coercedAbiPtr) {
605 auto origAS = dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
606 origPtr.getAddrSpace());
607 if (coercedAbiPtr->getAddrSpace() == (origAS ? origAS.getValue() : 0))
608 return passUnchanged();
609 auto coercedPtr = cast<cir::PointerType>(
abiTypeToCIR(coercedAbiTy, ctx));
610 return passCoerced(cir::PointerType::get(origPtr.getPointee(),
611 coercedPtr.getAddrSpace()),
614 auto origInt = dyn_cast<cir::IntType>(origTy);
615 const auto *coercedAbiInt = dyn_cast<llvm::abi::IntegerType>(coercedAbiTy);
617 origInt && coercedAbiInt &&
618 coercedAbiInt->getSizeInBits().getFixedValue() > origInt.getWidth();
625 "the classifier changed a scalar's kind or width");
626 return passUnchanged();
632 return mlir::failure();
638 return mlir::failure();
640 if (isa<cir::VectorType>(origTy))
641 return passUnchanged();
645 return passCoerced(coerced, offset);
651static mlir::FailureOr<ArgClassification>
658 if (info.isExtend()) {
659 assert(origTy &&
"an extended value must have a type");
660 if (isa<cir::BoolType>(origTy))
661 return ArgClassification::getExtend(
nullptr, info.isSignExt());
662 assert((isa<cir::IntType, cir::RecordType>(origTy)) &&
663 "Extend is only expected for integers, bool, and transparent "
665 mlir::Type extendedTy =
abiTypeToCIR(info.getCoerceToType(), ctx);
666 return ArgClassification::getExtend(extendedTy, info.isSignExt());
668 if (info.isIndirect())
669 return ArgClassification::getIndirect(info.getIndirectAlign(),
670 info.getIndirectByVal(),
671 info.getIndirectAddrSpace());
672 if (info.isIndirectAliased())
673 return ArgClassification::getIndirectAliased(info.getIndirectAlign(),
674 info.getIndirectAddrSpace());
677 assert(!info.isCoerceAndExpand() &&
"CoerceAndExpand is not handled yet");
678 assert(info.isIgnore() &&
"Unexpected classification");
679 return ArgClassification::getIgnore();
684 if (!fnTy.isVarArg())
685 return llvm::abi::RequiredArgs::All;
686 return llvm::abi::RequiredArgs(fnTy.getNumInputs());
698mlir::FailureOr<FunctionClassification>
699CIRABIClassifierCommon::classifySignature(
700 mlir::Type retCIR, mlir::TypeRange inputs, llvm::abi::RequiredArgs required,
701 const llvm::abi::TargetInfo &targetInfo, llvm::CallingConv::ID callConv,
702 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
703 assert(retCIR &&
"signature return type must be non-null");
704 assert((!required.allowsOptionalArgs() ||
705 required.getNumRequiredArgs() <= inputs.size()) &&
706 "declared parameters cannot outnumber the classified arguments");
707 MLIRContext *ctx =
modOp->getContext();
708 bool voidRet = isa<cir::VoidType>(retCIR);
710 auto reject = [&](mlir::Type t) ->
bool {
713 emitError() <<
"calling-convention lowering not yet implemented for type "
717 if (!voidRet && reject(retCIR))
718 return mlir::failure();
719 for (mlir::Type a : inputs)
721 return mlir::failure();
723 const llvm::abi::Type *retAbi =
724 voidRet ?
typeMapper.getTypeBuilder().getVoidType()
726 SmallVector<const llvm::abi::Type *> argAbi;
727 for (mlir::Type a : inputs)
730 std::unique_ptr<llvm::abi::FunctionInfo> fi =
731 llvm::abi::FunctionInfo::create(callConv, retAbi, argAbi, required);
732 targetInfo.computeInfo(*fi);
736 auto nyiCoercion = [&](mlir::Type t) {
737 emitError() <<
"calling-convention lowering not yet "
738 "implemented for the ABI coercion of type "
742 FunctionClassification fc;
743 fc.returnsVoid = voidRet;
744 mlir::Type origRet = voidRet ? mlir::Type() : retCIR;
745 mlir::FailureOr<ArgClassification> retAc =
749 return mlir::failure();
751 fc.returnInfo = *retAc;
752 for (
unsigned i = 0, e = fi->arg_size(); i < e; ++i) {
753 mlir::Type origArg = inputs[i];
754 const llvm::abi::ArgInfo &argInfo = fi->getArgInfo(i).Info;
755 mlir::FailureOr<ArgClassification> ac =
758 nyiCoercion(origArg);
759 return mlir::failure();
763 auto recTy = dyn_cast<cir::RecordType>(origArg);
764 if (ac->kind == ArgKind::Direct && !ac->coercedType && recTy &&
766 ac->coercedType = recTy.getMembers().front();
767 ac->neededIntRegs = argInfo.getNeededIntRegs();
768 ac->neededSseRegs = argInfo.getNeededSseRegs();
769 fc.argInfos.push_back(*ac);
777 if (cc == cir::CallingConv::AMDGPUKernel)
778 return llvm::CallingConv::AMDGPU_KERNEL;
779 return llvm::CallingConv::C;
785mlir::FailureOr<FunctionClassification>
787 cir::FuncType fnTy = func.getFunctionType();
788 return classifySignature(fnTy.getReturnType(), fnTy.getInputs(),
791 [&]() { return func.emitOpError(); });
798 mlir::Type ty,
const llvm::abi::TargetInfo &targetInfo,
799 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
800 MLIRContext *ctx =
modOp->getContext();
801 mlir::FailureOr<FunctionClassification> fc = classifySignature(
802 cir::VoidType::get(ctx), mlir::TypeRange(ty), llvm::abi::RequiredArgs(0),
803 targetInfo, llvm::CallingConv::C, emitError);
805 return mlir::failure();
806 return fc->argInfos[0];
816mlir::FailureOr<FunctionClassification>
818 cir::CIRCallOpInterface call, cir::FuncType calleeTy,
819 const llvm::abi::TargetInfo &targetInfo, llvm::CallingConv::ID callConv) {
820 assert(calleeTy.isVarArg() &&
821 "only a variadic callee can take more operands than it declares");
822 Operation *op = call.getOperation();
823 return classifySignature(calleeTy.getReturnType(),
824 call.getArgOperands().getTypes(),
826 [&]() {
return op->emitOpError(); });
829mlir::FailureOr<FunctionClassification>
831 cir::FuncOp callee) {
837mlir::FailureOr<FunctionClassification>
840 const llvm::abi::TargetInfo &targetInfo =
844 if (call.getNumArgOperands() > funcTy.getNumInputs())
846 return classifySignature(
847 funcTy.getReturnType(), funcTy.getInputs(),
requiredArgs(funcTy),
848 targetInfo, llvm::CallingConv::C, [&]() {
return call->emitOpError(); });
857static mlir::FailureOr<FunctionClassification>
859 mlir::Type returnType) {
861 fc->returnsVoid = mlir::isa<cir::VoidType>(returnType);
869static mlir::FailureOr<FunctionClassification>
873 Type returnType = func.getFunctionType().getReturnType();
875 if (!classificationAttrName.empty()) {
876 auto attr = func->getAttrOfType<DictionaryAttr>(classificationAttrName);
879 <<
"missing classification attribute '" << classificationAttrName
880 <<
"' (CallConvLowering driver mode 'classification-attr')";
881 return mlir::failure();
884 attr, [&]() {
return func.emitOpError(); }),
891 "classifyFunction only handles the test target");
903 explicit TestTargetClassifier(
const mlir::DataLayout &dl) : dl(dl) {}
905 mlir::FailureOr<FunctionClassification>
912 mlir::FailureOr<FunctionClassification>
913 classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp)
final {
915 <<
"variadic arguments not yet implemented in CallConvLowering";
916 return mlir::failure();
919 mlir::FailureOr<FunctionClassification>
920 classifyIndirectCall(cir::CIRCallOpInterface call)
final {
922 if (call.getNumArgOperands() > funcTy.getNumInputs()) {
924 <<
"variadic arguments not yet implemented in CallConvLowering";
925 return mlir::failure();
928 funcTy.getReturnType(),
930 funcTy.getReturnType());
933 mlir::FailureOr<ArgClassification> classifyVAArg(cir::VAArgOp vaArg)
final {
935 <<
"not yet implemented in CallConvLowering for the test target";
936 return mlir::failure();
940 const mlir::DataLayout &dl;
948 InjectedClassifier(
const mlir::DataLayout &dl, llvm::StringRef attrName)
949 : dl(dl), attrName(attrName) {}
951 mlir::FailureOr<FunctionClassification>
958 mlir::FailureOr<FunctionClassification>
959 classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp)
final {
961 <<
"variadic arguments not yet implemented in CallConvLowering";
962 return mlir::failure();
967 mlir::FailureOr<FunctionClassification>
968 classifyIndirectCall(cir::CIRCallOpInterface call)
final {
969 call->emitOpError() <<
"indirect call cannot be classified in the "
970 "'classification-attr' driver mode";
971 return mlir::failure();
974 mlir::FailureOr<ArgClassification> classifyVAArg(cir::VAArgOp vaArg)
final {
975 vaArg->emitOpError() <<
"cannot be classified in the "
976 "'classification-attr' driver mode";
977 return mlir::failure();
981 const mlir::DataLayout &dl;
982 std::string attrName;
987std::unique_ptr<CIRABIClassifier>
989 return std::make_unique<TestTargetClassifier>(dl);
992std::unique_ptr<CIRABIClassifier>
994 llvm::StringRef attrName) {
995 return std::make_unique<InjectedClassifier>(dl, attrName);
static bool recordIsTransparentUnion(ModuleOp modOp, cir::RecordType recTy)
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 recordUnadjustedAlign(ModuleOp modOp, cir::RecordType recTy, const DataLayout &dl)
A record's unadjusted alignment, the alignment its members give it before an alignment attribute on t...
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 mlir::FailureOr< 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::FailureOr< FunctionClassification > withReturnVoidness(mlir::FailureOr< FunctionClassification > fc, mlir::Type returnType)
Record on fc whether returnType is CIR's void.
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 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 llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy)
Where fnTy's declared parameters end and its ellipsis arguments begin.
static bool coerceKeepsScalarValue(mlir::Type origTy, const llvm::abi::Type *coercedAbiTy)
Whether coercedAbiTy holds the same value as the scalar origTy: an integer of the same width,...
static mlir::FailureOr< FunctionClassification > classifyFunction(cir::FuncOp func, const DataLayout &dl, cir::CallConvTarget target, StringRef classificationAttrName)
Classify func using whichever driver mode is configured.
static mlir::FailureOr< ArgClassification > convertDirectArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx, mlir::Type origTy)
Convert a Direct llvm::abi::ArgInfo.
static bool sseUpCoerceSizeUnsupported(uint64_t recordBits, llvm::ArrayRef< mlir::Type > members, const DataLayout &dl)
Whether the record's size has no SSEUP coerce.
static bool isSupportedType(mlir::Type ty, const DataLayout &dl)
The CIR types the bridge handles.
static mlir::Type abiTypeToCIR(const llvm::abi::Type *ty, MLIRContext *ctx)
Convert an llvm::abi::Type coercion type back to a CIR type.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
mlir::FailureOr< mlir::abi::FunctionClassification > classifyIndirectCall(cir::CIRCallOpInterface call) override
A callee resolved at run time carries no features of its own, so the call is classified at the featur...
mlir::FailureOr< mlir::abi::FunctionClassification > classifyFunction(cir::FuncOp func) override
Classify a cir.func using the LLVM ABI library.
const mlir::DataLayout & dl
mlir::FailureOr< 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...
mlir::FailureOr< 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...
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
Produces the classification CallConvLowering rewrites a signature from.
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...
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...
cir::FuncType getIndirectCalleeType(cir::CIRCallOpInterface call)
The signature the indirect call call reaches its callee through.
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.
static bool addressSpace()