clang 24.0.0git
CIRABIRewriteContext.h
Go to the documentation of this file.
1//===- CIRABIRewriteContext.h - CIR ABI rewrite context ---------*- 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// Defines CIRABIRewriteContext, the CIR dialect's implementation of the
10// generic mlir::abi::ABIRewriteContext. Given a FunctionClassification it
11// rewrites a cir.func signature, the function body, and call sites to match
12// the ABI-lowered shape.
13//
14// This file handles Direct (pass-through and coerce-in-registers), Extend,
15// Ignore, Indirect (sret return, byval and non-byval arguments), and Expand
16// (struct flattening into scalar fields).
17//
18//===----------------------------------------------------------------------===//
19
20#ifndef CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRABIREWRITECONTEXT_H
21#define CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRABIREWRITECONTEXT_H
22
23#include "mlir/ABI/ABIRewriteContext.h"
24#include "mlir/Analysis/AliasAnalysis.h"
25#include "mlir/IR/BuiltinOps.h"
26#include "mlir/Interfaces/DataLayoutInterfaces.h"
29#include "llvm/ADT/SmallVector.h"
30#include <cassert>
31#include <utility>
32
33namespace cir {
34
35/// CIR-specific implementation of mlir::abi::ABIRewriteContext.
36///
37/// The driver pass (CallConvLoweringPass) computes a FunctionClassification
38/// for each cir.func / cir.call and dispatches to this class to perform the
39/// actual IR rewriting using cir dialect operations.
40///
41/// Holds a reference to the module's DataLayout for coercion alignment
42/// queries. The DataLayout must outlive the rewrite context.
44public:
45 CIRABIRewriteContext(mlir::ModuleOp module, const mlir::DataLayout &dl)
46 : module(module), dl(dl), aliasAnalysis(module) {
47 cir::registerCIRAliasAnalyses(aliasAnalysis, module);
48 }
49
51 assert(pendingParamSlots.empty() &&
52 "finalizeParameterSlots must run before the rewrite context dies");
53 }
54
55 mlir::LogicalResult
56 rewriteFunctionDefinition(mlir::FunctionOpInterface funcOp,
57 const mlir::abi::FunctionClassification &fc,
58 mlir::OpBuilder &builder) override;
59
60 mlir::LogicalResult
61 rewriteCallSite(mlir::Operation *callOp,
62 const mlir::abi::FunctionClassification &fc,
63 mlir::OpBuilder &builder) override;
64
65 /// Expand a `cir.va_arg` into the x86-64 SysV register-save-area /
66 /// overflow-area sequence.
67 mlir::LogicalResult rewriteVAArg(mlir::Operation *vaArgOp,
68 const mlir::abi::ArgClassification &ac,
69 mlir::OpBuilder &builder) override;
70
71 /// Retype \p addrOp, which holds the address of \p funcOp, to the signature
72 /// funcOp was rewritten to, and cast it back so existing uses keep the type
73 /// they were built for. A no-op when the ABI left funcOp's type alone.
74 /// Call after funcOp has been rewritten. Not an override, since taking a
75 /// function's address has no counterpart in the generic contract.
76 void rewriteFunctionAddress(cir::GetGlobalOp addrOp, cir::FuncOp funcOp,
77 mlir::OpBuilder &builder);
78
79 /// Bring each non-byval indirect parameter of \p funcOp into the shape the
80 /// rest of the rewrite assumes: the parameter's only use, if it has one, is
81 /// a single store into an alloca of the matching pointer type that no other
82 /// non-byval indirect parameter spills to, and that alloca states the
83 /// alignment the ABI promises rather than the one CIRGen picked for a local
84 /// copy. A use of the parameter as a call argument is routed through a load
85 /// of that slot, so that it names the storage an argument has to name.
86 ///
87 /// Call for every function before any definition or call site is rewritten.
88 /// findParamSpill asserts this shape while the enclosing definition is
89 /// rewritten, and a call is rewritten with its callee rather than with its
90 /// enclosing function and so may be reached first.
91 ///
92 /// A parameter read with no spill to name is given one, since it becomes
93 /// the incoming pointer directly. A parameter spilled twice, spilled to a
94 /// slot another such parameter also spills to, consumed other than as a
95 /// call argument, spilled where the incoming pointer cannot replace the
96 /// storage, or read where the spill does not dominate it gets a diagnostic
97 /// on the operation at fault and failure.
98 ///
99 /// Not an override, since this has no counterpart in the generic contract.
100 mlir::LogicalResult
101 prepareNonByvalParameters(cir::FuncOp funcOp,
102 const mlir::abi::FunctionClassification &fc);
103
104 /// Replace each non-byval indirect parameter's spill slot with the
105 /// incoming pointer, so the body operates on the caller's storage in place.
106 /// Call once, after every function and call site has been rewritten: a call
107 /// forwarding such a parameter reads the slot to recognize it. Not an
108 /// override, since deferring this has no counterpart in the generic
109 /// contract.
111
112 mlir::StringRef getDialectNamespace() const override { return "cir"; }
113
114private:
115 mlir::ModuleOp module;
116 const mlir::DataLayout &dl;
117
118 /// Alias analysis over the module with the CIR implementations registered.
119 /// rewriteCallSite asks it whether a byval operand's storage is written
120 /// between its load and the call.
121 mlir::AliasAnalysis aliasAnalysis;
122
123 /// Param-slot allocas that non-byval indirect parameters will
124 /// replace, paired with the incoming pointer that replaces them. The
125 /// rewrite retypes the block argument but leaves the slot standing, because
126 /// a call site recognizes a forwardable parameter by the slot its operand
127 /// was loaded from. finalizeParameterSlots does the replacement once every
128 /// call site has been rewritten.
130 pendingParamSlots;
131};
132
133/// The signature the indirect call \p call reaches its callee through.
134cir::FuncType getIndirectCalleeType(cir::CIRCallOpInterface call);
135
136} // namespace cir
137
138#endif // CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRABIREWRITECONTEXT_H
void rewriteFunctionAddress(cir::GetGlobalOp addrOp, cir::FuncOp funcOp, mlir::OpBuilder &builder)
Retype addrOp, which holds the address of funcOp, to the signature funcOp was rewritten to,...
mlir::LogicalResult rewriteFunctionDefinition(mlir::FunctionOpInterface funcOp, const mlir::abi::FunctionClassification &fc, mlir::OpBuilder &builder) override
void finalizeParameterSlots()
Replace each non-byval indirect parameter's spill slot with the incoming pointer, so the body operate...
mlir::StringRef getDialectNamespace() const override
mlir::LogicalResult prepareNonByvalParameters(cir::FuncOp funcOp, const mlir::abi::FunctionClassification &fc)
Bring each non-byval indirect parameter of funcOp into the shape the rest of the rewrite assumes: the...
CIRABIRewriteContext(mlir::ModuleOp module, const mlir::DataLayout &dl)
mlir::LogicalResult rewriteVAArg(mlir::Operation *vaArgOp, const mlir::abi::ArgClassification &ac, mlir::OpBuilder &builder) override
Expand a cir.va_arg into the x86-64 SysV register-save-area / overflow-area sequence.
mlir::LogicalResult rewriteCallSite(mlir::Operation *callOp, const mlir::abi::FunctionClassification &fc, mlir::OpBuilder &builder) override
void registerCIRAliasAnalyses(mlir::AliasAnalysis &aa, mlir::Operation *op)
Register all CIR alias analysis implementations with aa, which answers queries about values within op...
cir::FuncType getIndirectCalleeType(cir::CIRCallOpInterface call)
The signature the indirect call call reaches its callee through.