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