MLIR 24.0.0git
ABIRewriteContext.h
Go to the documentation of this file.
1//===- ABIRewriteContext.h - Dialect-specific ABI rewriting -----*- C++ -*-===//
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 defines ABIRewriteContext, the abstract interface for dialect-
10// specific ABI lowering rewrites. Each MLIR dialect that wants ABI lowering
11// (CIR, FIR, etc.) provides a concrete subclass.
12//
13// ABIRewriteContext consumes ABI classification results and drives the
14// creation of lowered function signatures, argument coercions, and call
15// site rewrites using dialect-specific operations.
16//
17//===----------------------------------------------------------------------===//
18
19#ifndef MLIR_ABI_ABIREWRITECONTEXT_H
20#define MLIR_ABI_ABIREWRITECONTEXT_H
21
22#include "mlir/IR/Builders.h"
23#include "mlir/IR/Operation.h"
24#include "mlir/IR/Types.h"
25#include "mlir/IR/Value.h"
27#include "llvm/ADT/STLExtras.h"
28#include "llvm/Support/Alignment.h"
29
30namespace mlir {
31namespace abi {
32
33/// Classification of how a single argument or return value should be
34/// passed at the ABI level.
35///
36/// This is a dialect-agnostic representation. It mirrors the kinds
37/// found in the LLVM ABI library and in CIR's ABIArgInfo, but does
38/// not depend on either.
39enum class ArgKind : uint8_t {
40 /// Pass directly in registers, possibly coerced to a different type.
42
43 /// Like Direct, but with a sign/zero extension attribute.
45
46 /// Pass indirectly via a pointer (sret for returns, byval for args).
48
49 /// Ignore (void return, empty struct).
51
52 /// Expand an aggregate into its constituent scalar fields.
54};
55
56/// Describes how a single argument or return value is passed after ABI
57/// lowering.
60
61 /// The ABI-coerced type, if different from the original. Null means
62 /// use the original type.
63 Type coercedType = nullptr;
64
65 /// For Indirect: alignment of the pointed-to object.
66 llvm::Align indirectAlign = llvm::Align(1);
67
68 /// For Extend: whether to sign-extend (true) or zero-extend (false).
69 bool signExtend = false;
70
71 /// For Direct: whether a struct coercion can be flattened into
72 /// individual register-width arguments.
73 bool canFlatten = true;
74
75 /// For Indirect: whether the callee gets ownership (byval).
76 bool byVal = false;
77
78 /// Whether the value is passed as-is, so a rewriter can leave it alone.
79 /// Only an uncoerced Direct qualifies. Extend counts as needing a rewrite
80 /// even though it only adds an attribute, because the attribute changes
81 /// observable behavior.
82 bool isPassThrough() const { return kind == ArgKind::Direct && !coercedType; }
83
84 /// Whether two classifications describe the same wire format. Every field
85 /// participates, so a field added above must be added here as well.
86 bool operator==(const ArgClassification &other) const {
87 return kind == other.kind && coercedType == other.coercedType &&
89 signExtend == other.signExtend && canFlatten == other.canFlatten &&
90 byVal == other.byVal;
91 }
92
93 static ArgClassification getDirect(Type coerced = nullptr) {
96 c.coercedType = coerced;
97 return c;
98 }
99
103 return c;
104 }
105
106 static ArgClassification getIndirect(llvm::Align align, bool byVal = true) {
109 c.indirectAlign = align;
110 c.byVal = byVal;
111 return c;
112 }
113
114 static ArgClassification getExtend(Type coerced, bool signExt) {
117 c.coercedType = coerced;
118 c.signExtend = signExt;
119 return c;
120 }
121};
122
123/// Holds the full ABI classification for a function: return type and
124/// all arguments.
128
129 /// Whether the classified return type was the source language's void.
130 ///
131 /// A void return classifies as Ignore, and so does a return the ABI drops,
132 /// such as an empty record. The two need opposite treatment: void is
133 /// already its own wire form, while a dropped record return has to be
134 /// rewritten to one. returnInfo alone cannot tell them apart, so whoever
135 /// produces the classification records it here, next to the return type it
136 /// came from. A consumer that re-derived it from something else could pair
137 /// a classification with the wrong answer, and reading a dropped return as
138 /// void means silently skipping the rewrite it needs.
139 ///
140 /// Left false when unknown, which costs a needless rewrite rather than a
141 /// skipped one.
142 bool returnsVoid = false;
143
144 /// Whether any value in the signature is passed differently from how it is
145 /// written, so a rewriter has work to do.
146 bool needsRewrite() const {
147 if (!returnsVoid && !returnInfo.isPassThrough())
148 return true;
149 return !llvm::all_of(argInfos, [](const ArgClassification &ac) {
150 return ac.isPassThrough();
151 });
152 }
153};
154
155/// ABIRewriteContext is the abstract interface that each dialect
156/// implements to perform ABI-specific rewrites on its operations.
157///
158/// The pass orchestrator calls these methods after ABI classification
159/// to rewrite function definitions and call sites.
161public:
162 virtual ~ABIRewriteContext() = default;
163
164 /// Rewrite a function definition to use ABI-lowered types.
165 ///
166 /// This creates a new function with the lowered signature, rewrites
167 /// the function body to adapt between the ABI types and the
168 /// original high-level types, and replaces the original function.
169 ///
170 /// \param funcOp The function to rewrite (via FunctionOpInterface).
171 /// \param fc The ABI classification for this function.
172 /// \param builder The OpBuilder to use for modifications.
173 /// \returns success() if the function was rewritten.
174 virtual LogicalResult
175 rewriteFunctionDefinition(FunctionOpInterface funcOp,
176 const FunctionClassification &fc,
177 OpBuilder &builder) = 0;
178
179 /// Rewrite a call operation to match the callee's ABI-lowered
180 /// signature.
181 ///
182 /// This coerces arguments, handles indirect returns (sret), and
183 /// adapts the call result back to the original high-level type.
184 ///
185 /// \param callOp The call operation to rewrite.
186 /// \param fc The ABI classification for the callee.
187 /// \param builder The OpBuilder to use for modifications.
188 /// \returns success() if the call was rewritten.
189 virtual LogicalResult rewriteCallSite(Operation *callOp,
190 const FunctionClassification &fc,
191 OpBuilder &builder) = 0;
192
193 /// Return the dialect namespace this context handles (e.g. "cir").
194 virtual StringRef getDialectNamespace() const = 0;
195};
196
197} // namespace abi
198} // namespace mlir
199
200#endif // MLIR_ABI_ABIREWRITECONTEXT_H
This class helps build Operations.
Definition Builders.h:210
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
ABIRewriteContext is the abstract interface that each dialect implements to perform ABI-specific rewr...
virtual StringRef getDialectNamespace() const =0
Return the dialect namespace this context handles (e.g. "cir").
virtual ~ABIRewriteContext()=default
virtual LogicalResult rewriteFunctionDefinition(FunctionOpInterface funcOp, const FunctionClassification &fc, OpBuilder &builder)=0
Rewrite a function definition to use ABI-lowered types.
virtual LogicalResult rewriteCallSite(Operation *callOp, const FunctionClassification &fc, OpBuilder &builder)=0
Rewrite a call operation to match the callee's ABI-lowered signature.
ArgKind
Classification of how a single argument or return value should be passed at the ABI level.
@ Indirect
Pass indirectly via a pointer (sret for returns, byval for args).
@ Extend
Like Direct, but with a sign/zero extension attribute.
@ Expand
Expand an aggregate into its constituent scalar fields.
@ Ignore
Ignore (void return, empty struct).
@ Direct
Pass directly in registers, possibly coerced to a different type.
Include the generated interface declarations.
Describes how a single argument or return value is passed after ABI lowering.
static ArgClassification getIgnore()
static ArgClassification getDirect(Type coerced=nullptr)
bool canFlatten
For Direct: whether a struct coercion can be flattened into individual register-width arguments.
bool signExtend
For Extend: whether to sign-extend (true) or zero-extend (false).
static ArgClassification getIndirect(llvm::Align align, bool byVal=true)
bool isPassThrough() const
Whether the value is passed as-is, so a rewriter can leave it alone.
bool operator==(const ArgClassification &other) const
Whether two classifications describe the same wire format.
Type coercedType
The ABI-coerced type, if different from the original.
bool byVal
For Indirect: whether the callee gets ownership (byval).
llvm::Align indirectAlign
For Indirect: alignment of the pointed-to object.
static ArgClassification getExtend(Type coerced, bool signExt)
Holds the full ABI classification for a function: return type and all arguments.
bool returnsVoid
Whether the classified return type was the source language's void.
bool needsRewrite() const
Whether any value in the signature is passed differently from how it is written, so a rewriter has wo...
SmallVector< ArgClassification > argInfos