clang 24.0.0git
CIRABIClassifier.cpp
Go to the documentation of this file.
1//===- CIRABIClassifier.cpp - ABI classification for CIR ------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the classification shared by the targets that classify
10// through the LLVM ABI Lowering Library, and the two test drivers that stand
11// in for a target.
12//
13//===----------------------------------------------------------------------===//
14
15#include "CIRABIClassifier.h"
17
18#include "mlir/ABI/Targets/Test/TestTarget.h"
20
21using namespace mlir;
22using namespace mlir::abi;
23using namespace cir;
24
25/// FIXME: Only the AMDGPU kernel convention is mapped. Every other convention
26/// is classified as C.
27llvm::CallingConv::ID cir::convertCallingConv(cir::CallingConv cc) {
28 if (cc == cir::CallingConv::AMDGPUKernel)
29 return llvm::CallingConv::AMDGPU_KERNEL;
30 return llvm::CallingConv::C;
31}
32
33std::optional<FunctionClassification>
35 cir::FuncOp callee) {
36 return classifyVariadicCall(call, callee.getFunctionType(),
37 getTargetInfo(callee),
38 convertCallingConv(callee.getCallingConv()));
39}
40
41std::optional<FunctionClassification>
42CIRABIClassifierCommon::classifyIndirectCall(cir::CIRCallOpInterface call) {
43 cir::FuncType funcTy = getIndirectCalleeType(call);
44 const llvm::abi::TargetInfo &targetInfo =
45 getTargetInfo(call->getParentOfType<cir::FuncOp>());
46 // An indirect callee is an ordinary function pointer, so it uses the C
47 // convention.
48 if (call.getNumArgOperands() > funcTy.getNumInputs())
49 return classifyVariadicCall(call, funcTy, targetInfo, llvm::CallingConv::C);
50 return classifySignature(
51 funcTy.getReturnType(), funcTy.getInputs(), requiredArgs(funcTy),
52 targetInfo, llvm::CallingConv::C, [&]() { return call->emitOpError(); });
53}
54
55namespace {
56
57/// Classifies with the MLIR test ABI target: predictable rules that
58/// approximate x86_64 SysV, used by tests that need a target-independent
59/// driver.
60class TestTargetClassifier final : public CIRABIClassifier {
61public:
62 explicit TestTargetClassifier(const mlir::DataLayout &dl) : dl(dl) {}
63
64 std::optional<FunctionClassification>
65 classifyFunction(cir::FuncOp func) final {
67 /*classificationAttrName=*/"");
68 }
69
70 /// The test target classifies only declared parameters.
71 std::optional<FunctionClassification>
72 classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp) final {
73 call->emitOpError()
74 << "variadic arguments not yet implemented in CallConvLowering";
75 return std::nullopt;
76 }
77
78 std::optional<FunctionClassification>
79 classifyIndirectCall(cir::CIRCallOpInterface call) final {
80 cir::FuncType funcTy = getIndirectCalleeType(call);
81 if (call.getNumArgOperands() > funcTy.getNumInputs()) {
82 call->emitOpError()
83 << "variadic arguments not yet implemented in CallConvLowering";
84 return std::nullopt;
85 }
86 return withReturnVoidness(mlir::abi::test::classify(funcTy.getInputs(),
87 funcTy.getReturnType(),
88 dl),
89 funcTy.getReturnType());
90 }
91
92 std::optional<ArgClassification> classifyVAArg(cir::VAArgOp vaArg) final {
93 vaArg->emitOpError()
94 << "not yet implemented in CallConvLowering for the test target";
95 return std::nullopt;
96 }
97
98private:
99 const mlir::DataLayout &dl;
100};
101
102/// Reads a pre-built classification from a function attribute, so a test can
103/// inject any classification (including shapes no target produces) without
104/// depending on a real ABI target.
105class InjectedClassifier final : public CIRABIClassifier {
106public:
107 InjectedClassifier(const mlir::DataLayout &dl, llvm::StringRef attrName)
108 : dl(dl), attrName(attrName) {}
109
110 std::optional<FunctionClassification>
111 classifyFunction(cir::FuncOp func) final {
112 return cir::classifyFunction(func, dl, cir::CallConvTarget::None, attrName);
113 }
114
115 /// The injected classification covers a function's declared parameters, so
116 /// it cannot describe an operand passed through an ellipsis.
117 std::optional<FunctionClassification>
118 classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp) final {
119 call->emitOpError()
120 << "variadic arguments not yet implemented in CallConvLowering";
121 return std::nullopt;
122 }
123
124 /// Nor can it describe a callee resolved at run time, which names no
125 /// function to read the attribute from.
126 std::optional<FunctionClassification>
127 classifyIndirectCall(cir::CIRCallOpInterface call) final {
128 call->emitOpError() << "indirect call cannot be classified in the "
129 "'classification-attr' driver mode";
130 return std::nullopt;
131 }
132
133 std::optional<ArgClassification> classifyVAArg(cir::VAArgOp vaArg) final {
134 vaArg->emitOpError() << "cannot be classified in the "
135 "'classification-attr' driver mode";
136 return std::nullopt;
137 }
138
139private:
140 const mlir::DataLayout &dl;
141 std::string attrName;
142};
143
144} // namespace
145
146std::unique_ptr<CIRABIClassifier>
147cir::createTestTargetABIClassifier(const mlir::DataLayout &dl) {
148 return std::make_unique<TestTargetClassifier>(dl);
149}
150
151std::unique_ptr<CIRABIClassifier>
152cir::createInjectedABIClassifier(const mlir::DataLayout &dl,
153 llvm::StringRef attrName) {
154 return std::make_unique<InjectedClassifier>(dl, attrName);
155}
std::optional< mlir::abi::FunctionClassification > classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp callee) override
The call is classified at the callee's features, not the caller's, because the pass rewrites the defi...
std::optional< 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...
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.
Produces the classification CallConvLowering rewrites a signature from.
std::optional< mlir::abi::FunctionClassification > withReturnVoidness(std::optional< mlir::abi::FunctionClassification > fc, mlir::Type returnType)
Record on fc whether returnType is CIR's void.
llvm::CallingConv::ID convertCallingConv(cir::CallingConv cc)
Map a CIR calling convention to the llvm::CallingConv the ABI classifier uses.
cir::FuncType getIndirectCalleeType(cir::CIRCallOpInterface call)
The signature the indirect call call reaches its callee through.
std::optional< mlir::abi::FunctionClassification > classifyFunction(cir::FuncOp func, const mlir::DataLayout &dl, cir::CallConvTarget target, llvm::StringRef classificationAttrName)
Classify func with the test target, or from the attribute named classificationAttrName when that is n...
std::unique_ptr< CIRABIClassifier > createInjectedABIClassifier(const mlir::DataLayout &dl, llvm::StringRef attrName)
A classifier that reads each function's classification from the DictionaryAttr named attrName.
std::unique_ptr< CIRABIClassifier > createTestTargetABIClassifier(const mlir::DataLayout &dl)
The MLIR test ABI target's classifier, whose predictable rules approximate x86_64 SysV.
llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy)
Where fnTy's declared parameters end and its ellipsis arguments begin.