clang 22.0.0git
LoweringPrepare.cpp
Go to the documentation of this file.
1//===- LoweringPrepare.cpp - pareparation work for LLVM lowering ----------===//
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
10#include "PassDetail.h"
11#include "mlir/IR/Attributes.h"
13#include "clang/Basic/Module.h"
21#include "llvm/Support/Path.h"
22
23#include <memory>
24
25using namespace mlir;
26using namespace cir;
27
28namespace mlir {
29#define GEN_PASS_DEF_LOWERINGPREPARE
30#include "clang/CIR/Dialect/Passes.h.inc"
31} // namespace mlir
32
33static SmallString<128> getTransformedFileName(mlir::ModuleOp mlirModule) {
34 SmallString<128> fileName;
35
36 if (mlirModule.getSymName())
37 fileName = llvm::sys::path::filename(mlirModule.getSymName()->str());
38
39 if (fileName.empty())
40 fileName = "<null>";
41
42 for (size_t i = 0; i < fileName.size(); ++i) {
43 // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
44 // to be the set of C preprocessing numbers.
45 if (!clang::isPreprocessingNumberBody(fileName[i]))
46 fileName[i] = '_';
47 }
48
49 return fileName;
50}
51
52/// Return the FuncOp called by `callOp`.
53static cir::FuncOp getCalledFunction(cir::CallOp callOp) {
54 mlir::SymbolRefAttr sym = llvm::dyn_cast_if_present<mlir::SymbolRefAttr>(
55 callOp.getCallableForCallee());
56 if (!sym)
57 return nullptr;
58 return dyn_cast_or_null<cir::FuncOp>(
59 mlir::SymbolTable::lookupNearestSymbolFrom(callOp, sym));
60}
61
62namespace {
63struct LoweringPreparePass
64 : public impl::LoweringPrepareBase<LoweringPreparePass> {
65 LoweringPreparePass() = default;
66 void runOnOperation() override;
67
68 void runOnOp(mlir::Operation *op);
69 void lowerCastOp(cir::CastOp op);
70 void lowerComplexDivOp(cir::ComplexDivOp op);
71 void lowerComplexMulOp(cir::ComplexMulOp op);
72 void lowerUnaryOp(cir::UnaryOp op);
73 void lowerGlobalOp(cir::GlobalOp op);
74 void lowerDynamicCastOp(cir::DynamicCastOp op);
75 void lowerArrayDtor(cir::ArrayDtor op);
76 void lowerArrayCtor(cir::ArrayCtor op);
77 void lowerTrivialCopyCall(cir::CallOp op);
78
79 /// Build the function that initializes the specified global
80 cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
81
82 /// Handle the dtor region by registering destructor with __cxa_atexit
83 cir::FuncOp getOrCreateDtorFunc(CIRBaseBuilderTy &builder, cir::GlobalOp op,
84 mlir::Region &dtorRegion,
85 cir::CallOp &dtorCall);
86
87 /// Build a module init function that calls all the dynamic initializers.
88 void buildCXXGlobalInitFunc();
89
90 /// Materialize global ctor/dtor list
91 void buildGlobalCtorDtorList();
92
93 cir::FuncOp buildRuntimeFunction(
94 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
95 cir::FuncType type,
96 cir::GlobalLinkageKind linkage = cir::GlobalLinkageKind::ExternalLinkage);
97
98 cir::GlobalOp buildRuntimeVariable(
99 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
100 mlir::Type type,
101 cir::GlobalLinkageKind linkage = cir::GlobalLinkageKind::ExternalLinkage,
102 cir::VisibilityKind visibility = cir::VisibilityKind::Default);
103
104 ///
105 /// AST related
106 /// -----------
107
108 clang::ASTContext *astCtx;
109
110 // Helper for lowering C++ ABI specific operations.
111 std::shared_ptr<cir::LoweringPrepareCXXABI> cxxABI;
112
113 /// Tracks current module.
114 mlir::ModuleOp mlirModule;
115
116 /// Tracks existing dynamic initializers.
117 llvm::StringMap<uint32_t> dynamicInitializerNames;
118 llvm::SmallVector<cir::FuncOp> dynamicInitializers;
119
120 /// List of ctors and their priorities to be called before main()
121 llvm::SmallVector<std::pair<std::string, uint32_t>, 4> globalCtorList;
122 /// List of dtors and their priorities to be called when unloading module.
123 llvm::SmallVector<std::pair<std::string, uint32_t>, 4> globalDtorList;
124
125 void setASTContext(clang::ASTContext *c) {
126 astCtx = c;
127 switch (c->getCXXABIKind()) {
128 case clang::TargetCXXABI::GenericItanium:
129 // We'll need X86-specific support for handling vaargs lowering, but for
130 // now the Itanium ABI will work.
133 break;
134 case clang::TargetCXXABI::GenericAArch64:
135 case clang::TargetCXXABI::AppleARM64:
138 break;
139 default:
140 llvm_unreachable("NYI");
141 }
142 }
143};
144
145} // namespace
146
147cir::GlobalOp LoweringPreparePass::buildRuntimeVariable(
148 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
149 mlir::Type type, cir::GlobalLinkageKind linkage,
150 cir::VisibilityKind visibility) {
151 cir::GlobalOp g = dyn_cast_or_null<cir::GlobalOp>(
152 mlir::SymbolTable::lookupNearestSymbolFrom(
153 mlirModule, mlir::StringAttr::get(mlirModule->getContext(), name)));
154 if (!g) {
155 g = cir::GlobalOp::create(builder, loc, name, type);
156 g.setLinkageAttr(
157 cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
158 mlir::SymbolTable::setSymbolVisibility(
159 g, mlir::SymbolTable::Visibility::Private);
160 g.setGlobalVisibilityAttr(
161 cir::VisibilityAttr::get(builder.getContext(), visibility));
162 }
163 return g;
164}
165
166cir::FuncOp LoweringPreparePass::buildRuntimeFunction(
167 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
168 cir::FuncType type, cir::GlobalLinkageKind linkage) {
169 cir::FuncOp f = dyn_cast_or_null<FuncOp>(SymbolTable::lookupNearestSymbolFrom(
170 mlirModule, StringAttr::get(mlirModule->getContext(), name)));
171 if (!f) {
172 f = cir::FuncOp::create(builder, loc, name, type);
173 f.setLinkageAttr(
174 cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
175 mlir::SymbolTable::setSymbolVisibility(
176 f, mlir::SymbolTable::Visibility::Private);
177
179 }
180 return f;
181}
182
183static mlir::Value lowerScalarToComplexCast(mlir::MLIRContext &ctx,
184 cir::CastOp op) {
185 cir::CIRBaseBuilderTy builder(ctx);
186 builder.setInsertionPoint(op);
187
188 mlir::Value src = op.getSrc();
189 mlir::Value imag = builder.getNullValue(src.getType(), op.getLoc());
190 return builder.createComplexCreate(op.getLoc(), src, imag);
191}
192
193static mlir::Value lowerComplexToScalarCast(mlir::MLIRContext &ctx,
194 cir::CastOp op,
195 cir::CastKind elemToBoolKind) {
196 cir::CIRBaseBuilderTy builder(ctx);
197 builder.setInsertionPoint(op);
198
199 mlir::Value src = op.getSrc();
200 if (!mlir::isa<cir::BoolType>(op.getType()))
201 return builder.createComplexReal(op.getLoc(), src);
202
203 // Complex cast to bool: (bool)(a+bi) => (bool)a || (bool)b
204 mlir::Value srcReal = builder.createComplexReal(op.getLoc(), src);
205 mlir::Value srcImag = builder.createComplexImag(op.getLoc(), src);
206
207 cir::BoolType boolTy = builder.getBoolTy();
208 mlir::Value srcRealToBool =
209 builder.createCast(op.getLoc(), elemToBoolKind, srcReal, boolTy);
210 mlir::Value srcImagToBool =
211 builder.createCast(op.getLoc(), elemToBoolKind, srcImag, boolTy);
212 return builder.createLogicalOr(op.getLoc(), srcRealToBool, srcImagToBool);
213}
214
215static mlir::Value lowerComplexToComplexCast(mlir::MLIRContext &ctx,
216 cir::CastOp op,
217 cir::CastKind scalarCastKind) {
218 CIRBaseBuilderTy builder(ctx);
219 builder.setInsertionPoint(op);
220
221 mlir::Value src = op.getSrc();
222 auto dstComplexElemTy =
223 mlir::cast<cir::ComplexType>(op.getType()).getElementType();
224
225 mlir::Value srcReal = builder.createComplexReal(op.getLoc(), src);
226 mlir::Value srcImag = builder.createComplexImag(op.getLoc(), src);
227
228 mlir::Value dstReal = builder.createCast(op.getLoc(), scalarCastKind, srcReal,
229 dstComplexElemTy);
230 mlir::Value dstImag = builder.createCast(op.getLoc(), scalarCastKind, srcImag,
231 dstComplexElemTy);
232 return builder.createComplexCreate(op.getLoc(), dstReal, dstImag);
233}
234
235void LoweringPreparePass::lowerCastOp(cir::CastOp op) {
236 mlir::MLIRContext &ctx = getContext();
237 mlir::Value loweredValue = [&]() -> mlir::Value {
238 switch (op.getKind()) {
239 case cir::CastKind::float_to_complex:
240 case cir::CastKind::int_to_complex:
241 return lowerScalarToComplexCast(ctx, op);
242 case cir::CastKind::float_complex_to_real:
243 case cir::CastKind::int_complex_to_real:
244 return lowerComplexToScalarCast(ctx, op, op.getKind());
245 case cir::CastKind::float_complex_to_bool:
246 return lowerComplexToScalarCast(ctx, op, cir::CastKind::float_to_bool);
247 case cir::CastKind::int_complex_to_bool:
248 return lowerComplexToScalarCast(ctx, op, cir::CastKind::int_to_bool);
249 case cir::CastKind::float_complex:
250 return lowerComplexToComplexCast(ctx, op, cir::CastKind::floating);
251 case cir::CastKind::float_complex_to_int_complex:
252 return lowerComplexToComplexCast(ctx, op, cir::CastKind::float_to_int);
253 case cir::CastKind::int_complex:
254 return lowerComplexToComplexCast(ctx, op, cir::CastKind::integral);
255 case cir::CastKind::int_complex_to_float_complex:
256 return lowerComplexToComplexCast(ctx, op, cir::CastKind::int_to_float);
257 default:
258 return nullptr;
259 }
260 }();
261
262 if (loweredValue) {
263 op.replaceAllUsesWith(loweredValue);
264 op.erase();
265 }
266}
267
268static mlir::Value buildComplexBinOpLibCall(
269 LoweringPreparePass &pass, CIRBaseBuilderTy &builder,
270 llvm::StringRef (*libFuncNameGetter)(llvm::APFloat::Semantics),
271 mlir::Location loc, cir::ComplexType ty, mlir::Value lhsReal,
272 mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag) {
273 cir::FPTypeInterface elementTy =
274 mlir::cast<cir::FPTypeInterface>(ty.getElementType());
275
276 llvm::StringRef libFuncName = libFuncNameGetter(
277 llvm::APFloat::SemanticsToEnum(elementTy.getFloatSemantics()));
278 llvm::SmallVector<mlir::Type, 4> libFuncInputTypes(4, elementTy);
279
280 cir::FuncType libFuncTy = cir::FuncType::get(libFuncInputTypes, ty);
281
282 // Insert a declaration for the runtime function to be used in Complex
283 // multiplication and division when needed
284 cir::FuncOp libFunc;
285 {
286 mlir::OpBuilder::InsertionGuard ipGuard{builder};
287 builder.setInsertionPointToStart(pass.mlirModule.getBody());
288 libFunc = pass.buildRuntimeFunction(builder, libFuncName, loc, libFuncTy);
289 }
290
291 cir::CallOp call =
292 builder.createCallOp(loc, libFunc, {lhsReal, lhsImag, rhsReal, rhsImag});
293 return call.getResult();
294}
295
296static llvm::StringRef
297getComplexDivLibCallName(llvm::APFloat::Semantics semantics) {
298 switch (semantics) {
299 case llvm::APFloat::S_IEEEhalf:
300 return "__divhc3";
301 case llvm::APFloat::S_IEEEsingle:
302 return "__divsc3";
303 case llvm::APFloat::S_IEEEdouble:
304 return "__divdc3";
305 case llvm::APFloat::S_PPCDoubleDouble:
306 return "__divtc3";
307 case llvm::APFloat::S_x87DoubleExtended:
308 return "__divxc3";
309 case llvm::APFloat::S_IEEEquad:
310 return "__divtc3";
311 default:
312 llvm_unreachable("unsupported floating point type");
313 }
314}
315
316static mlir::Value
317buildAlgebraicComplexDiv(CIRBaseBuilderTy &builder, mlir::Location loc,
318 mlir::Value lhsReal, mlir::Value lhsImag,
319 mlir::Value rhsReal, mlir::Value rhsImag) {
320 // (a+bi) / (c+di) = ((ac+bd)/(cc+dd)) + ((bc-ad)/(cc+dd))i
321 mlir::Value &a = lhsReal;
322 mlir::Value &b = lhsImag;
323 mlir::Value &c = rhsReal;
324 mlir::Value &d = rhsImag;
325
326 mlir::Value ac = builder.createBinop(loc, a, cir::BinOpKind::Mul, c); // a*c
327 mlir::Value bd = builder.createBinop(loc, b, cir::BinOpKind::Mul, d); // b*d
328 mlir::Value cc = builder.createBinop(loc, c, cir::BinOpKind::Mul, c); // c*c
329 mlir::Value dd = builder.createBinop(loc, d, cir::BinOpKind::Mul, d); // d*d
330 mlir::Value acbd =
331 builder.createBinop(loc, ac, cir::BinOpKind::Add, bd); // ac+bd
332 mlir::Value ccdd =
333 builder.createBinop(loc, cc, cir::BinOpKind::Add, dd); // cc+dd
334 mlir::Value resultReal =
335 builder.createBinop(loc, acbd, cir::BinOpKind::Div, ccdd);
336
337 mlir::Value bc = builder.createBinop(loc, b, cir::BinOpKind::Mul, c); // b*c
338 mlir::Value ad = builder.createBinop(loc, a, cir::BinOpKind::Mul, d); // a*d
339 mlir::Value bcad =
340 builder.createBinop(loc, bc, cir::BinOpKind::Sub, ad); // bc-ad
341 mlir::Value resultImag =
342 builder.createBinop(loc, bcad, cir::BinOpKind::Div, ccdd);
343 return builder.createComplexCreate(loc, resultReal, resultImag);
344}
345
346static mlir::Value
348 mlir::Value lhsReal, mlir::Value lhsImag,
349 mlir::Value rhsReal, mlir::Value rhsImag) {
350 // Implements Smith's algorithm for complex division.
351 // SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 (1962).
352
353 // Let:
354 // - lhs := a+bi
355 // - rhs := c+di
356 // - result := lhs / rhs = e+fi
357 //
358 // The algorithm pseudocode looks like follows:
359 // if fabs(c) >= fabs(d):
360 // r := d / c
361 // tmp := c + r*d
362 // e = (a + b*r) / tmp
363 // f = (b - a*r) / tmp
364 // else:
365 // r := c / d
366 // tmp := d + r*c
367 // e = (a*r + b) / tmp
368 // f = (b*r - a) / tmp
369
370 mlir::Value &a = lhsReal;
371 mlir::Value &b = lhsImag;
372 mlir::Value &c = rhsReal;
373 mlir::Value &d = rhsImag;
374
375 auto trueBranchBuilder = [&](mlir::OpBuilder &, mlir::Location) {
376 mlir::Value r = builder.createBinop(loc, d, cir::BinOpKind::Div,
377 c); // r := d / c
378 mlir::Value rd = builder.createBinop(loc, r, cir::BinOpKind::Mul, d); // r*d
379 mlir::Value tmp = builder.createBinop(loc, c, cir::BinOpKind::Add,
380 rd); // tmp := c + r*d
381
382 mlir::Value br = builder.createBinop(loc, b, cir::BinOpKind::Mul, r); // b*r
383 mlir::Value abr =
384 builder.createBinop(loc, a, cir::BinOpKind::Add, br); // a + b*r
385 mlir::Value e = builder.createBinop(loc, abr, cir::BinOpKind::Div, tmp);
386
387 mlir::Value ar = builder.createBinop(loc, a, cir::BinOpKind::Mul, r); // a*r
388 mlir::Value bar =
389 builder.createBinop(loc, b, cir::BinOpKind::Sub, ar); // b - a*r
390 mlir::Value f = builder.createBinop(loc, bar, cir::BinOpKind::Div, tmp);
391
392 mlir::Value result = builder.createComplexCreate(loc, e, f);
393 builder.createYield(loc, result);
394 };
395
396 auto falseBranchBuilder = [&](mlir::OpBuilder &, mlir::Location) {
397 mlir::Value r = builder.createBinop(loc, c, cir::BinOpKind::Div,
398 d); // r := c / d
399 mlir::Value rc = builder.createBinop(loc, r, cir::BinOpKind::Mul, c); // r*c
400 mlir::Value tmp = builder.createBinop(loc, d, cir::BinOpKind::Add,
401 rc); // tmp := d + r*c
402
403 mlir::Value ar = builder.createBinop(loc, a, cir::BinOpKind::Mul, r); // a*r
404 mlir::Value arb =
405 builder.createBinop(loc, ar, cir::BinOpKind::Add, b); // a*r + b
406 mlir::Value e = builder.createBinop(loc, arb, cir::BinOpKind::Div, tmp);
407
408 mlir::Value br = builder.createBinop(loc, b, cir::BinOpKind::Mul, r); // b*r
409 mlir::Value bra =
410 builder.createBinop(loc, br, cir::BinOpKind::Sub, a); // b*r - a
411 mlir::Value f = builder.createBinop(loc, bra, cir::BinOpKind::Div, tmp);
412
413 mlir::Value result = builder.createComplexCreate(loc, e, f);
414 builder.createYield(loc, result);
415 };
416
417 auto cFabs = cir::FAbsOp::create(builder, loc, c);
418 auto dFabs = cir::FAbsOp::create(builder, loc, d);
419 cir::CmpOp cmpResult =
420 builder.createCompare(loc, cir::CmpOpKind::ge, cFabs, dFabs);
421 auto ternary = cir::TernaryOp::create(builder, loc, cmpResult,
422 trueBranchBuilder, falseBranchBuilder);
423
424 return ternary.getResult();
425}
426
428 mlir::MLIRContext &context, clang::ASTContext &cc,
429 CIRBaseBuilderTy &builder, mlir::Type elementType) {
430
431 auto getHigherPrecisionFPType = [&context](mlir::Type type) -> mlir::Type {
432 if (mlir::isa<cir::FP16Type>(type))
433 return cir::SingleType::get(&context);
434
435 if (mlir::isa<cir::SingleType>(type) || mlir::isa<cir::BF16Type>(type))
436 return cir::DoubleType::get(&context);
437
438 if (mlir::isa<cir::DoubleType>(type))
439 return cir::LongDoubleType::get(&context, type);
440
441 return type;
442 };
443
444 auto getFloatTypeSemantics =
445 [&cc](mlir::Type type) -> const llvm::fltSemantics & {
446 const clang::TargetInfo &info = cc.getTargetInfo();
447 if (mlir::isa<cir::FP16Type>(type))
448 return info.getHalfFormat();
449
450 if (mlir::isa<cir::BF16Type>(type))
451 return info.getBFloat16Format();
452
453 if (mlir::isa<cir::SingleType>(type))
454 return info.getFloatFormat();
455
456 if (mlir::isa<cir::DoubleType>(type))
457 return info.getDoubleFormat();
458
459 if (mlir::isa<cir::LongDoubleType>(type)) {
460 if (cc.getLangOpts().OpenMP && cc.getLangOpts().OpenMPIsTargetDevice)
461 llvm_unreachable("NYI Float type semantics with OpenMP");
462 return info.getLongDoubleFormat();
463 }
464
465 if (mlir::isa<cir::FP128Type>(type)) {
466 if (cc.getLangOpts().OpenMP && cc.getLangOpts().OpenMPIsTargetDevice)
467 llvm_unreachable("NYI Float type semantics with OpenMP");
468 return info.getFloat128Format();
469 }
470
471 llvm_unreachable("Unsupported float type semantics");
472 };
473
474 const mlir::Type higherElementType = getHigherPrecisionFPType(elementType);
475 const llvm::fltSemantics &elementTypeSemantics =
476 getFloatTypeSemantics(elementType);
477 const llvm::fltSemantics &higherElementTypeSemantics =
478 getFloatTypeSemantics(higherElementType);
479
480 // Check that the promoted type can handle the intermediate values without
481 // overflowing. This can be interpreted as:
482 // (SmallerType.LargestFiniteVal * SmallerType.LargestFiniteVal) * 2 <=
483 // LargerType.LargestFiniteVal.
484 // In terms of exponent it gives this formula:
485 // (SmallerType.LargestFiniteVal * SmallerType.LargestFiniteVal
486 // doubles the exponent of SmallerType.LargestFiniteVal)
487 if (llvm::APFloat::semanticsMaxExponent(elementTypeSemantics) * 2 + 1 <=
488 llvm::APFloat::semanticsMaxExponent(higherElementTypeSemantics)) {
489 return higherElementType;
490 }
491
492 // The intermediate values can't be represented in the promoted type
493 // without overflowing.
494 return {};
495}
496
497static mlir::Value
498lowerComplexDiv(LoweringPreparePass &pass, CIRBaseBuilderTy &builder,
499 mlir::Location loc, cir::ComplexDivOp op, mlir::Value lhsReal,
500 mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag,
501 mlir::MLIRContext &mlirCx, clang::ASTContext &cc) {
502 cir::ComplexType complexTy = op.getType();
503 if (mlir::isa<cir::FPTypeInterface>(complexTy.getElementType())) {
504 cir::ComplexRangeKind range = op.getRange();
505 if (range == cir::ComplexRangeKind::Improved)
506 return buildRangeReductionComplexDiv(builder, loc, lhsReal, lhsImag,
507 rhsReal, rhsImag);
508
509 if (range == cir::ComplexRangeKind::Full)
511 loc, complexTy, lhsReal, lhsImag, rhsReal,
512 rhsImag);
513
514 if (range == cir::ComplexRangeKind::Promoted) {
515 mlir::Type originalElementType = complexTy.getElementType();
516 mlir::Type higherPrecisionElementType =
518 originalElementType);
519
520 if (!higherPrecisionElementType)
521 return buildRangeReductionComplexDiv(builder, loc, lhsReal, lhsImag,
522 rhsReal, rhsImag);
523
524 cir::CastKind floatingCastKind = cir::CastKind::floating;
525 lhsReal = builder.createCast(floatingCastKind, lhsReal,
526 higherPrecisionElementType);
527 lhsImag = builder.createCast(floatingCastKind, lhsImag,
528 higherPrecisionElementType);
529 rhsReal = builder.createCast(floatingCastKind, rhsReal,
530 higherPrecisionElementType);
531 rhsImag = builder.createCast(floatingCastKind, rhsImag,
532 higherPrecisionElementType);
533
534 mlir::Value algebraicResult = buildAlgebraicComplexDiv(
535 builder, loc, lhsReal, lhsImag, rhsReal, rhsImag);
536
537 mlir::Value resultReal = builder.createComplexReal(loc, algebraicResult);
538 mlir::Value resultImag = builder.createComplexImag(loc, algebraicResult);
539
540 mlir::Value finalReal =
541 builder.createCast(floatingCastKind, resultReal, originalElementType);
542 mlir::Value finalImag =
543 builder.createCast(floatingCastKind, resultImag, originalElementType);
544 return builder.createComplexCreate(loc, finalReal, finalImag);
545 }
546 }
547
548 return buildAlgebraicComplexDiv(builder, loc, lhsReal, lhsImag, rhsReal,
549 rhsImag);
550}
551
552void LoweringPreparePass::lowerComplexDivOp(cir::ComplexDivOp op) {
553 cir::CIRBaseBuilderTy builder(getContext());
554 builder.setInsertionPointAfter(op);
555 mlir::Location loc = op.getLoc();
556 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
557 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
558 mlir::Value lhsReal = builder.createComplexReal(loc, lhs);
559 mlir::Value lhsImag = builder.createComplexImag(loc, lhs);
560 mlir::Value rhsReal = builder.createComplexReal(loc, rhs);
561 mlir::Value rhsImag = builder.createComplexImag(loc, rhs);
562
563 mlir::Value loweredResult =
564 lowerComplexDiv(*this, builder, loc, op, lhsReal, lhsImag, rhsReal,
565 rhsImag, getContext(), *astCtx);
566 op.replaceAllUsesWith(loweredResult);
567 op.erase();
568}
569
570static llvm::StringRef
571getComplexMulLibCallName(llvm::APFloat::Semantics semantics) {
572 switch (semantics) {
573 case llvm::APFloat::S_IEEEhalf:
574 return "__mulhc3";
575 case llvm::APFloat::S_IEEEsingle:
576 return "__mulsc3";
577 case llvm::APFloat::S_IEEEdouble:
578 return "__muldc3";
579 case llvm::APFloat::S_PPCDoubleDouble:
580 return "__multc3";
581 case llvm::APFloat::S_x87DoubleExtended:
582 return "__mulxc3";
583 case llvm::APFloat::S_IEEEquad:
584 return "__multc3";
585 default:
586 llvm_unreachable("unsupported floating point type");
587 }
588}
589
590static mlir::Value lowerComplexMul(LoweringPreparePass &pass,
591 CIRBaseBuilderTy &builder,
592 mlir::Location loc, cir::ComplexMulOp op,
593 mlir::Value lhsReal, mlir::Value lhsImag,
594 mlir::Value rhsReal, mlir::Value rhsImag) {
595 // (a+bi) * (c+di) = (ac-bd) + (ad+bc)i
596 mlir::Value resultRealLhs =
597 builder.createBinop(loc, lhsReal, cir::BinOpKind::Mul, rhsReal);
598 mlir::Value resultRealRhs =
599 builder.createBinop(loc, lhsImag, cir::BinOpKind::Mul, rhsImag);
600 mlir::Value resultImagLhs =
601 builder.createBinop(loc, lhsReal, cir::BinOpKind::Mul, rhsImag);
602 mlir::Value resultImagRhs =
603 builder.createBinop(loc, lhsImag, cir::BinOpKind::Mul, rhsReal);
604 mlir::Value resultReal = builder.createBinop(
605 loc, resultRealLhs, cir::BinOpKind::Sub, resultRealRhs);
606 mlir::Value resultImag = builder.createBinop(
607 loc, resultImagLhs, cir::BinOpKind::Add, resultImagRhs);
608 mlir::Value algebraicResult =
609 builder.createComplexCreate(loc, resultReal, resultImag);
610
611 cir::ComplexType complexTy = op.getType();
612 cir::ComplexRangeKind rangeKind = op.getRange();
613 if (mlir::isa<cir::IntType>(complexTy.getElementType()) ||
614 rangeKind == cir::ComplexRangeKind::Basic ||
615 rangeKind == cir::ComplexRangeKind::Improved ||
616 rangeKind == cir::ComplexRangeKind::Promoted)
617 return algebraicResult;
618
620
621 // Check whether the real part and the imaginary part of the result are both
622 // NaN. If so, emit a library call to compute the multiplication instead.
623 // We check a value against NaN by comparing the value against itself.
624 mlir::Value resultRealIsNaN = builder.createIsNaN(loc, resultReal);
625 mlir::Value resultImagIsNaN = builder.createIsNaN(loc, resultImag);
626 mlir::Value resultRealAndImagAreNaN =
627 builder.createLogicalAnd(loc, resultRealIsNaN, resultImagIsNaN);
628
629 return cir::TernaryOp::create(
630 builder, loc, resultRealAndImagAreNaN,
631 [&](mlir::OpBuilder &, mlir::Location) {
632 mlir::Value libCallResult = buildComplexBinOpLibCall(
633 pass, builder, &getComplexMulLibCallName, loc, complexTy,
634 lhsReal, lhsImag, rhsReal, rhsImag);
635 builder.createYield(loc, libCallResult);
636 },
637 [&](mlir::OpBuilder &, mlir::Location) {
638 builder.createYield(loc, algebraicResult);
639 })
640 .getResult();
641}
642
643void LoweringPreparePass::lowerComplexMulOp(cir::ComplexMulOp op) {
644 cir::CIRBaseBuilderTy builder(getContext());
645 builder.setInsertionPointAfter(op);
646 mlir::Location loc = op.getLoc();
647 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
648 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
649 mlir::Value lhsReal = builder.createComplexReal(loc, lhs);
650 mlir::Value lhsImag = builder.createComplexImag(loc, lhs);
651 mlir::Value rhsReal = builder.createComplexReal(loc, rhs);
652 mlir::Value rhsImag = builder.createComplexImag(loc, rhs);
653 mlir::Value loweredResult = lowerComplexMul(*this, builder, loc, op, lhsReal,
654 lhsImag, rhsReal, rhsImag);
655 op.replaceAllUsesWith(loweredResult);
656 op.erase();
657}
658
659void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
660 mlir::Type ty = op.getType();
661 if (!mlir::isa<cir::ComplexType>(ty))
662 return;
663
664 mlir::Location loc = op.getLoc();
665 cir::UnaryOpKind opKind = op.getKind();
666
667 CIRBaseBuilderTy builder(getContext());
668 builder.setInsertionPointAfter(op);
669
670 mlir::Value operand = op.getInput();
671 mlir::Value operandReal = builder.createComplexReal(loc, operand);
672 mlir::Value operandImag = builder.createComplexImag(loc, operand);
673
674 mlir::Value resultReal;
675 mlir::Value resultImag;
676
677 switch (opKind) {
678 case cir::UnaryOpKind::Inc:
679 case cir::UnaryOpKind::Dec:
680 resultReal = builder.createUnaryOp(loc, opKind, operandReal);
681 resultImag = operandImag;
682 break;
683
684 case cir::UnaryOpKind::Plus:
685 case cir::UnaryOpKind::Minus:
686 resultReal = builder.createUnaryOp(loc, opKind, operandReal);
687 resultImag = builder.createUnaryOp(loc, opKind, operandImag);
688 break;
689
690 case cir::UnaryOpKind::Not:
691 resultReal = operandReal;
692 resultImag =
693 builder.createUnaryOp(loc, cir::UnaryOpKind::Minus, operandImag);
694 break;
695 }
696
697 mlir::Value result = builder.createComplexCreate(loc, resultReal, resultImag);
698 op.replaceAllUsesWith(result);
699 op.erase();
700}
701
702cir::FuncOp LoweringPreparePass::getOrCreateDtorFunc(CIRBaseBuilderTy &builder,
703 cir::GlobalOp op,
704 mlir::Region &dtorRegion,
705 cir::CallOp &dtorCall) {
706 mlir::OpBuilder::InsertionGuard guard(builder);
709
710 cir::VoidType voidTy = builder.getVoidTy();
711 auto voidPtrTy = cir::PointerType::get(voidTy);
712
713 // Look for operations in dtorBlock
714 mlir::Block &dtorBlock = dtorRegion.front();
715
716 // The first operation should be a get_global to retrieve the address
717 // of the global variable we're destroying.
718 auto opIt = dtorBlock.getOperations().begin();
719 cir::GetGlobalOp ggop = mlir::cast<cir::GetGlobalOp>(*opIt);
720
721 // The simple case is just a call to a destructor, like this:
722 //
723 // %0 = cir.get_global %globalS : !cir.ptr<!rec_S>
724 // cir.call %_ZN1SD1Ev(%0) : (!cir.ptr<!rec_S>) -> ()
725 // (implicit cir.yield)
726 //
727 // That is, if the second operation is a call that takes the get_global result
728 // as its only operand, and the only other operation is a yield, then we can
729 // just return the called function.
730 if (dtorBlock.getOperations().size() == 3) {
731 auto callOp = mlir::dyn_cast<cir::CallOp>(&*(++opIt));
732 auto yieldOp = mlir::dyn_cast<cir::YieldOp>(&*(++opIt));
733 if (yieldOp && callOp && callOp.getNumOperands() == 1 &&
734 callOp.getArgOperand(0) == ggop) {
735 dtorCall = callOp;
736 return getCalledFunction(callOp);
737 }
738 }
739
740 // Otherwise, we need to create a helper function to replace the dtor region.
741 // This name is kind of arbitrary, but it matches the name that classic
742 // codegen uses, based on the expected case that gets us here.
743 builder.setInsertionPointAfter(op);
744 SmallString<256> fnName("__cxx_global_array_dtor");
745 uint32_t cnt = dynamicInitializerNames[fnName]++;
746 if (cnt)
747 fnName += "." + std::to_string(cnt);
748
749 // Create the helper function.
750 auto fnType = cir::FuncType::get({voidPtrTy}, voidTy);
751 cir::FuncOp dtorFunc =
752 buildRuntimeFunction(builder, fnName, op.getLoc(), fnType,
753 cir::GlobalLinkageKind::InternalLinkage);
754 mlir::Block *entryBB = dtorFunc.addEntryBlock();
755
756 // Move everything from the dtor region into the helper function.
757 entryBB->getOperations().splice(entryBB->begin(), dtorBlock.getOperations(),
758 dtorBlock.begin(), dtorBlock.end());
759
760 // Before erasing this, clone it back into the dtor region
761 cir::GetGlobalOp dtorGGop =
762 mlir::cast<cir::GetGlobalOp>(entryBB->getOperations().front());
763 builder.setInsertionPointToStart(&dtorBlock);
764 builder.clone(*dtorGGop.getOperation());
765
766 // Replace all uses of the help function's get_global with the function
767 // argument.
768 mlir::Value dtorArg = entryBB->getArgument(0);
769 dtorGGop.replaceAllUsesWith(dtorArg);
770 dtorGGop.erase();
771
772 // Replace the yield in the final block with a return
773 mlir::Block &finalBlock = dtorFunc.getBody().back();
774 auto yieldOp = cast<cir::YieldOp>(finalBlock.getTerminator());
775 builder.setInsertionPoint(yieldOp);
776 cir::ReturnOp::create(builder, yieldOp->getLoc());
777 yieldOp->erase();
778
779 // Create a call to the helper function, passing the original get_global op
780 // as the argument.
781 cir::GetGlobalOp origGGop =
782 mlir::cast<cir::GetGlobalOp>(dtorBlock.getOperations().front());
783 builder.setInsertionPointAfter(origGGop);
784 mlir::Value ggopResult = origGGop.getResult();
785 dtorCall = builder.createCallOp(op.getLoc(), dtorFunc, ggopResult);
786
787 // Add a yield after the call.
788 auto finalYield = cir::YieldOp::create(builder, op.getLoc());
789
790 // Erase everything after the yield.
791 dtorBlock.getOperations().erase(std::next(mlir::Block::iterator(finalYield)),
792 dtorBlock.end());
793 dtorRegion.getBlocks().erase(std::next(dtorRegion.begin()), dtorRegion.end());
794
795 return dtorFunc;
796}
797
798cir::FuncOp
799LoweringPreparePass::buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op) {
800 // TODO(cir): Store this in the GlobalOp.
801 // This should come from the MangleContext, but for now I'm hardcoding it.
802 SmallString<256> fnName("__cxx_global_var_init");
803 // Get a unique name
804 uint32_t cnt = dynamicInitializerNames[fnName]++;
805 if (cnt)
806 fnName += "." + std::to_string(cnt);
807
808 // Create a variable initialization function.
809 CIRBaseBuilderTy builder(getContext());
810 builder.setInsertionPointAfter(op);
811 cir::VoidType voidTy = builder.getVoidTy();
812 auto fnType = cir::FuncType::get({}, voidTy);
813 FuncOp f = buildRuntimeFunction(builder, fnName, op.getLoc(), fnType,
814 cir::GlobalLinkageKind::InternalLinkage);
815
816 // Move over the initialzation code of the ctor region.
817 mlir::Block *entryBB = f.addEntryBlock();
818 if (!op.getCtorRegion().empty()) {
819 mlir::Block &block = op.getCtorRegion().front();
820 entryBB->getOperations().splice(entryBB->begin(), block.getOperations(),
821 block.begin(), std::prev(block.end()));
822 }
823
824 // Register the destructor call with __cxa_atexit
825 mlir::Region &dtorRegion = op.getDtorRegion();
826 if (!dtorRegion.empty()) {
829
830 // Create a variable that binds the atexit to this shared object.
831 builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
832 cir::GlobalOp handle = buildRuntimeVariable(
833 builder, "__dso_handle", op.getLoc(), builder.getI8Type(),
834 cir::GlobalLinkageKind::ExternalLinkage, cir::VisibilityKind::Hidden);
835
836 // If this is a simple call to a destructor, get the called function.
837 // Otherwise, create a helper function for the entire dtor region,
838 // replacing the current dtor region body with a call to the helper
839 // function.
840 cir::CallOp dtorCall;
841 cir::FuncOp dtorFunc =
842 getOrCreateDtorFunc(builder, op, dtorRegion, dtorCall);
843
844 // Create a runtime helper function:
845 // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
846 auto voidPtrTy = cir::PointerType::get(voidTy);
847 auto voidFnTy = cir::FuncType::get({voidPtrTy}, voidTy);
848 auto voidFnPtrTy = cir::PointerType::get(voidFnTy);
849 auto handlePtrTy = cir::PointerType::get(handle.getSymType());
850 auto fnAtExitType =
851 cir::FuncType::get({voidFnPtrTy, voidPtrTy, handlePtrTy}, voidTy);
852 const char *nameAtExit = "__cxa_atexit";
853 cir::FuncOp fnAtExit =
854 buildRuntimeFunction(builder, nameAtExit, op.getLoc(), fnAtExitType);
855
856 // Replace the dtor (or helper) call with a call to
857 // __cxa_atexit(&dtor, &var, &__dso_handle)
858 builder.setInsertionPointAfter(dtorCall);
859 mlir::Value args[3];
860 auto dtorPtrTy = cir::PointerType::get(dtorFunc.getFunctionType());
861 // dtorPtrTy
862 args[0] = cir::GetGlobalOp::create(builder, dtorCall.getLoc(), dtorPtrTy,
863 dtorFunc.getSymName());
864 args[0] = cir::CastOp::create(builder, dtorCall.getLoc(), voidFnPtrTy,
865 cir::CastKind::bitcast, args[0]);
866 args[1] =
867 cir::CastOp::create(builder, dtorCall.getLoc(), voidPtrTy,
868 cir::CastKind::bitcast, dtorCall.getArgOperand(0));
869 args[2] = cir::GetGlobalOp::create(builder, handle.getLoc(), handlePtrTy,
870 handle.getSymName());
871 builder.createCallOp(dtorCall.getLoc(), fnAtExit, args);
872 dtorCall->erase();
873 mlir::Block &dtorBlock = dtorRegion.front();
874 entryBB->getOperations().splice(entryBB->end(), dtorBlock.getOperations(),
875 dtorBlock.begin(),
876 std::prev(dtorBlock.end()));
877 }
878
879 // Replace cir.yield with cir.return
880 builder.setInsertionPointToEnd(entryBB);
881 mlir::Operation *yieldOp = nullptr;
882 if (!op.getCtorRegion().empty()) {
883 mlir::Block &block = op.getCtorRegion().front();
884 yieldOp = &block.getOperations().back();
885 } else {
886 assert(!dtorRegion.empty());
887 mlir::Block &block = dtorRegion.front();
888 yieldOp = &block.getOperations().back();
889 }
890
891 assert(isa<cir::YieldOp>(*yieldOp));
892 cir::ReturnOp::create(builder, yieldOp->getLoc());
893 return f;
894}
895
896void LoweringPreparePass::lowerGlobalOp(GlobalOp op) {
897 mlir::Region &ctorRegion = op.getCtorRegion();
898 mlir::Region &dtorRegion = op.getDtorRegion();
899
900 if (!ctorRegion.empty() || !dtorRegion.empty()) {
901 // Build a variable initialization function and move the initialzation code
902 // in the ctor region over.
903 cir::FuncOp f = buildCXXGlobalVarDeclInitFunc(op);
904
905 // Clear the ctor and dtor region
906 ctorRegion.getBlocks().clear();
907 dtorRegion.getBlocks().clear();
908
910 dynamicInitializers.push_back(f);
911 }
912
914}
915
916template <typename AttributeTy>
917static llvm::SmallVector<mlir::Attribute>
918prepareCtorDtorAttrList(mlir::MLIRContext *context,
919 llvm::ArrayRef<std::pair<std::string, uint32_t>> list) {
921 for (const auto &[name, priority] : list)
922 attrs.push_back(AttributeTy::get(context, name, priority));
923 return attrs;
924}
925
926void LoweringPreparePass::buildGlobalCtorDtorList() {
927 if (!globalCtorList.empty()) {
928 llvm::SmallVector<mlir::Attribute> globalCtors =
930 globalCtorList);
931
932 mlirModule->setAttr(cir::CIRDialect::getGlobalCtorsAttrName(),
933 mlir::ArrayAttr::get(&getContext(), globalCtors));
934 }
935
936 if (!globalDtorList.empty()) {
937 llvm::SmallVector<mlir::Attribute> globalDtors =
939 globalDtorList);
940 mlirModule->setAttr(cir::CIRDialect::getGlobalDtorsAttrName(),
941 mlir::ArrayAttr::get(&getContext(), globalDtors));
942 }
943}
944
945void LoweringPreparePass::buildCXXGlobalInitFunc() {
946 if (dynamicInitializers.empty())
947 return;
948
949 // TODO: handle globals with a user-specified initialzation priority.
950 // TODO: handle default priority more nicely.
952
953 SmallString<256> fnName;
954 // Include the filename in the symbol name. Including "sub_" matches gcc
955 // and makes sure these symbols appear lexicographically behind the symbols
956 // with priority (TBD). Module implementation units behave the same
957 // way as a non-modular TU with imports.
958 // TODO: check CXX20ModuleInits
959 if (astCtx->getCurrentNamedModule() &&
961 llvm::raw_svector_ostream out(fnName);
962 std::unique_ptr<clang::MangleContext> mangleCtx(
963 astCtx->createMangleContext());
964 cast<clang::ItaniumMangleContext>(*mangleCtx)
965 .mangleModuleInitializer(astCtx->getCurrentNamedModule(), out);
966 } else {
967 fnName += "_GLOBAL__sub_I_";
968 fnName += getTransformedFileName(mlirModule);
969 }
970
971 CIRBaseBuilderTy builder(getContext());
972 builder.setInsertionPointToEnd(&mlirModule.getBodyRegion().back());
973 auto fnType = cir::FuncType::get({}, builder.getVoidTy());
974 cir::FuncOp f =
975 buildRuntimeFunction(builder, fnName, mlirModule.getLoc(), fnType,
976 cir::GlobalLinkageKind::ExternalLinkage);
977 builder.setInsertionPointToStart(f.addEntryBlock());
978 for (cir::FuncOp &f : dynamicInitializers)
979 builder.createCallOp(f.getLoc(), f, {});
980 // Add the global init function (not the individual ctor functions) to the
981 // global ctor list.
982 globalCtorList.emplace_back(fnName,
983 cir::GlobalCtorAttr::getDefaultPriority());
984
985 cir::ReturnOp::create(builder, f.getLoc());
986}
987
988void LoweringPreparePass::lowerDynamicCastOp(DynamicCastOp op) {
989 CIRBaseBuilderTy builder(getContext());
990 builder.setInsertionPointAfter(op);
991
992 assert(astCtx && "AST context is not available during lowering prepare");
993 auto loweredValue = cxxABI->lowerDynamicCast(builder, *astCtx, op);
994
995 op.replaceAllUsesWith(loweredValue);
996 op.erase();
997}
998
1000 clang::ASTContext *astCtx,
1001 mlir::Operation *op, mlir::Type eltTy,
1002 mlir::Value arrayAddr, uint64_t arrayLen,
1003 bool isCtor) {
1004 // Generate loop to call into ctor/dtor for every element.
1005 mlir::Location loc = op->getLoc();
1006
1007 // TODO: instead of getting the size from the AST context, create alias for
1008 // PtrDiffTy and unify with CIRGen stuff.
1009 const unsigned sizeTypeSize =
1010 astCtx->getTypeSize(astCtx->getSignedSizeType());
1011 uint64_t endOffset = isCtor ? arrayLen : arrayLen - 1;
1012 mlir::Value endOffsetVal =
1013 builder.getUnsignedInt(loc, endOffset, sizeTypeSize);
1014
1015 auto begin = cir::CastOp::create(builder, loc, eltTy,
1016 cir::CastKind::array_to_ptrdecay, arrayAddr);
1017 mlir::Value end =
1018 cir::PtrStrideOp::create(builder, loc, eltTy, begin, endOffsetVal);
1019 mlir::Value start = isCtor ? begin : end;
1020 mlir::Value stop = isCtor ? end : begin;
1021
1022 mlir::Value tmpAddr = builder.createAlloca(
1023 loc, /*addr type*/ builder.getPointerTo(eltTy),
1024 /*var type*/ eltTy, "__array_idx", builder.getAlignmentAttr(1));
1025 builder.createStore(loc, start, tmpAddr);
1026
1027 cir::DoWhileOp loop = builder.createDoWhile(
1028 loc,
1029 /*condBuilder=*/
1030 [&](mlir::OpBuilder &b, mlir::Location loc) {
1031 auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
1032 auto cmp = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne,
1033 currentElement, stop);
1034 builder.createCondition(cmp);
1035 },
1036 /*bodyBuilder=*/
1037 [&](mlir::OpBuilder &b, mlir::Location loc) {
1038 auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
1039
1040 cir::CallOp ctorCall;
1041 op->walk([&](cir::CallOp c) { ctorCall = c; });
1042 assert(ctorCall && "expected ctor call");
1043
1044 // Array elements get constructed in order but destructed in reverse.
1045 mlir::Value stride;
1046 if (isCtor)
1047 stride = builder.getUnsignedInt(loc, 1, sizeTypeSize);
1048 else
1049 stride = builder.getSignedInt(loc, -1, sizeTypeSize);
1050
1051 ctorCall->moveBefore(stride.getDefiningOp());
1052 ctorCall->setOperand(0, currentElement);
1053 auto nextElement = cir::PtrStrideOp::create(builder, loc, eltTy,
1054 currentElement, stride);
1055
1056 // Store the element pointer to the temporary variable
1057 builder.createStore(loc, nextElement, tmpAddr);
1058 builder.createYield(loc);
1059 });
1060
1061 op->replaceAllUsesWith(loop);
1062 op->erase();
1063}
1064
1065void LoweringPreparePass::lowerArrayDtor(cir::ArrayDtor op) {
1066 CIRBaseBuilderTy builder(getContext());
1067 builder.setInsertionPointAfter(op.getOperation());
1068
1069 mlir::Type eltTy = op->getRegion(0).getArgument(0).getType();
1070 assert(!cir::MissingFeatures::vlas());
1071 auto arrayLen =
1072 mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize();
1073 lowerArrayDtorCtorIntoLoop(builder, astCtx, op, eltTy, op.getAddr(), arrayLen,
1074 false);
1075}
1076
1077void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
1078 cir::CIRBaseBuilderTy builder(getContext());
1079 builder.setInsertionPointAfter(op.getOperation());
1080
1081 mlir::Type eltTy = op->getRegion(0).getArgument(0).getType();
1082 assert(!cir::MissingFeatures::vlas());
1083 auto arrayLen =
1084 mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize();
1085 lowerArrayDtorCtorIntoLoop(builder, astCtx, op, eltTy, op.getAddr(), arrayLen,
1086 true);
1087}
1088
1089void LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {
1090 cir::FuncOp funcOp = getCalledFunction(op);
1091 if (!funcOp)
1092 return;
1093
1094 std::optional<cir::CtorKind> ctorKind = funcOp.getCxxConstructorKind();
1095 if (ctorKind && *ctorKind == cir::CtorKind::Copy &&
1096 funcOp.isCxxTrivialMemberFunction()) {
1097 // Replace the trivial copy constructor call with a `CopyOp`
1098 CIRBaseBuilderTy builder(getContext());
1099 mlir::ValueRange operands = op.getOperands();
1100 mlir::Value dest = operands[0];
1101 mlir::Value src = operands[1];
1102 builder.setInsertionPoint(op);
1103 builder.createCopy(dest, src);
1104 op.erase();
1105 }
1106}
1107
1108void LoweringPreparePass::runOnOp(mlir::Operation *op) {
1109 if (auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) {
1110 lowerArrayCtor(arrayCtor);
1111 } else if (auto arrayDtor = dyn_cast<cir::ArrayDtor>(op)) {
1112 lowerArrayDtor(arrayDtor);
1113 } else if (auto cast = mlir::dyn_cast<cir::CastOp>(op)) {
1114 lowerCastOp(cast);
1115 } else if (auto complexDiv = mlir::dyn_cast<cir::ComplexDivOp>(op)) {
1116 lowerComplexDivOp(complexDiv);
1117 } else if (auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op)) {
1118 lowerComplexMulOp(complexMul);
1119 } else if (auto glob = mlir::dyn_cast<cir::GlobalOp>(op)) {
1120 lowerGlobalOp(glob);
1121 } else if (auto dynamicCast = mlir::dyn_cast<cir::DynamicCastOp>(op)) {
1122 lowerDynamicCastOp(dynamicCast);
1123 } else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) {
1124 lowerUnaryOp(unary);
1125 } else if (auto callOp = dyn_cast<cir::CallOp>(op)) {
1126 lowerTrivialCopyCall(callOp);
1127 } else if (auto fnOp = dyn_cast<cir::FuncOp>(op)) {
1128 if (auto globalCtor = fnOp.getGlobalCtorPriority())
1129 globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
1130 else if (auto globalDtor = fnOp.getGlobalDtorPriority())
1131 globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
1132 }
1133}
1134
1135void LoweringPreparePass::runOnOperation() {
1136 mlir::Operation *op = getOperation();
1137 if (isa<::mlir::ModuleOp>(op))
1138 mlirModule = cast<::mlir::ModuleOp>(op);
1139
1140 llvm::SmallVector<mlir::Operation *> opsToTransform;
1141
1142 op->walk([&](mlir::Operation *op) {
1143 if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
1144 cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
1145 cir::FuncOp, cir::CallOp, cir::GlobalOp, cir::UnaryOp>(op))
1146 opsToTransform.push_back(op);
1147 });
1148
1149 for (mlir::Operation *o : opsToTransform)
1150 runOnOp(o);
1151
1152 buildCXXGlobalInitFunc();
1153 buildGlobalCtorDtorList();
1154}
1155
1156std::unique_ptr<Pass> mlir::createLoweringPreparePass() {
1157 return std::make_unique<LoweringPreparePass>();
1158}
1159
1160std::unique_ptr<Pass>
1162 auto pass = std::make_unique<LoweringPreparePass>();
1163 pass->setASTContext(astCtx);
1164 return std::move(pass);
1165}
Defines the clang::ASTContext interface.
static mlir::Value buildRangeReductionComplexDiv(CIRBaseBuilderTy &builder, mlir::Location loc, mlir::Value lhsReal, mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag)
static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, clang::ASTContext *astCtx, mlir::Operation *op, mlir::Type eltTy, mlir::Value arrayAddr, uint64_t arrayLen, bool isCtor)
static llvm::StringRef getComplexDivLibCallName(llvm::APFloat::Semantics semantics)
static llvm::SmallVector< mlir::Attribute > prepareCtorDtorAttrList(mlir::MLIRContext *context, llvm::ArrayRef< std::pair< std::string, uint32_t > > list)
static llvm::StringRef getComplexMulLibCallName(llvm::APFloat::Semantics semantics)
static mlir::Value buildComplexBinOpLibCall(LoweringPreparePass &pass, CIRBaseBuilderTy &builder, llvm::StringRef(*libFuncNameGetter)(llvm::APFloat::Semantics), mlir::Location loc, cir::ComplexType ty, mlir::Value lhsReal, mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag)
static mlir::Value lowerComplexMul(LoweringPreparePass &pass, CIRBaseBuilderTy &builder, mlir::Location loc, cir::ComplexMulOp op, mlir::Value lhsReal, mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag)
static SmallString< 128 > getTransformedFileName(mlir::ModuleOp mlirModule)
static mlir::Value lowerComplexToComplexCast(mlir::MLIRContext &ctx, cir::CastOp op, cir::CastKind scalarCastKind)
static mlir::Value lowerComplexToScalarCast(mlir::MLIRContext &ctx, cir::CastOp op, cir::CastKind elemToBoolKind)
static mlir::Value buildAlgebraicComplexDiv(CIRBaseBuilderTy &builder, mlir::Location loc, mlir::Value lhsReal, mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag)
static cir::FuncOp getCalledFunction(cir::CallOp callOp)
Return the FuncOp called by callOp.
static mlir::Type higherPrecisionElementTypeForComplexArithmetic(mlir::MLIRContext &context, clang::ASTContext &cc, CIRBaseBuilderTy &builder, mlir::Type elementType)
static mlir::Value lowerScalarToComplexCast(mlir::MLIRContext &ctx, cir::CastOp op)
static mlir::Value lowerComplexDiv(LoweringPreparePass &pass, CIRBaseBuilderTy &builder, mlir::Location loc, cir::ComplexDivOp op, mlir::Value lhsReal, mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag, mlir::MLIRContext &mlirCx, clang::ASTContext &cc)
Defines the clang::Module class, which describes a module in the source code.
__device__ __2f16 b
__device__ __2f16 float c
mlir::Value createLogicalOr(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::ConditionOp createCondition(mlir::Value condition)
Create a loop condition.
cir::VoidType getVoidTy()
cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc)
mlir::Value createCast(mlir::Location loc, cir::CastKind kind, mlir::Value src, mlir::Type newTy)
cir::PointerType getPointerTo(mlir::Type ty)
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand)
cir::DoWhileOp createDoWhile(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder)
Create a do-while operation.
cir::CopyOp createCopy(mlir::Value dst, mlir::Value src, bool isVolatile=false)
Create a copy with inferred length.
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::Type returnType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={})
mlir::Value getSignedInt(mlir::Location loc, int64_t val, unsigned numBits)
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
mlir::IntegerAttr getAlignmentAttr(clang::CharUnits alignment)
mlir::Value createBinop(mlir::Location loc, mlir::Value lhs, cir::BinOpKind kind, mlir::Value rhs)
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real, mlir::Value imag)
mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst, bool isVolatile=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
mlir::Value createLogicalAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind, mlir::Value operand)
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, mlir::Type type, llvm::StringRef name, mlir::IntegerAttr alignment, mlir::Value dynAllocSize)
cir::BoolType getBoolTy()
mlir::Value getUnsignedInt(mlir::Location loc, uint64_t val, unsigned numBits)
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand)
static LoweringPrepareCXXABI * createItaniumABI()
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
MangleContext * createMangleContext(const TargetInfo *T=nullptr)
If T is null pointer, assume the target in ASTContext.
const LangOptions & getLangOpts() const
Definition ASTContext.h:944
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:909
QualType getSignedSizeType() const
Return the unique signed counterpart of the integer type corresponding to size_t.
Module * getCurrentNamedModule() const
Get module under construction, nullptr if this is not a C++20 module.
bool isModuleImplementation() const
Is this a module implementation.
Definition Module.h:664
Exposes information about the current target.
Definition TargetInfo.h:226
const llvm::fltSemantics & getDoubleFormat() const
Definition TargetInfo.h:803
const llvm::fltSemantics & getHalfFormat() const
Definition TargetInfo.h:788
const llvm::fltSemantics & getBFloat16Format() const
Definition TargetInfo.h:798
const llvm::fltSemantics & getLongDoubleFormat() const
Definition TargetInfo.h:809
const llvm::fltSemantics & getFloatFormat() const
Definition TargetInfo.h:793
const llvm::fltSemantics & getFloat128Format() const
Definition TargetInfo.h:817
Defines the clang::TargetInfo interface.
LLVM_READONLY bool isPreprocessingNumberBody(unsigned char c)
Return true if this is the body character of a C preprocessing number, which is [a-zA-Z0-9_.
Definition CharInfo.h:168
unsigned int uint32_t
std::unique_ptr< Pass > createLoweringPreparePass()
static bool opGlobalThreadLocal()
static bool opGlobalAnnotations()
static bool opGlobalCtorPriority()
static bool loweringPrepareX86CXXABI()
static bool opFuncExtraAttrs()
static bool fastMathFlags()
static bool loweringPrepareAArch64XXABI()
static bool astVarDeclInterface()