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