-
Notifications
You must be signed in to change notification settings - Fork 140
/
Copy pathLowerModule.cpp
247 lines (205 loc) · 8.72 KB
/
LowerModule.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
//===--- LowerModule.cpp - Lower CIR Module to a Target -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file partially mimics clang/lib/CodeGen/CodeGenModule.cpp. The queries
// are adapted to operate on the CIR dialect, however.
//
//===----------------------------------------------------------------------===//
// FIXME(cir): This header file is not exposed to the public API, but can be
// reused by CIR ABI lowering since it holds target-specific information.
#include "../../../../Basic/Targets.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "CIRLowerContext.h"
#include "LowerFunction.h"
#include "LowerModule.h"
#include "TargetInfo.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Support/LogicalResult.h"
#include "clang/CIR/Target/AArch64.h"
#include "llvm/Support/ErrorHandling.h"
using MissingFeatures = cir::MissingFeatures;
using AArch64ABIKind = cir::AArch64ABIKind;
using X86AVXABILevel = cir::X86AVXABILevel;
namespace cir {
static CIRCXXABI *createCXXABI(LowerModule &CGM) {
switch (CGM.getCXXABIKind()) {
case clang::TargetCXXABI::AppleARM64:
case clang::TargetCXXABI::Fuchsia:
case clang::TargetCXXABI::GenericAArch64:
case clang::TargetCXXABI::GenericARM:
case clang::TargetCXXABI::iOS:
case clang::TargetCXXABI::WatchOS:
case clang::TargetCXXABI::GenericMIPS:
case clang::TargetCXXABI::GenericItanium:
case clang::TargetCXXABI::WebAssembly:
case clang::TargetCXXABI::XL:
return CreateItaniumCXXABI(CGM);
case clang::TargetCXXABI::Microsoft:
cir_cconv_unreachable("Windows ABI NYI");
}
cir_cconv_unreachable("invalid C++ ABI kind");
}
static std::unique_ptr<TargetLoweringInfo>
createTargetLoweringInfo(LowerModule &LM) {
const clang::TargetInfo &Target = LM.getTarget();
const llvm::Triple &Triple = Target.getTriple();
switch (Triple.getArch()) {
case llvm::Triple::aarch64_be:
case llvm::Triple::aarch64: {
AArch64ABIKind Kind = AArch64ABIKind::AAPCS;
if (Target.getABI() == "darwinpcs")
cir_cconv_unreachable("DarwinPCS ABI NYI");
else if (Triple.isOSWindows())
cir_cconv_unreachable("Windows ABI NYI");
else if (Target.getABI() == "aapcs-soft")
cir_cconv_unreachable("AAPCS-soft ABI NYI");
return createAArch64TargetLoweringInfo(LM, Kind);
}
case llvm::Triple::x86_64: {
switch (Triple.getOS()) {
case llvm::Triple::Win32:
cir_cconv_unreachable("Windows ABI NYI");
default:
return createX86_64TargetLoweringInfo(LM, X86AVXABILevel::None);
}
}
case llvm::Triple::spirv64:
return createSPIRVTargetLoweringInfo(LM);
default:
cir_cconv_unreachable("ABI NYI");
}
}
LowerModule::LowerModule(clang::LangOptions opts, mlir::ModuleOp &module,
std::unique_ptr<clang::TargetInfo> target,
mlir::PatternRewriter &rewriter)
: context(module, opts), module(module), Target(std::move(target)),
ABI(createCXXABI(*this)), types(*this), rewriter(rewriter) {
context.initBuiltinTypes(*Target);
}
const TargetLoweringInfo &LowerModule::getTargetLoweringInfo() {
if (!TheTargetCodeGenInfo)
TheTargetCodeGenInfo = createTargetLoweringInfo(*this);
return *TheTargetCodeGenInfo;
}
void LowerModule::setCIRFunctionAttributes(FuncOp GD,
const LowerFunctionInfo &Info,
FuncOp F, bool IsThunk) {
unsigned CallingConv;
// NOTE(cir): The method below will update the F function in-place with the
// proper attributes.
constructAttributeList(GD.getName(), Info, GD, F, CallingConv,
/*AttrOnCallSite=*/false, IsThunk);
// TODO(cir): Set Function's calling convention.
}
/// Set function attributes for a function declaration.
///
/// This method is based on CodeGenModule::SetFunctionAttributes but it
/// altered to consider only the ABI/Target-related bits.
void LowerModule::setFunctionAttributes(FuncOp oldFn, FuncOp newFn,
bool IsIncompleteFunction,
bool IsThunk) {
// TODO(cir): There's some special handling from attributes related to LLVM
// intrinsics. Should we do that here as well?
// Setup target-specific attributes.
if (!IsIncompleteFunction)
setCIRFunctionAttributes(oldFn, getTypes().arrangeGlobalDeclaration(oldFn),
newFn, IsThunk);
// TODO(cir): Handle attributes for returned "this" objects.
// NOTE(cir): Skipping some linkage and other global value attributes here as
// it might be better for CIRGen to handle them.
// TODO(cir): Skipping section attributes here.
// TODO(cir): Skipping error attributes here.
// If we plan on emitting this inline builtin, we can't treat it as a builtin.
if (MissingFeatures::funcDeclIsInlineBuiltinDeclaration()) {
cir_cconv_unreachable("NYI");
}
if (MissingFeatures::funcDeclIsReplaceableGlobalAllocationFunction()) {
cir_cconv_unreachable("NYI");
}
if (MissingFeatures::funcDeclIsCXXConstructorDecl() ||
MissingFeatures::funcDeclIsCXXDestructorDecl())
cir_cconv_unreachable("NYI");
else if (MissingFeatures::funcDeclIsCXXMethodDecl())
cir_cconv_unreachable("NYI");
// NOTE(cir) Skipping emissions that depend on codegen options, as well as
// sanitizers handling here. Do this in CIRGen.
if (MissingFeatures::langOpts() && MissingFeatures::openMP())
cir_cconv_unreachable("NYI");
// NOTE(cir): Skipping more things here that depend on codegen options.
if (MissingFeatures::extParamInfo()) {
cir_cconv_unreachable("NYI");
}
}
/// Rewrites an existing function to conform to the ABI.
///
/// This method is based on CodeGenModule::EmitGlobalFunctionDefinition but it
/// considerably simplified as it tries to remove any CodeGen related code.
llvm::LogicalResult LowerModule::rewriteFunctionDefinition(FuncOp op) {
mlir::OpBuilder::InsertionGuard guard(rewriter);
rewriter.setInsertionPoint(op);
// Get ABI/target-specific function information.
const LowerFunctionInfo &FI = this->getTypes().arrangeGlobalDeclaration(op);
// Get ABI/target-specific function type.
FuncType Ty = this->getTypes().getFunctionType(FI);
// NOTE(cir): Skipping getAddrOfFunction and getOrCreateCIRFunction methods
// here, as they are mostly codegen logic.
// Create a new function with the ABI-specific types.
FuncOp newFn = mlir::cast<FuncOp>(rewriter.cloneWithoutRegions(op));
newFn.setType(Ty);
// NOTE(cir): The clone above will preserve any existing attributes. If there
// are high-level attributes that ought to be dropped, do it here.
// Set up ABI-specific function attributes.
setFunctionAttributes(op, newFn, false, /*IsThunk=*/false);
if (MissingFeatures::extParamInfo()) {
cir_cconv_unreachable("ExtraAttrs are NYI");
}
// Is a function definition: handle the body.
if (!op.isDeclaration()) {
if (LowerFunction(*this, rewriter, op, newFn)
.generateCode(op, newFn, FI)
.failed())
return llvm::failure();
}
// Erase original ABI-agnostic function.
rewriter.eraseOp(op);
return llvm::success();
}
llvm::LogicalResult LowerModule::rewriteFunctionCall(CallOp callOp,
FuncOp funcOp) {
mlir::OpBuilder::InsertionGuard guard(rewriter);
rewriter.setInsertionPoint(callOp);
// Create a new function with the ABI-specific calling convention.
if (LowerFunction(*this, rewriter, funcOp, callOp)
.rewriteCallOp(callOp)
.failed())
return llvm::failure();
return llvm::success();
}
// TODO: not to create it every time
std::unique_ptr<LowerModule>
createLowerModule(mlir::ModuleOp module, mlir::PatternRewriter &rewriter) {
// Fetch target information.
llvm::Triple triple(mlir::cast<mlir::StringAttr>(
module->getAttr(cir::CIRDialect::getTripleAttrName()))
.getValue());
clang::TargetOptions targetOptions;
targetOptions.Triple = triple.str();
auto targetInfo = clang::targets::AllocateTarget(triple, targetOptions);
// FIXME(cir): This just uses the default language options. We need to account
// for custom options.
// Create context.
cir_cconv_assert(!cir::MissingFeatures::langOpts());
clang::LangOptions langOpts;
return std::make_unique<LowerModule>(langOpts, module, std::move(targetInfo),
rewriter);
}
} // namespace cir