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) {
95 if (isa<cir::VectorType>(ty))
96 return 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))
100 return mayReachSseUp(arrTy.getElementType(), dl);
101 if (
auto recTy = dyn_cast<cir::RecordType>(ty))
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");
116static bool sseUpCoerceSizeUnsupported(uint64_t recordBits,
118 const DataLayout &dl) {
119 if (recordBits == 128 || recordBits == 256 || recordBits == 512)
121 if (recordBits < 128 || recordBits > 512)
123 return llvm::any_of(members,
124 [&](mlir::Type m) {
return mayReachSseUp(m, dl); });
129static bool memberIsEmptyRecord(mlir::Type ty) {
130 while (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
131 ty = arrTy.getElementType();
132 auto recTy = dyn_cast<cir::RecordType>(ty);
142static llvm::Align recordDeclaredAlign(ModuleOp modOp,
cir::RecordType recTy,
143 const DataLayout &dl) {
146 return llvm::Align(dl.getTypeABIAlignment(recTy));
147 return llvm::Align(layout.getRecordAlign());
153static bool hasIncompleteRecordByValue(mlir::Type ty) {
154 if (
auto recTy = dyn_cast<cir::RecordType>(ty))
156 llvm::any_of(recTy.
getMembers(), hasIncompleteRecordByValue);
157 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
158 return hasIncompleteRecordByValue(arrTy.getElementType());
169static bool isSupportedType(mlir::Type ty,
const DataLayout &dl) {
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))
202 return isSupportedType(complexTy.getElementType(), dl);
203 if (
auto vecTy = dyn_cast<cir::VectorType>(ty)) {
206 if (vecTy.getIsScalable())
213 mlir::Type elemTy = vecTy.getElementType();
214 if (
auto elemInt = dyn_cast<cir::IntType>(elemTy)) {
215 if (elemInt.getWidth() % 8)
217 }
else if (
auto elemFp = dyn_cast<cir::FPTypeInterface>(elemTy)) {
218 if (&elemFp.getFloatSemantics() == &llvm::APFloat::x87DoubleExtended())
226 if (!llvm::isPowerOf2_64(dl.getTypeSizeInBits(ty).getFixedValue()))
228 return isSupportedType(elemTy, dl);
230 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
231 return isSupportedType(arrTy.getElementType(), dl);
235 if (
auto bfTy = dyn_cast<cir::BitFieldType>(ty)) {
236 if (mlir::Type storageTy = bfTy.getStorageType())
237 if (!isSupportedType(storageTy, dl))
239 return llvm::all_of(bfTy.getFields(), [&](cir::BitFieldDeclAttr decl) {
240 return isSupportedType(decl.getDeclaredType(), dl);
243 if (
auto recTy = dyn_cast<cir::RecordType>(ty)) {
250 [&](mlir::Type m) { return isSupportedType(m, dl); }))
254 uint64_t recordBits = dl.getTypeSizeInBits(recTy).getFixedValue();
257 if (sseUpCoerceSizeUnsupported(recordBits, members, dl))
262 if (members.empty() && recordBits > 128)
267 if (llvm::any_of(members, [&](mlir::Type m) {
268 auto bfTy = dyn_cast<cir::BitFieldType>(m);
269 if (!bfTy || dl.getTypeSizeInBits(bfTy).getFixedValue() <= 64)
271 return llvm::any_of(bfTy.getFields(), [](cir::BitFieldDeclAttr d) {
272 auto intTy = dyn_cast<cir::IntType>(d.getDeclaredType());
273 return intTy && intTy.getIsBitInt();
286 for (
auto [idx, memberTy,
kind] :
288 if (
kind != cir::RecordMemberKind::Empty)
290 if (dl.getTypeSizeInBits(memberTy).getFixedValue()) {
291 if (memberIsEmptyRecord(memberTy))
294 dl.getTypeABIAlignment(memberTy)) {
305static mlir::Type abiTypeToCIR(
const llvm::abi::Type *ty, MLIRContext *ctx) {
308 return llvm::TypeSwitch<const llvm::abi::Type *, mlir::Type>(ty)
310 [&](
const llvm::abi::VoidType *) {
return cir::VoidType::get(ctx); })
311 .Case([&](
const llvm::abi::IntegerType *intTy) {
312 return cir::IntType::get(ctx, intTy->getSizeInBits().getFixedValue(),
313 intTy->isSigned(), intTy->isBitInt());
315 .Case([&](
const llvm::abi::FloatType *fltTy) {
318 .Case([&](
const llvm::abi::PointerType *) {
319 return cir::PointerType::get(cir::VoidType::get(ctx));
321 .Case([&](
const llvm::abi::VectorType *vecTy) -> mlir::Type {
322 mlir::Type elemCIR = abiTypeToCIR(vecTy->getElementType(), ctx);
325 return cir::VectorType::get(elemCIR,
326 vecTy->getNumElements().getFixedValue());
328 .Case([&](
const llvm::abi::RecordType *recTy) -> mlir::Type {
330 fieldTypes.reserve(recTy->getFields().size());
331 for (
const auto &field : recTy->getFields()) {
332 mlir::Type fieldCIR = abiTypeToCIR(field.FieldType, ctx);
335 fieldTypes.push_back(fieldCIR);
338 return cir::StructType::get(
339 ctx, fieldTypes,
false,
342 .
Default([](
const llvm::abi::Type *) -> mlir::Type {
return nullptr; });
348static const llvm::abi::Type *mapCIRType(mlir::Type type,
349 mlir::abi::ABITypeMapper &typeMapper,
350 const DataLayout &dl, ModuleOp modOp) {
351 llvm::abi::TypeBuilder &tb = typeMapper.getTypeBuilder();
352 return llvm::TypeSwitch<mlir::Type, const llvm::abi::Type *>(type)
353 .Case([&](cir::IntType intTy) {
354 return tb.getIntegerType(intTy.getWidth(),
355 llvm::Align(dl.getTypeABIAlignment(type)),
356 intTy.isSigned(), intTy.getIsBitInt());
358 .Case([&](cir::PointerType ptrTy) {
359 unsigned addrSpace = 0;
360 if (
auto targetAsAttr =
361 dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
362 ptrTy.getAddrSpace()))
363 addrSpace = targetAsAttr.getValue();
364 return tb.getPointerType(dl.getTypeSizeInBits(type),
365 llvm::Align(dl.getTypeABIAlignment(type)),
368 .Case([&](cir::VPtrType) {
372 return tb.getPointerType(dl.getTypeSizeInBits(type),
373 llvm::Align(dl.getTypeABIAlignment(type)));
375 .Case([&](cir::BoolType) {
376 return tb.getIntegerType(dl.getTypeSizeInBits(type),
377 llvm::Align(dl.getTypeABIAlignment(type)),
380 .Case([&](cir::VoidType) {
return tb.getVoidType(); })
381 .Case([&](cir::FPTypeInterface fpTy) {
384 return tb.getFloatType(fpTy.getFloatSemantics(),
385 llvm::Align(dl.getTypeABIAlignment(type)));
387 .Case([&](cir::ComplexType complexTy) {
388 return tb.getComplexType(
389 mapCIRType(complexTy.getElementType(), typeMapper, dl, modOp),
390 llvm::Align(dl.getTypeABIAlignment(type)));
392 .Case([&](cir::VectorType vecTy) {
395 return tb.getVectorType(
396 mapCIRType(vecTy.getElementType(), typeMapper, dl, modOp),
397 llvm::ElementCount::getFixed(vecTy.getSize()),
398 llvm::Align(dl.getTypeABIAlignment(type)));
400 .Case([&](cir::ArrayType arrTy) {
401 const llvm::abi::Type *elemAbi =
402 mapCIRType(arrTy.getElementType(), typeMapper, dl, modOp);
403 return tb.getArrayType(elemAbi, arrTy.getSize(),
404 dl.getTypeSizeInBits(type).getFixedValue());
407 llvm::abi::RecordFlags flags = llvm::abi::RecordFlags::None;
408 if (recordCanPassInRegs(modOp, recTy))
409 flags = flags | llvm::abi::RecordFlags::CanPassInRegisters;
410 llvm::TypeSize sizeBits = llvm::TypeSize::getFixed(
411 dl.getTypeSizeInBits(type).getFixedValue());
412 llvm::Align
align = recordDeclaredAlign(modOp, recTy, dl);
420 return tb.getRecordType(
422 llvm::abi::StructPacking::Default,
447 auto addAccessUnit = [&](cir::BitFieldType bfTy,
448 uint64_t unitOffsetBits) {
449 mlir::Type unitTy = bfTy.getStorageType();
451 unitTy ? dl.getTypeSizeInBits(unitTy).getFixedValue() : 0;
452 for (
auto [idx, decl] : llvm::enumerate(bfTy.getFields())) {
453 const uint64_t offsetBits =
454 unitOffsetBits + bfTy.getFieldBitOffset(idx);
455 const bool holdsUnit = idx == 0 && unitTy;
457 fields.push_back(llvm::abi::FieldInfo(
458 mapCIRType(unitTy, typeMapper, dl, modOp), offsetBits,
459 true,
decl.getWidth(),
460 decl.getIsUnnamed()));
461 mlir::Type declaredTy =
decl.getDeclaredType();
463 dl.getTypeSizeInBits(declaredTy).getFixedValue() > unitBits)
464 fields.push_back(llvm::abi::FieldInfo(
465 mapCIRType(declaredTy, typeMapper, dl, modOp), offsetBits,
466 true, holdsUnit ? 0 :
decl.getWidth(),
467 holdsUnit ||
decl.getIsUnnamed()));
482 cir::RecordMemberKind::Pad) &&
483 "a union member cannot be marked pad");
484 for (mlir::Type variantTy : recTy.
getMembers()) {
485 if (
auto bfTy = dyn_cast<cir::BitFieldType>(variantTy)) {
489 addAccessUnit(bfTy, 0);
492 if (dl.getTypeSizeInBits(variantTy).getFixedValue() == 0 ||
493 memberIsEmptyRecord(variantTy))
495 fields.push_back(llvm::abi::FieldInfo(
496 mapCIRType(variantTy, typeMapper, dl, modOp)));
498 return tb.getUnionType(fields, sizeBits, align,
500 llvm::abi::StructPacking::Default, flags);
509 for (
auto [idx, fieldTy,
kind] :
511 if (
kind == cir::RecordMemberKind::Pad)
513 if (
auto bfTy = dyn_cast<cir::BitFieldType>(fieldTy)) {
519 bool isUnnamed =
kind == cir::RecordMemberKind::Empty;
520 uint64_t widthBits = dl.getTypeSizeInBits(fieldTy).getFixedValue();
521 if (isUnnamed && widthBits == 0)
523 assert((!isUnnamed || !memberIsEmptyRecord(fieldTy)) &&
524 "an empty-for-ABI member must not reach the classifier as an "
525 "unnamed bit-field");
526 fields.push_back(llvm::abi::FieldInfo(
527 mapCIRType(fieldTy, typeMapper, dl, modOp),
529 isUnnamed, isUnnamed ? widthBits : 0,
533 return tb.getRecordType(
534 fields, sizeBits, align, align,
535 llvm::abi::StructPacking::Default,
538 .
Default([](mlir::Type) ->
const llvm::abi::Type * {
540 "mapCIRType: type not pre-filtered by classifyX86_64Function");
570static std::optional<ArgClassification>
571convertABIArgInfo(
const llvm::abi::ArgInfo &info, MLIRContext *ctx,
573 if (
info.isDirect()) {
574 unsigned offset =
info.getDirectOffset();
577 const llvm::abi::Type *coerceAbi =
info.getCoerceToType();
578 bool isAggregate = isa_and_present<cir::RecordType, cir::ArrayType>(origTy);
581 bool comparesAgainstCoerce =
582 coerceAbi && isa_and_present<cir::ComplexType, cir::VectorType>(origTy);
583 bool coerceIsRegisterTuple =
584 isa_and_present<llvm::abi::RecordType>(coerceAbi);
587 if (offset && coerceIsRegisterTuple)
591 auto origInt = dyn_cast_if_present<cir::IntType>(origTy);
592 const auto *coerceInt =
593 dyn_cast_if_present<llvm::abi::IntegerType>(coerceAbi);
594 bool coerceWidensScalar =
595 origInt && coerceInt &&
596 coerceInt->getSizeInBits().getFixedValue() > origInt.getWidth();
602 if (!offset && !isAggregate && !comparesAgainstCoerce &&
603 !coerceIsRegisterTuple && !coerceWidensScalar)
604 return ArgClassification::getDirect();
605 mlir::Type coerced = abiTypeToCIR(coerceAbi, ctx);
610 if (offset && coerced == origTy)
614 if (comparesAgainstCoerce && coerced == origTy)
615 return ArgClassification::getDirect();
616 ArgClassification classified =
617 ArgClassification::getDirect(coerced, offset);
618 classified.canFlatten =
info.getCanBeFlattened();
623 if (
info.isExtend()) {
624 if (isa_and_present<cir::BoolType>(origTy))
625 return ArgClassification::getExtend(
nullptr,
info.isSignExt());
626 assert((!origTy || isa<cir::IntType>(origTy)) &&
627 "the x86_64 classifier only returns Extend for integers and bool");
628 mlir::Type extendedTy = abiTypeToCIR(
info.getCoerceToType(), ctx);
629 return ArgClassification::getExtend(extendedTy,
info.isSignExt());
631 if (
info.isIndirect())
632 return ArgClassification::getIndirect(
info.getIndirectAlign(),
633 info.getIndirectByVal());
634 assert(
info.isIgnore() &&
"Unexpected classification");
635 return ArgClassification::getIgnore();
642static llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy) {
643 if (!fnTy.isVarArg())
644 return llvm::abi::RequiredArgs::All;
645 return llvm::abi::RequiredArgs(fnTy.getNumInputs());
656static std::optional<FunctionClassification> classifyX86_64Signature(
657 mlir::Type retCIR, mlir::TypeRange inputs, llvm::abi::RequiredArgs required,
658 MLIRContext *ctx,
const DataLayout &dl,
659 mlir::abi::ABITypeMapper &typeMapper,
660 const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp,
661 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
662 assert(retCIR &&
"signature return type must be non-null");
663 assert((!required.allowsOptionalArgs() ||
664 required.getNumRequiredArgs() <= inputs.size()) &&
665 "declared parameters cannot outnumber the classified arguments");
666 bool voidRet = isa<cir::VoidType>(retCIR);
668 auto reject = [&](mlir::Type t) ->
bool {
669 if (isSupportedType(t, dl))
672 <<
"x86_64 calling-convention lowering not yet implemented for type "
676 if (!voidRet && reject(retCIR))
678 for (mlir::Type a : inputs)
682 const llvm::abi::Type *retAbi =
683 voidRet ? typeMapper.getTypeBuilder().getVoidType()
684 : mapCIRType(retCIR, typeMapper, dl, modOp);
686 for (mlir::Type a : inputs)
687 argAbi.push_back(mapCIRType(a, typeMapper, dl, modOp));
689 std::unique_ptr<llvm::abi::FunctionInfo> fi = llvm::abi::FunctionInfo::create(
690 llvm::CallingConv::C, retAbi, argAbi, required);
691 targetInfo.computeInfo(*fi);
695 auto nyiCoercion = [&](mlir::Type t) {
696 emitError() <<
"x86_64 calling-convention lowering not yet "
697 "implemented for the ABI coercion of type "
701 FunctionClassification fc;
702 fc.returnsVoid = voidRet;
703 mlir::Type origRet = voidRet ? mlir::Type() : retCIR;
704 std::optional<ArgClassification> retAc =
705 convertABIArgInfo(fi->getReturnInfo(), ctx, origRet);
710 fc.returnInfo = *retAc;
711 for (
unsigned i = 0, e = fi->arg_size(); i < e; ++i) {
712 mlir::Type origArg = i < inputs.size() ? inputs[i] : mlir::Type();
713 const llvm::abi::ArgInfo &argInfo = fi->getArgInfo(i).Info;
714 std::optional<ArgClassification> ac =
715 convertABIArgInfo(argInfo, ctx, origArg);
717 nyiCoercion(origArg);
720 ac->neededIntRegs = argInfo.getNeededIntRegs();
721 ac->neededSseRegs = argInfo.getNeededSseRegs();
722 fc.argInfos.push_back(*ac);
729static llvm::abi::X86AVXABILevel funcAvxLevel(cir::FuncOp func,
730 llvm::abi::X86AVXABILevel base) {
735 auto features = func->getAttrOfType<mlir::StringAttr>(
"cir.target-features");
742 for (llvm::StringRef feature : llvm::split(features.getValue(),
',')) {
743 if (!feature.consume_front(
"+"))
745 if (feature ==
"avx512f")
746 return std::max(base, llvm::abi::X86AVXABILevel::AVX512);
747 avx |= feature ==
"avx";
749 return avx ? std::max(base, llvm::abi::X86AVXABILevel::AVX) : base;
755static std::optional<FunctionClassification>
756classifyX86_64Function(cir::FuncOp func,
const DataLayout &dl,
757 mlir::abi::ABITypeMapper &typeMapper,
758 const llvm::abi::TargetInfo &targetInfo,
760 cir::FuncType fnTy = func.getFunctionType();
761 return classifyX86_64Signature(fnTy.getReturnType(), fnTy.getInputs(),
762 requiredArgs(fnTy), func->getContext(), dl,
763 typeMapper, targetInfo, modOp,
764 [&]() { return func.emitOpError(); });
770static std::optional<ArgClassification> classifyX86_64VarArgType(
771 mlir::Type ty, MLIRContext *ctx,
const DataLayout &dl,
772 mlir::abi::ABITypeMapper &typeMapper,
773 const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp,
774 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
775 std::optional<FunctionClassification> fc = classifyX86_64Signature(
776 cir::VoidType::get(ctx), mlir::TypeRange(ty), llvm::abi::RequiredArgs(0),
777 ctx, dl, typeMapper, targetInfo, modOp, emitError);
780 return fc->argInfos[0];
790static std::optional<FunctionClassification> classifyX86_64VariadicCall(
791 cir::CIRCallOpInterface call, cir::FuncType calleeTy,
const DataLayout &dl,
792 mlir::abi::ABITypeMapper &typeMapper,
793 const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp) {
794 assert(calleeTy.isVarArg() &&
795 "only a variadic callee can take more operands than it declares");
796 Operation *op = call.getOperation();
797 return classifyX86_64Signature(
798 calleeTy.getReturnType(), call.getArgOperands().getTypes(),
799 requiredArgs(calleeTy), op->getContext(), dl, typeMapper, targetInfo,
800 modOp, [&]() { return op->emitOpError(); });
810static bool classifiesSamePrefix(
const FunctionClassification &calleeFc,
811 const FunctionClassification &callFc) {
812 if (callFc.argInfos.size() < calleeFc.argInfos.size())
814 return calleeFc.returnInfo == callFc.returnInfo &&
815 std::equal(calleeFc.argInfos.begin(), calleeFc.argInfos.end(),
816 callFc.argInfos.begin());
820struct CallConvLoweringPass
821 :
public impl::CallConvLoweringBase<CallConvLoweringPass> {
822 using CallConvLoweringBase::CallConvLoweringBase;
824 CallConvLoweringPass(
const CallConvLoweringOptions &options,
825 const llvm::abi::X86ABICompatInfo &x86AbiCompat)
826 : CallConvLoweringBase(options), x86AbiCompat(x86AbiCompat) {}
828 void runOnOperation()
override;
834 llvm::abi::X86ABICompatInfo x86AbiCompat;
843static std::optional<FunctionClassification>
844withReturnVoidness(std::optional<FunctionClassification> fc,
845 mlir::Type returnType) {
847 fc->returnsVoid = mlir::isa<cir::VoidType>(returnType);
855std::optional<FunctionClassification>
856classifyFunction(cir::FuncOp func,
const DataLayout &dl,
859 Type returnType = func.getFunctionType().getReturnType();
861 if (!classificationAttrName.empty()) {
862 auto attr = func->getAttrOfType<DictionaryAttr>(classificationAttrName);
865 <<
"missing classification attribute '" << classificationAttrName
866 <<
"' (CallConvLowering driver mode 'classification-attr')";
869 return withReturnVoidness(mlir::abi::test::parseClassificationAttr(
870 attr, [&]() {
return func.emitOpError(); }),
877 "classifyFunction only handles the test target");
878 return withReturnVoidness(mlir::abi::test::classify(argTypes, returnType, dl),
887cir::FuncOp lookupCallee(Operation *callOp, SymbolTable &symbolTable) {
888 FlatSymbolRefAttr callee;
889 if (
auto call = dyn_cast<cir::CallOp>(callOp))
890 callee = call.getCalleeAttr();
891 else if (
auto tryCall = dyn_cast<cir::TryCallOp>(callOp))
892 callee = tryCall.getCalleeAttr();
897 return symbolTable.lookup<cir::FuncOp>(callee.getValue());
905cir::FuncType indirectCalleeType(cir::CIRCallOpInterface call) {
906 if (!call.isIndirect())
908 return cast<cir::FuncType>(
909 cast<cir::PointerType>(call.getIndirectCall().getType()).getPointee());
912void CallConvLoweringPass::runOnOperation() {
913 ModuleOp moduleOp = getOperation();
914 MLIRContext *ctx = &getContext();
917 bool haveAttr = !classificationAttr.empty();
918 if (haveTarget == haveAttr) {
919 moduleOp.emitOpError() <<
"CallConvLowering requires exactly one of "
920 "'target' or 'classification-attr' pass options";
925 if (!moduleOp->hasAttr(DLTIDialect::kDataLayoutAttrName)) {
926 moduleOp.emitOpError()
927 <<
"CallConvLowering requires a DataLayout (dlti.dl_spec attribute "
933 DataLayout dl(moduleOp);
934 CIRABIRewriteContext rewriteCtx(moduleOp, dl);
939 llvm::scope_exit drainParamSlots(
940 [&] { rewriteCtx.finalizeParameterSlots(); });
941 SymbolTable symbolTable(moduleOp);
945 static constexpr unsigned numAvxLevels =
946 static_cast<unsigned>(llvm::abi::X86AVXABILevel::Last) + 1;
948 std::optional<mlir::abi::ABITypeMapper> x86TypeMapper;
949 std::array<std::unique_ptr<llvm::abi::TargetInfo>, numAvxLevels> x86Targets;
951 x86TypeMapper.emplace(dl);
953 [&](llvm::abi::X86AVXABILevel level) ->
const llvm::abi::TargetInfo & {
954 assert(
static_cast<unsigned>(level) < numAvxLevels &&
955 "a new X86AVXABILevel must move X86AVXABILevel::Last");
956 std::unique_ptr<llvm::abi::TargetInfo> &slot =
957 x86Targets[
static_cast<unsigned>(level)];
959 slot = llvm::abi::createX86_64TargetInfo(
960 x86TypeMapper->getTypeBuilder(), level,
964 llvm::abi::X86AVXABILevel baseAvxLevel = x86AvxAbiLevel.getValue();
965 auto avxLevelFor = [&](cir::FuncOp func) -> llvm::abi::X86AVXABILevel {
968 return funcAvxLevel(func, baseAvxLevel);
974 llvm::MapVector<cir::FuncOp, FunctionClassification> classifications;
975 bool anyFailed =
false;
976 moduleOp.walk([&](cir::FuncOp f) {
981 cir::FuncType fnTy = f.getFunctionType();
982 if (f.isDeclaration() &&
983 (hasIncompleteRecordByValue(fnTy.getReturnType()) ||
984 llvm::any_of(fnTy.getInputs(), hasIncompleteRecordByValue)))
986 std::optional<FunctionClassification> fc;
988 fc = classifyX86_64Function(f, dl, *x86TypeMapper,
989 x86TargetFor(avxLevelFor(f)), moduleOp);
991 fc = classifyFunction(f, dl, target, classificationAttr);
996 classifications.insert({f, std::move(*fc)});
1012 llvm::DenseMap<cir::FuncOp, SmallVector<Operation *>> callers;
1016 llvm::DenseMap<Operation *, FunctionClassification> variadicCallSites;
1017 moduleOp.walk([&](Operation *op) {
1018 auto call = dyn_cast<cir::CIRCallOpInterface>(op);
1021 cir::FuncOp callee = lookupCallee(op, symbolTable);
1024 callers[callee].push_back(op);
1029 cir::FuncType calleeTy = callee.getFunctionType();
1030 if (!isX86 || call.getNumArgOperands() <= calleeTy.getNumInputs())
1036 if (!calleeTy.isVarArg()) {
1037 op->emitOpError() <<
"extra arguments to a callee without a prototype "
1038 "not yet implemented in CallConvLowering";
1047 std::optional<FunctionClassification> fc =
1048 classifyX86_64VariadicCall(call, calleeTy, dl, *x86TypeMapper,
1049 x86TargetFor(avxLevelFor(callee)), moduleOp);
1054 variadicCallSites.insert({op, std::move(*fc)});
1057 signalPassFailure();
1067 llvm::DenseMap<cir::FuncOp, SmallVector<cir::GetGlobalOp>> addressTakers;
1068 moduleOp.walk([&](cir::GetGlobalOp getGlobal) {
1069 auto ptrTy = cast<cir::PointerType>(getGlobal.getAddr().getType());
1070 if (!isa<cir::FuncType>(ptrTy.getPointee()))
1075 auto callee = cast<cir::FuncOp>(symbolTable.lookup(getGlobal.getName()));
1076 addressTakers[callee].push_back(getGlobal);
1085 for (
auto &kv : classifications)
1086 rewriteCtx.normalizeParameterSlotAlignments(kv.first, kv.second);
1099 OpBuilder builder(ctx);
1100 for (
auto &kv : classifications) {
1101 cir::FuncOp func = kv.first;
1102 const FunctionClassification &fc = kv.second;
1103 if (failed(rewriteCtx.rewriteFunctionDefinition(func, fc, builder))) {
1104 signalPassFailure();
1107 for (Operation *callOp : callers.lookup(func)) {
1108 const FunctionClassification *callFc = &fc;
1109 if (
auto it = variadicCallSites.find(callOp);
1110 it != variadicCallSites.end()) {
1111 callFc = &it->second;
1112 assert(classifiesSamePrefix(fc, *callFc) &&
1113 "a call site's declared parameters must be classified the same "
1114 "way as the callee's");
1116 if (failed(rewriteCtx.rewriteCallSite(callOp, *callFc, builder))) {
1117 signalPassFailure();
1121 for (cir::GetGlobalOp addrOp : addressTakers.lookup(func))
1122 rewriteCtx.rewriteFunctionAddress(addrOp, func, builder);
1131 SmallVector<cir::CIRCallOpInterface> indirectCalls;
1132 moduleOp.walk([&](cir::CIRCallOpInterface c) {
1133 if (indirectCalleeType(c))
1134 indirectCalls.push_back(c);
1136 for (cir::CIRCallOpInterface c : indirectCalls) {
1140 if (!classificationAttr.empty()) {
1141 c->emitOpError() <<
"indirect call cannot be classified in the "
1142 "'classification-attr' driver mode";
1143 signalPassFailure();
1146 cir::FuncType funcTy = indirectCalleeType(c);
1147 auto classifySignature =
1148 [&](mlir::TypeRange argTypes) -> std::optional<FunctionClassification> {
1153 return classifyX86_64Signature(
1154 funcTy.getReturnType(), argTypes, requiredArgs(funcTy), ctx, dl,
1156 x86TargetFor(avxLevelFor(c->getParentOfType<cir::FuncOp>())),
1157 moduleOp, [&]() { return c->emitOpError(); });
1158 return withReturnVoidness(
1159 mlir::abi::test::classify(argTypes, funcTy.getReturnType(), dl),
1160 funcTy.getReturnType());
1169 if (c.getNumArgOperands() > funcTy.getNumInputs()) {
1170 std::optional<FunctionClassification> callFc =
1171 classifySignature(c.getArgOperands().getTypes());
1173 signalPassFailure();
1176 if (!callFc->needsRewrite())
1178 c->emitOpError() <<
"variadic arguments to an indirect call not yet "
1179 "implemented in CallConvLowering";
1180 signalPassFailure();
1184 std::optional<FunctionClassification> fc =
1185 classifySignature(funcTy.getInputs());
1187 signalPassFailure();
1190 if (failed(rewriteCtx.rewriteCallSite(c.getOperation(), *fc, builder))) {
1191 signalPassFailure();
1199 SmallVector<cir::VAArgOp> vaArgs;
1200 moduleOp.walk([&](cir::VAArgOp v) { vaArgs.push_back(v); });
1201 for (cir::VAArgOp v : vaArgs) {
1202 cir::FuncOp enclosing = v->getParentOfType<cir::FuncOp>();
1203 std::optional<ArgClassification> ac = classifyX86_64VarArgType(
1204 v.getType(), ctx, dl, *x86TypeMapper,
1205 x86TargetFor(avxLevelFor(enclosing)), moduleOp,
1206 [&]() {
return v->emitOpError(); });
1208 signalPassFailure();
1211 if (failed(rewriteCtx.rewriteVAArg(v.getOperation(), *ac, builder))) {
1212 signalPassFailure();
1222 return std::make_unique<CallConvLoweringPass>();
1228 const llvm::abi::X86ABICompatInfo &x86AbiCompat) {
1229 CallConvLoweringOptions options;
1230 options.target = target;
1231 options.x86AvxAbiLevel = x86AvxAbiLevel;
1233 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...
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...
static bool allowsX86TargetAttrAvx(const clang::ASTContext &astContext, clang::LangOptions::ClangABI compat)
Whether __attribute__((target(...))) on a function may raise its AVX ABI level above the command line...
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()