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/StringExtras.h"
52#include "llvm/ADT/TypeSwitch.h"
53#include "llvm/IR/CallingConv.h"
54#include "llvm/Support/MathExtras.h"
60using namespace mlir::abi;
64#define GEN_PASS_DEF_CALLCONVLOWERING
65#include "clang/CIR/Dialect/Passes.h.inc"
95 return layout.getArgPassingKind() == cir::ArgPassingKind::CanPassInRegs;
100static bool memberIsEmptyRecord(mlir::Type ty) {
101 while (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
102 ty = arrTy.getElementType();
103 auto recTy = dyn_cast<cir::RecordType>(ty);
113static llvm::Align recordDeclaredAlign(ModuleOp modOp,
cir::RecordType recTy,
114 const DataLayout &dl) {
117 return llvm::Align(dl.getTypeABIAlignment(recTy));
118 return llvm::Align(layout.getRecordAlign());
123static bool reachesNamedBitFieldUnit(mlir::Type ty) {
124 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
125 return reachesNamedBitFieldUnit(arrTy.getElementType());
126 auto recTy = dyn_cast<cir::RecordType>(ty);
131 for (
auto [memberTy,
kind] :
136 return llvm::any_of(recTy.
getMembers(), reachesNamedBitFieldUnit);
142static bool hasIncompleteRecordByValue(mlir::Type ty) {
143 if (
auto recTy = dyn_cast<cir::RecordType>(ty))
145 llvm::any_of(recTy.
getMembers(), hasIncompleteRecordByValue);
146 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
147 return hasIncompleteRecordByValue(arrTy.getElementType());
158static bool isSupportedType(mlir::Type ty,
const DataLayout &dl) {
162 if (
auto ptrTy = dyn_cast<cir::PointerType>(ty))
163 return !ptrTy.getAddrSpace() ||
164 mlir::isa<cir::TargetAddressSpaceAttr>(ptrTy.getAddrSpace());
168 if (isa<cir::VPtrType>(ty)) {
172 if (isa<cir::VoidType, cir::BoolType>(ty))
176 if (isa<cir::FPTypeInterface>(ty))
178 if (
auto intTy = dyn_cast<cir::IntType>(ty)) {
189 if (intTy.getIsBitInt())
190 return intTy.getWidth() <= 128;
191 return intTy.getWidth() <= 64 || intTy.getWidth() == 128;
193 if (
auto complexTy = dyn_cast<cir::ComplexType>(ty))
194 return isSupportedType(complexTy.getElementType(), dl);
195 if (
auto vecTy = dyn_cast<cir::VectorType>(ty)) {
198 if (vecTy.getIsScalable())
206 mlir::Type elemTy = vecTy.getElementType();
207 if (
auto elemInt = dyn_cast<cir::IntType>(elemTy)) {
208 if (elemInt.getWidth() % 8)
210 }
else if (
auto elemFp = dyn_cast<cir::FPTypeInterface>(elemTy)) {
211 if (&elemFp.getFloatSemantics() == &llvm::APFloat::x87DoubleExtended())
219 if (!llvm::isPowerOf2_64(dl.getTypeSizeInBits(ty).getFixedValue()))
221 return isSupportedType(elemTy, dl);
223 if (
auto arrTy = dyn_cast<cir::ArrayType>(ty))
224 return isSupportedType(arrTy.getElementType(), dl);
225 if (
auto recTy = dyn_cast<cir::RecordType>(ty)) {
236 uint64_t recordBits = dl.getTypeSizeInBits(recTy).getFixedValue();
237 if (members.empty()) {
241 if (recordBits > 128)
244 auto spansRecord = [&](mlir::Type m) {
245 return dl.getTypeSizeInBits(m).getFixedValue() == recordBits;
247 if (!llvm::any_of(members, spansRecord))
254 !llvm::any_of(llvm::zip_equal(members, kinds),
255 [&](
const auto &pair) {
256 auto [memberTy,
kind] = pair;
257 return spansRecord(memberTy) &&
259 !memberIsEmptyRecord(memberTy);
263 }
else if (recTy.
getPadded() && reachesNamedBitFieldUnit(recTy)) {
276 for (
auto [idx, memberTy,
kind] :
278 if (
kind != cir::RecordMemberKind::Empty)
280 if (dl.getTypeSizeInBits(memberTy).getFixedValue()) {
281 if (memberIsEmptyRecord(memberTy))
284 dl.getTypeABIAlignment(memberTy)) {
289 [&](mlir::Type m) { return isSupportedType(m, dl); });
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) {
302 return cir::IntType::get(ctx, intTy->getSizeInBits().getFixedValue(),
303 intTy->isSigned(), intTy->isBitInt());
305 .Case([&](
const llvm::abi::FloatType *fltTy) {
308 .Case([&](
const llvm::abi::PointerType *) {
309 return cir::PointerType::get(cir::VoidType::get(ctx));
311 .Case([&](
const llvm::abi::VectorType *vecTy) -> mlir::Type {
312 mlir::Type elemCIR = abiTypeToCIR(vecTy->getElementType(), ctx);
315 return cir::VectorType::get(elemCIR,
316 vecTy->getNumElements().getFixedValue());
318 .Case([&](
const llvm::abi::RecordType *recTy) -> mlir::Type {
320 fieldTypes.reserve(recTy->getFields().size());
321 for (
const auto &field : recTy->getFields()) {
322 mlir::Type fieldCIR = abiTypeToCIR(field.FieldType, ctx);
325 fieldTypes.push_back(fieldCIR);
328 return cir::StructType::get(
329 ctx, fieldTypes,
false,
332 .
Default([](
const llvm::abi::Type *) -> mlir::Type {
return nullptr; });
338static const llvm::abi::Type *mapCIRType(mlir::Type type,
339 mlir::abi::ABITypeMapper &typeMapper,
340 const DataLayout &dl, ModuleOp modOp) {
341 llvm::abi::TypeBuilder &tb = typeMapper.getTypeBuilder();
342 return llvm::TypeSwitch<mlir::Type, const llvm::abi::Type *>(type)
343 .Case([&](cir::IntType intTy) {
344 return tb.getIntegerType(intTy.getWidth(),
345 llvm::Align(dl.getTypeABIAlignment(type)),
346 intTy.isSigned(), intTy.getIsBitInt());
348 .Case([&](cir::PointerType ptrTy) {
349 unsigned addrSpace = 0;
350 if (
auto targetAsAttr =
351 dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
352 ptrTy.getAddrSpace()))
353 addrSpace = targetAsAttr.getValue();
354 return tb.getPointerType(dl.getTypeSizeInBits(type),
355 llvm::Align(dl.getTypeABIAlignment(type)),
358 .Case([&](cir::VPtrType) {
362 return tb.getPointerType(dl.getTypeSizeInBits(type),
363 llvm::Align(dl.getTypeABIAlignment(type)));
365 .Case([&](cir::BoolType) {
366 return tb.getIntegerType(dl.getTypeSizeInBits(type),
367 llvm::Align(dl.getTypeABIAlignment(type)),
370 .Case([&](cir::VoidType) {
return tb.getVoidType(); })
371 .Case([&](cir::FPTypeInterface fpTy) {
374 return tb.getFloatType(fpTy.getFloatSemantics(),
375 llvm::Align(dl.getTypeABIAlignment(type)));
377 .Case([&](cir::ComplexType complexTy) {
378 return tb.getComplexType(
379 mapCIRType(complexTy.getElementType(), typeMapper, dl, modOp),
380 llvm::Align(dl.getTypeABIAlignment(type)));
382 .Case([&](cir::VectorType vecTy) {
385 return tb.getVectorType(
386 mapCIRType(vecTy.getElementType(), typeMapper, dl, modOp),
387 llvm::ElementCount::getFixed(vecTy.getSize()),
388 llvm::Align(dl.getTypeABIAlignment(type)));
390 .Case([&](cir::ArrayType arrTy) {
391 const llvm::abi::Type *elemAbi =
392 mapCIRType(arrTy.getElementType(), typeMapper, dl, modOp);
393 return tb.getArrayType(elemAbi, arrTy.getSize(),
394 dl.getTypeSizeInBits(type).getFixedValue());
397 llvm::abi::RecordFlags flags = llvm::abi::RecordFlags::None;
398 if (recordCanPassInRegs(modOp, recTy))
399 flags = flags | llvm::abi::RecordFlags::CanPassInRegisters;
400 llvm::TypeSize sizeBits = llvm::TypeSize::getFixed(
401 dl.getTypeSizeInBits(type).getFixedValue());
402 llvm::Align
align = recordDeclaredAlign(modOp, recTy, dl);
408 return tb.getRecordType(
409 {}, sizeBits,
align, llvm::abi::StructPacking::Default,
422 for (
auto [fieldTy,
kind] :
425 fields.push_back(llvm::abi::FieldInfo(
426 mapCIRType(fieldTy, typeMapper, dl, modOp)));
427 return tb.getUnionType(fields, sizeBits, align,
428 llvm::abi::StructPacking::Default, flags);
437 for (
auto [idx, fieldTy,
kind] :
439 if (
kind == cir::RecordMemberKind::Pad)
443 mlir::Type countedTy = fieldTy;
444 bool isUnnamedUnit =
kind == cir::RecordMemberKind::Empty;
446 countedTy = cast<cir::ArrayType>(fieldTy).getElementType();
447 isUnnamedUnit =
true;
449 uint64_t widthBits = dl.getTypeSizeInBits(countedTy).getFixedValue();
450 if (isUnnamedUnit && widthBits == 0)
452 assert((!isUnnamedUnit || !memberIsEmptyRecord(countedTy)) &&
453 "an empty-for-ABI member must not reach the classifier as an "
454 "unnamed bit-field");
460 fields.push_back(llvm::abi::FieldInfo(
461 mapCIRType(countedTy, typeMapper, dl, modOp),
463 isAccessUnit, isAccessUnit ? widthBits : 0,
467 return tb.getRecordType(
468 fields, sizeBits, align, llvm::abi::StructPacking::Default,
471 .
Default([](mlir::Type) ->
const llvm::abi::Type * {
473 "mapCIRType: type not pre-filtered by classifyX86_64Function");
499static std::optional<ArgClassification>
500convertABIArgInfo(
const llvm::abi::ArgInfo &info, MLIRContext *ctx,
502 if (
info.isDirect()) {
506 if (
info.getDirectOffset())
510 const llvm::abi::Type *coerceAbi =
info.getCoerceToType();
511 bool isAggregate = isa_and_present<cir::RecordType, cir::ArrayType>(origTy);
514 bool comparesAgainstCoerce =
515 coerceAbi && isa_and_present<cir::ComplexType, cir::VectorType>(origTy);
516 bool coerceIsRegisterTuple =
517 isa_and_present<llvm::abi::RecordType>(coerceAbi);
520 auto origInt = dyn_cast_if_present<cir::IntType>(origTy);
521 const auto *coerceInt =
522 dyn_cast_if_present<llvm::abi::IntegerType>(coerceAbi);
523 bool coerceWidensScalar =
524 origInt && coerceInt &&
525 coerceInt->getSizeInBits().getFixedValue() > origInt.getWidth();
529 if (!isAggregate && !comparesAgainstCoerce && !coerceIsRegisterTuple &&
531 return ArgClassification::getDirect(
nullptr);
532 mlir::Type coerced = abiTypeToCIR(coerceAbi, ctx);
537 if (comparesAgainstCoerce && coerced == origTy)
538 return ArgClassification::getDirect(
nullptr);
539 return ArgClassification::getDirect(coerced);
541 if (
info.isExtend()) {
542 if (isa_and_present<cir::BoolType>(origTy))
543 return ArgClassification::getExtend(
nullptr,
info.isSignExt());
544 assert((!origTy || isa<cir::IntType>(origTy)) &&
545 "the x86_64 classifier only returns Extend for integers and bool");
546 mlir::Type extendedTy = abiTypeToCIR(
info.getCoerceToType(), ctx);
547 return ArgClassification::getExtend(extendedTy,
info.isSignExt());
549 if (
info.isIndirect())
550 return ArgClassification::getIndirect(
info.getIndirectAlign(),
551 info.getIndirectByVal());
552 assert(
info.isIgnore() &&
"Unexpected classification");
553 return ArgClassification::getIgnore();
560static llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy) {
561 if (!fnTy.isVarArg())
562 return llvm::abi::RequiredArgs::All;
563 return llvm::abi::RequiredArgs(fnTy.getNumInputs());
574static std::optional<FunctionClassification> classifyX86_64Signature(
575 mlir::Type retCIR, mlir::TypeRange inputs, llvm::abi::RequiredArgs required,
576 MLIRContext *ctx,
const DataLayout &dl,
577 mlir::abi::ABITypeMapper &typeMapper,
578 const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp,
579 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
580 assert(retCIR &&
"signature return type must be non-null");
581 assert((!required.allowsOptionalArgs() ||
582 required.getNumRequiredArgs() <= inputs.size()) &&
583 "declared parameters cannot outnumber the classified arguments");
584 bool voidRet = isa<cir::VoidType>(retCIR);
586 auto reject = [&](mlir::Type t) ->
bool {
587 if (isSupportedType(t, dl))
590 <<
"x86_64 calling-convention lowering not yet implemented for type "
594 if (!voidRet && reject(retCIR))
596 for (mlir::Type a : inputs)
600 const llvm::abi::Type *retAbi =
601 voidRet ? typeMapper.getTypeBuilder().getVoidType()
602 : mapCIRType(retCIR, typeMapper, dl, modOp);
604 for (mlir::Type a : inputs)
605 argAbi.push_back(mapCIRType(a, typeMapper, dl, modOp));
607 std::unique_ptr<llvm::abi::FunctionInfo> fi = llvm::abi::FunctionInfo::create(
608 llvm::CallingConv::C, retAbi, argAbi, required);
609 targetInfo.computeInfo(*fi);
613 auto nyiCoercion = [&](mlir::Type t) {
614 emitError() <<
"x86_64 calling-convention lowering not yet "
615 "implemented for the ABI coercion of type "
619 FunctionClassification fc;
620 fc.returnsVoid = voidRet;
621 mlir::Type origRet = voidRet ? mlir::Type() : retCIR;
622 std::optional<ArgClassification> retAc =
623 convertABIArgInfo(fi->getReturnInfo(), ctx, origRet);
628 fc.returnInfo = *retAc;
629 for (
unsigned i = 0, e = fi->arg_size(); i < e; ++i) {
630 mlir::Type origArg = i < inputs.size() ? inputs[i] : mlir::Type();
631 std::optional<ArgClassification> ac =
632 convertABIArgInfo(fi->getArgInfo(i).Info, ctx, origArg);
634 nyiCoercion(origArg);
637 fc.argInfos.push_back(*ac);
644static llvm::abi::X86AVXABILevel funcAvxLevel(cir::FuncOp func,
645 llvm::abi::X86AVXABILevel base) {
650 auto features = func->getAttrOfType<mlir::StringAttr>(
"cir.target-features");
657 for (llvm::StringRef feature : llvm::split(features.getValue(),
',')) {
658 if (!feature.consume_front(
"+"))
660 if (feature ==
"avx512f")
661 return std::max(base, llvm::abi::X86AVXABILevel::AVX512);
662 avx |= feature ==
"avx";
664 return avx ? std::max(base, llvm::abi::X86AVXABILevel::AVX) : base;
670static std::optional<FunctionClassification>
671classifyX86_64Function(cir::FuncOp func,
const DataLayout &dl,
672 mlir::abi::ABITypeMapper &typeMapper,
673 const llvm::abi::TargetInfo &targetInfo,
675 cir::FuncType fnTy = func.getFunctionType();
676 return classifyX86_64Signature(fnTy.getReturnType(), fnTy.getInputs(),
677 requiredArgs(fnTy), func->getContext(), dl,
678 typeMapper, targetInfo, modOp,
679 [&]() { return func.emitOpError(); });
689static std::optional<FunctionClassification> classifyX86_64VariadicCall(
690 cir::CIRCallOpInterface call, cir::FuncType calleeTy,
const DataLayout &dl,
691 mlir::abi::ABITypeMapper &typeMapper,
692 const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp) {
693 assert(calleeTy.isVarArg() &&
694 "only a variadic callee can take more operands than it declares");
695 Operation *op = call.getOperation();
696 return classifyX86_64Signature(
697 calleeTy.getReturnType(), call.getArgOperands().getTypes(),
698 requiredArgs(calleeTy), op->getContext(), dl, typeMapper, targetInfo,
699 modOp, [&]() { return op->emitOpError(); });
709static bool classifiesSamePrefix(
const FunctionClassification &calleeFc,
710 const FunctionClassification &callFc) {
711 if (callFc.argInfos.size() < calleeFc.argInfos.size())
713 return calleeFc.returnInfo == callFc.returnInfo &&
714 std::equal(calleeFc.argInfos.begin(), calleeFc.argInfos.end(),
715 callFc.argInfos.begin());
719struct CallConvLoweringPass
720 :
public impl::CallConvLoweringBase<CallConvLoweringPass> {
721 using CallConvLoweringBase::CallConvLoweringBase;
723 CallConvLoweringPass(
const CallConvLoweringOptions &options,
724 const llvm::abi::ABICompatInfo &x86AbiCompat)
725 : CallConvLoweringBase(options), x86AbiCompat(x86AbiCompat) {}
727 void runOnOperation()
override;
733 llvm::abi::ABICompatInfo x86AbiCompat;
742static std::optional<FunctionClassification>
743withReturnVoidness(std::optional<FunctionClassification> fc,
744 mlir::Type returnType) {
746 fc->returnsVoid = mlir::isa<cir::VoidType>(returnType);
754std::optional<FunctionClassification>
755classifyFunction(cir::FuncOp func,
const DataLayout &dl,
758 Type returnType = func.getFunctionType().getReturnType();
760 if (!classificationAttrName.empty()) {
761 auto attr = func->getAttrOfType<DictionaryAttr>(classificationAttrName);
764 <<
"missing classification attribute '" << classificationAttrName
765 <<
"' (CallConvLowering driver mode 'classification-attr')";
768 return withReturnVoidness(mlir::abi::test::parseClassificationAttr(
769 attr, [&]() {
return func.emitOpError(); }),
776 "classifyFunction only handles the test target");
777 return withReturnVoidness(mlir::abi::test::classify(argTypes, returnType, dl),
786cir::FuncOp lookupCallee(Operation *callOp, SymbolTable &symbolTable) {
787 FlatSymbolRefAttr callee;
788 if (
auto call = dyn_cast<cir::CallOp>(callOp))
789 callee = call.getCalleeAttr();
790 else if (
auto tryCall = dyn_cast<cir::TryCallOp>(callOp))
791 callee = tryCall.getCalleeAttr();
796 return symbolTable.lookup<cir::FuncOp>(callee.getValue());
804cir::FuncType indirectCalleeType(cir::CIRCallOpInterface call) {
805 if (!call.isIndirect())
807 return cast<cir::FuncType>(
808 cast<cir::PointerType>(call.getIndirectCall().getType()).getPointee());
811void CallConvLoweringPass::runOnOperation() {
812 ModuleOp moduleOp = getOperation();
813 MLIRContext *ctx = &getContext();
816 bool haveAttr = !classificationAttr.empty();
817 if (haveTarget == haveAttr) {
818 moduleOp.emitOpError() <<
"CallConvLowering requires exactly one of "
819 "'target' or 'classification-attr' pass options";
824 if (!moduleOp->hasAttr(DLTIDialect::kDataLayoutAttrName)) {
825 moduleOp.emitOpError()
826 <<
"CallConvLowering requires a DataLayout (dlti.dl_spec attribute "
832 DataLayout dl(moduleOp);
833 CIRABIRewriteContext rewriteCtx(moduleOp, dl);
834 SymbolTable symbolTable(moduleOp);
838 static constexpr unsigned numAvxLevels =
839 static_cast<unsigned>(llvm::abi::X86AVXABILevel::Last) + 1;
841 std::optional<mlir::abi::ABITypeMapper> x86TypeMapper;
842 std::array<std::unique_ptr<llvm::abi::TargetInfo>, numAvxLevels> x86Targets;
844 x86TypeMapper.emplace(dl);
846 [&](llvm::abi::X86AVXABILevel level) ->
const llvm::abi::TargetInfo & {
847 assert(
static_cast<unsigned>(level) < numAvxLevels &&
848 "a new X86AVXABILevel must move X86AVXABILevel::Last");
849 std::unique_ptr<llvm::abi::TargetInfo> &slot =
850 x86Targets[
static_cast<unsigned>(level)];
852 slot = llvm::abi::createX86_64TargetInfo(
853 x86TypeMapper->getTypeBuilder(), level,
857 llvm::abi::X86AVXABILevel baseAvxLevel = x86AvxAbiLevel.getValue();
858 auto avxLevelFor = [&](cir::FuncOp func) -> llvm::abi::X86AVXABILevel {
861 return funcAvxLevel(func, baseAvxLevel);
867 llvm::MapVector<cir::FuncOp, FunctionClassification> classifications;
868 bool anyFailed =
false;
869 moduleOp.walk([&](cir::FuncOp f) {
874 cir::FuncType fnTy = f.getFunctionType();
875 if (f.isDeclaration() &&
876 (hasIncompleteRecordByValue(fnTy.getReturnType()) ||
877 llvm::any_of(fnTy.getInputs(), hasIncompleteRecordByValue)))
879 std::optional<FunctionClassification> fc;
881 fc = classifyX86_64Function(f, dl, *x86TypeMapper,
882 x86TargetFor(avxLevelFor(f)), moduleOp);
884 fc = classifyFunction(f, dl, target, classificationAttr);
889 classifications.insert({f, std::move(*fc)});
905 llvm::DenseMap<cir::FuncOp, SmallVector<Operation *>> callers;
909 llvm::DenseMap<Operation *, FunctionClassification> variadicCallSites;
910 moduleOp.walk([&](Operation *op) {
911 auto call = dyn_cast<cir::CIRCallOpInterface>(op);
914 cir::FuncOp callee = lookupCallee(op, symbolTable);
917 callers[callee].push_back(op);
922 cir::FuncType calleeTy = callee.getFunctionType();
923 if (!isX86 || call.getNumArgOperands() <= calleeTy.getNumInputs())
929 if (!calleeTy.isVarArg()) {
930 op->emitOpError() <<
"extra arguments to a callee without a prototype "
931 "not yet implemented in CallConvLowering";
940 std::optional<FunctionClassification> fc =
941 classifyX86_64VariadicCall(call, calleeTy, dl, *x86TypeMapper,
942 x86TargetFor(avxLevelFor(callee)), moduleOp);
947 variadicCallSites.insert({op, std::move(*fc)});
960 llvm::DenseMap<cir::FuncOp, SmallVector<cir::GetGlobalOp>> addressTakers;
961 moduleOp.walk([&](cir::GetGlobalOp getGlobal) {
962 auto ptrTy = cast<cir::PointerType>(getGlobal.getAddr().getType());
963 if (!isa<cir::FuncType>(ptrTy.getPointee()))
968 auto callee = cast<cir::FuncOp>(symbolTable.lookup(getGlobal.getName()));
969 addressTakers[callee].push_back(getGlobal);
983 OpBuilder builder(ctx);
984 for (
auto &kv : classifications) {
985 cir::FuncOp func = kv.first;
986 const FunctionClassification &fc = kv.second;
987 if (failed(rewriteCtx.rewriteFunctionDefinition(func, fc, builder))) {
991 for (Operation *callOp : callers.lookup(func)) {
992 const FunctionClassification *callFc = &fc;
993 if (
auto it = variadicCallSites.find(callOp);
994 it != variadicCallSites.end()) {
995 callFc = &it->second;
996 assert(classifiesSamePrefix(fc, *callFc) &&
997 "a call site's declared parameters must be classified the same "
998 "way as the callee's");
1000 if (failed(rewriteCtx.rewriteCallSite(callOp, *callFc, builder))) {
1001 signalPassFailure();
1005 for (cir::GetGlobalOp addrOp : addressTakers.lookup(func))
1006 rewriteCtx.rewriteFunctionAddress(addrOp, func, builder);
1015 SmallVector<cir::CIRCallOpInterface> indirectCalls;
1016 moduleOp.walk([&](cir::CIRCallOpInterface c) {
1017 if (indirectCalleeType(c))
1018 indirectCalls.push_back(c);
1020 for (cir::CIRCallOpInterface c : indirectCalls) {
1024 if (!classificationAttr.empty()) {
1025 c->emitOpError() <<
"indirect call cannot be classified in the "
1026 "'classification-attr' driver mode";
1027 signalPassFailure();
1030 cir::FuncType funcTy = indirectCalleeType(c);
1031 auto classifySignature =
1032 [&](mlir::TypeRange argTypes) -> std::optional<FunctionClassification> {
1037 return classifyX86_64Signature(
1038 funcTy.getReturnType(), argTypes, requiredArgs(funcTy), ctx, dl,
1040 x86TargetFor(avxLevelFor(c->getParentOfType<cir::FuncOp>())),
1041 moduleOp, [&]() { return c->emitOpError(); });
1042 return withReturnVoidness(
1043 mlir::abi::test::classify(argTypes, funcTy.getReturnType(), dl),
1044 funcTy.getReturnType());
1053 if (c.getNumArgOperands() > funcTy.getNumInputs()) {
1054 std::optional<FunctionClassification> callFc =
1055 classifySignature(c.getArgOperands().getTypes());
1057 signalPassFailure();
1060 if (!callFc->needsRewrite())
1062 c->emitOpError() <<
"variadic arguments to an indirect call not yet "
1063 "implemented in CallConvLowering";
1064 signalPassFailure();
1068 std::optional<FunctionClassification> fc =
1069 classifySignature(funcTy.getInputs());
1071 signalPassFailure();
1074 if (failed(rewriteCtx.rewriteCallSite(c.getOperation(), *fc, builder))) {
1075 signalPassFailure();
1084 return std::make_unique<CallConvLoweringPass>();
1090 CallConvLoweringOptions options;
1091 options.target = target;
1092 options.x86AvxAbiLevel = x86AvxAbiLevel;
1094 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...
bool isZeroWidthBitField(mlir::Type memberTy, RecordMemberKind kind)
Whether a record member is a zero-width bit-field, spelled as a zero-length array of the bit-field's ...
bool holdsDataForABI(mlir::Type memberTy, RecordMemberKind kind)
Whether a member holds data for argument passing.
bool isBitFieldAccessUnit(RecordMemberKind kind)
Whether a member of this kind is a bit-field access unit holding data.
static bool allowsX86TargetAttrAvx(const clang::ASTContext &astContext)
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
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()