11#include "mlir/IR/Attributes.h"
21#include "llvm/Support/Path.h"
29#define GEN_PASS_DEF_LOWERINGPREPARE
30#include "clang/CIR/Dialect/Passes.h.inc"
34 SmallString<128> fileName;
36 if (mlirModule.getSymName())
37 fileName = llvm::sys::path::filename(mlirModule.getSymName()->str());
42 for (
size_t i = 0; i < fileName.size(); ++i) {
54 mlir::SymbolRefAttr sym = llvm::dyn_cast_if_present<mlir::SymbolRefAttr>(
55 callOp.getCallableForCallee());
58 return dyn_cast_or_null<cir::FuncOp>(
59 mlir::SymbolTable::lookupNearestSymbolFrom(callOp, sym));
63struct LoweringPreparePass
64 :
public impl::LoweringPrepareBase<LoweringPreparePass> {
65 LoweringPreparePass() =
default;
66 void runOnOperation()
override;
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);
79 cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
82 cir::FuncOp getOrCreateDtorFunc(CIRBaseBuilderTy &builder, cir::GlobalOp op,
83 mlir::Region &dtorRegion,
84 cir::CallOp &dtorCall);
87 void buildCXXGlobalInitFunc();
90 void buildGlobalCtorDtorList();
92 cir::FuncOp buildRuntimeFunction(
93 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
95 cir::GlobalLinkageKind linkage = cir::GlobalLinkageKind::ExternalLinkage);
97 cir::GlobalOp buildRuntimeVariable(
98 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
100 cir::GlobalLinkageKind linkage = cir::GlobalLinkageKind::ExternalLinkage,
101 cir::VisibilityKind visibility = cir::VisibilityKind::Default);
107 clang::ASTContext *astCtx;
110 std::shared_ptr<cir::LoweringPrepareCXXABI> cxxABI;
113 mlir::ModuleOp mlirModule;
116 llvm::StringMap<uint32_t> dynamicInitializerNames;
117 llvm::SmallVector<cir::FuncOp> dynamicInitializers;
120 llvm::SmallVector<std::pair<std::string, uint32_t>, 4> globalCtorList;
122 llvm::SmallVector<std::pair<std::string, uint32_t>, 4> globalDtorList;
124 void setASTContext(clang::ASTContext *
c) {
126 switch (
c->getCXXABIKind()) {
127 case clang::TargetCXXABI::GenericItanium:
133 case clang::TargetCXXABI::GenericAArch64:
134 case clang::TargetCXXABI::AppleARM64:
139 llvm_unreachable(
"NYI");
146cir::GlobalOp LoweringPreparePass::buildRuntimeVariable(
147 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
148 mlir::Type type, cir::GlobalLinkageKind linkage,
149 cir::VisibilityKind visibility) {
150 cir::GlobalOp g = dyn_cast_or_null<cir::GlobalOp>(
151 mlir::SymbolTable::lookupNearestSymbolFrom(
152 mlirModule, mlir::StringAttr::get(mlirModule->getContext(), name)));
154 g = cir::GlobalOp::create(builder, loc, name, type);
156 cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
157 mlir::SymbolTable::setSymbolVisibility(
158 g, mlir::SymbolTable::Visibility::Private);
159 g.setGlobalVisibilityAttr(
160 cir::VisibilityAttr::get(builder.getContext(), visibility));
165cir::FuncOp LoweringPreparePass::buildRuntimeFunction(
166 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
167 cir::FuncType type, cir::GlobalLinkageKind linkage) {
168 cir::FuncOp f = dyn_cast_or_null<FuncOp>(SymbolTable::lookupNearestSymbolFrom(
169 mlirModule, StringAttr::get(mlirModule->getContext(), name)));
171 f = cir::FuncOp::create(builder, loc, name, type);
173 cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
174 mlir::SymbolTable::setSymbolVisibility(
175 f, mlir::SymbolTable::Visibility::Private);
185 builder.setInsertionPoint(op);
187 mlir::Value src = op.getSrc();
188 mlir::Value imag = builder.
getNullValue(src.getType(), op.getLoc());
194 cir::CastKind elemToBoolKind) {
196 builder.setInsertionPoint(op);
198 mlir::Value src = op.getSrc();
199 if (!mlir::isa<cir::BoolType>(op.getType()))
206 cir::BoolType boolTy = builder.
getBoolTy();
207 mlir::Value srcRealToBool =
208 builder.
createCast(op.getLoc(), elemToBoolKind, srcReal, boolTy);
209 mlir::Value srcImagToBool =
210 builder.
createCast(op.getLoc(), elemToBoolKind, srcImag, boolTy);
211 return builder.
createLogicalOr(op.getLoc(), srcRealToBool, srcImagToBool);
216 cir::CastKind scalarCastKind) {
218 builder.setInsertionPoint(op);
220 mlir::Value src = op.getSrc();
221 auto dstComplexElemTy =
222 mlir::cast<cir::ComplexType>(op.getType()).getElementType();
227 mlir::Value dstReal = builder.
createCast(op.getLoc(), scalarCastKind, srcReal,
229 mlir::Value dstImag = builder.
createCast(op.getLoc(), scalarCastKind, srcImag,
234void LoweringPreparePass::lowerCastOp(cir::CastOp op) {
235 mlir::MLIRContext &ctx = getContext();
236 mlir::Value loweredValue = [&]() -> mlir::Value {
237 switch (op.getKind()) {
238 case cir::CastKind::float_to_complex:
239 case cir::CastKind::int_to_complex:
241 case cir::CastKind::float_complex_to_real:
242 case cir::CastKind::int_complex_to_real:
244 case cir::CastKind::float_complex_to_bool:
246 case cir::CastKind::int_complex_to_bool:
248 case cir::CastKind::float_complex:
250 case cir::CastKind::float_complex_to_int_complex:
252 case cir::CastKind::int_complex:
254 case cir::CastKind::int_complex_to_float_complex:
262 op.replaceAllUsesWith(loweredValue);
269 llvm::StringRef (*libFuncNameGetter)(llvm::APFloat::Semantics),
270 mlir::Location loc, cir::ComplexType ty, mlir::Value lhsReal,
271 mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag) {
272 cir::FPTypeInterface elementTy =
273 mlir::cast<cir::FPTypeInterface>(ty.getElementType());
275 llvm::StringRef libFuncName = libFuncNameGetter(
276 llvm::APFloat::SemanticsToEnum(elementTy.getFloatSemantics()));
279 cir::FuncType libFuncTy = cir::FuncType::get(libFuncInputTypes, ty);
285 mlir::OpBuilder::InsertionGuard ipGuard{builder};
286 builder.setInsertionPointToStart(pass.mlirModule.getBody());
287 libFunc = pass.buildRuntimeFunction(builder, libFuncName, loc, libFuncTy);
291 builder.
createCallOp(loc, libFunc, {lhsReal, lhsImag, rhsReal, rhsImag});
292 return call.getResult();
295static llvm::StringRef
298 case llvm::APFloat::S_IEEEhalf:
300 case llvm::APFloat::S_IEEEsingle:
302 case llvm::APFloat::S_IEEEdouble:
304 case llvm::APFloat::S_PPCDoubleDouble:
306 case llvm::APFloat::S_x87DoubleExtended:
308 case llvm::APFloat::S_IEEEquad:
311 llvm_unreachable(
"unsupported floating point type");
317 mlir::Value lhsReal, mlir::Value lhsImag,
318 mlir::Value rhsReal, mlir::Value rhsImag) {
320 mlir::Value &a = lhsReal;
321 mlir::Value &
b = lhsImag;
322 mlir::Value &
c = rhsReal;
323 mlir::Value &d = rhsImag;
325 mlir::Value ac = builder.
createBinop(loc, a, cir::BinOpKind::Mul,
c);
326 mlir::Value bd = builder.
createBinop(loc,
b, cir::BinOpKind::Mul, d);
327 mlir::Value cc = builder.
createBinop(loc,
c, cir::BinOpKind::Mul,
c);
328 mlir::Value dd = builder.
createBinop(loc, d, cir::BinOpKind::Mul, d);
330 builder.
createBinop(loc, ac, cir::BinOpKind::Add, bd);
332 builder.
createBinop(loc, cc, cir::BinOpKind::Add, dd);
333 mlir::Value resultReal =
334 builder.
createBinop(loc, acbd, cir::BinOpKind::Div, ccdd);
336 mlir::Value bc = builder.
createBinop(loc,
b, cir::BinOpKind::Mul,
c);
337 mlir::Value ad = builder.
createBinop(loc, a, cir::BinOpKind::Mul, d);
339 builder.
createBinop(loc, bc, cir::BinOpKind::Sub, ad);
340 mlir::Value resultImag =
341 builder.
createBinop(loc, bcad, cir::BinOpKind::Div, ccdd);
347 mlir::Value lhsReal, mlir::Value lhsImag,
348 mlir::Value rhsReal, mlir::Value rhsImag) {
369 mlir::Value &a = lhsReal;
370 mlir::Value &
b = lhsImag;
371 mlir::Value &
c = rhsReal;
372 mlir::Value &d = rhsImag;
374 auto trueBranchBuilder = [&](mlir::OpBuilder &, mlir::Location) {
375 mlir::Value r = builder.
createBinop(loc, d, cir::BinOpKind::Div,
377 mlir::Value rd = builder.
createBinop(loc, r, cir::BinOpKind::Mul, d);
378 mlir::Value tmp = builder.
createBinop(loc,
c, cir::BinOpKind::Add,
381 mlir::Value br = builder.
createBinop(loc,
b, cir::BinOpKind::Mul, r);
383 builder.
createBinop(loc, a, cir::BinOpKind::Add, br);
384 mlir::Value e = builder.
createBinop(loc, abr, cir::BinOpKind::Div, tmp);
386 mlir::Value ar = builder.
createBinop(loc, a, cir::BinOpKind::Mul, r);
389 mlir::Value f = builder.
createBinop(loc, bar, cir::BinOpKind::Div, tmp);
395 auto falseBranchBuilder = [&](mlir::OpBuilder &, mlir::Location) {
396 mlir::Value r = builder.
createBinop(loc,
c, cir::BinOpKind::Div,
398 mlir::Value rc = builder.
createBinop(loc, r, cir::BinOpKind::Mul,
c);
399 mlir::Value tmp = builder.
createBinop(loc, d, cir::BinOpKind::Add,
402 mlir::Value ar = builder.
createBinop(loc, a, cir::BinOpKind::Mul, r);
405 mlir::Value e = builder.
createBinop(loc, arb, cir::BinOpKind::Div, tmp);
407 mlir::Value br = builder.
createBinop(loc,
b, cir::BinOpKind::Mul, r);
409 builder.
createBinop(loc, br, cir::BinOpKind::Sub, a);
410 mlir::Value f = builder.
createBinop(loc, bra, cir::BinOpKind::Div, tmp);
416 auto cFabs = cir::FAbsOp::create(builder, loc,
c);
417 auto dFabs = cir::FAbsOp::create(builder, loc, d);
418 cir::CmpOp cmpResult =
419 builder.
createCompare(loc, cir::CmpOpKind::ge, cFabs, dFabs);
420 auto ternary = cir::TernaryOp::create(builder, loc, cmpResult,
421 trueBranchBuilder, falseBranchBuilder);
423 return ternary.getResult();
430 auto getHigherPrecisionFPType = [&context](mlir::Type type) -> mlir::Type {
431 if (mlir::isa<cir::FP16Type>(type))
432 return cir::SingleType::get(&context);
434 if (mlir::isa<cir::SingleType>(type) || mlir::isa<cir::BF16Type>(type))
435 return cir::DoubleType::get(&context);
437 if (mlir::isa<cir::DoubleType>(type))
438 return cir::LongDoubleType::get(&context, type);
443 auto getFloatTypeSemantics =
444 [&cc](mlir::Type type) ->
const llvm::fltSemantics & {
446 if (mlir::isa<cir::FP16Type>(type))
449 if (mlir::isa<cir::BF16Type>(type))
452 if (mlir::isa<cir::SingleType>(type))
455 if (mlir::isa<cir::DoubleType>(type))
458 if (mlir::isa<cir::LongDoubleType>(type)) {
460 llvm_unreachable(
"NYI Float type semantics with OpenMP");
464 if (mlir::isa<cir::FP128Type>(type)) {
466 llvm_unreachable(
"NYI Float type semantics with OpenMP");
470 llvm_unreachable(
"Unsupported float type semantics");
473 const mlir::Type higherElementType = getHigherPrecisionFPType(elementType);
474 const llvm::fltSemantics &elementTypeSemantics =
475 getFloatTypeSemantics(elementType);
476 const llvm::fltSemantics &higherElementTypeSemantics =
477 getFloatTypeSemantics(higherElementType);
486 if (llvm::APFloat::semanticsMaxExponent(elementTypeSemantics) * 2 + 1 <=
487 llvm::APFloat::semanticsMaxExponent(higherElementTypeSemantics)) {
488 return higherElementType;
498 mlir::Location loc, cir::ComplexDivOp op, mlir::Value lhsReal,
499 mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag,
501 cir::ComplexType complexTy = op.getType();
502 if (mlir::isa<cir::FPTypeInterface>(complexTy.getElementType())) {
503 cir::ComplexRangeKind range = op.getRange();
504 if (range == cir::ComplexRangeKind::Improved)
508 if (range == cir::ComplexRangeKind::Full)
510 loc, complexTy, lhsReal, lhsImag, rhsReal,
513 if (range == cir::ComplexRangeKind::Promoted) {
514 mlir::Type originalElementType = complexTy.getElementType();
515 mlir::Type higherPrecisionElementType =
517 originalElementType);
519 if (!higherPrecisionElementType)
523 cir::CastKind floatingCastKind = cir::CastKind::floating;
524 lhsReal = builder.
createCast(floatingCastKind, lhsReal,
525 higherPrecisionElementType);
526 lhsImag = builder.
createCast(floatingCastKind, lhsImag,
527 higherPrecisionElementType);
528 rhsReal = builder.
createCast(floatingCastKind, rhsReal,
529 higherPrecisionElementType);
530 rhsImag = builder.
createCast(floatingCastKind, rhsImag,
531 higherPrecisionElementType);
534 builder, loc, lhsReal, lhsImag, rhsReal, rhsImag);
539 mlir::Value finalReal =
540 builder.
createCast(floatingCastKind, resultReal, originalElementType);
541 mlir::Value finalImag =
542 builder.
createCast(floatingCastKind, resultImag, originalElementType);
551void LoweringPreparePass::lowerComplexDivOp(cir::ComplexDivOp op) {
552 cir::CIRBaseBuilderTy builder(getContext());
553 builder.setInsertionPointAfter(op);
554 mlir::Location loc = op.getLoc();
555 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
556 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
562 mlir::Value loweredResult =
564 rhsImag, getContext(), *astCtx);
565 op.replaceAllUsesWith(loweredResult);
569static llvm::StringRef
572 case llvm::APFloat::S_IEEEhalf:
574 case llvm::APFloat::S_IEEEsingle:
576 case llvm::APFloat::S_IEEEdouble:
578 case llvm::APFloat::S_PPCDoubleDouble:
580 case llvm::APFloat::S_x87DoubleExtended:
582 case llvm::APFloat::S_IEEEquad:
585 llvm_unreachable(
"unsupported floating point type");
591 mlir::Location loc, cir::ComplexMulOp op,
592 mlir::Value lhsReal, mlir::Value lhsImag,
593 mlir::Value rhsReal, mlir::Value rhsImag) {
595 mlir::Value resultRealLhs =
596 builder.
createBinop(loc, lhsReal, cir::BinOpKind::Mul, rhsReal);
597 mlir::Value resultRealRhs =
598 builder.
createBinop(loc, lhsImag, cir::BinOpKind::Mul, rhsImag);
599 mlir::Value resultImagLhs =
600 builder.
createBinop(loc, lhsReal, cir::BinOpKind::Mul, rhsImag);
601 mlir::Value resultImagRhs =
602 builder.
createBinop(loc, lhsImag, cir::BinOpKind::Mul, rhsReal);
604 loc, resultRealLhs, cir::BinOpKind::Sub, resultRealRhs);
606 loc, resultImagLhs, cir::BinOpKind::Add, resultImagRhs);
607 mlir::Value algebraicResult =
610 cir::ComplexType complexTy = op.getType();
611 cir::ComplexRangeKind rangeKind = op.getRange();
612 if (mlir::isa<cir::IntType>(complexTy.getElementType()) ||
613 rangeKind == cir::ComplexRangeKind::Basic ||
614 rangeKind == cir::ComplexRangeKind::Improved ||
615 rangeKind == cir::ComplexRangeKind::Promoted)
616 return algebraicResult;
623 mlir::Value resultRealIsNaN = builder.
createIsNaN(loc, resultReal);
624 mlir::Value resultImagIsNaN = builder.
createIsNaN(loc, resultImag);
625 mlir::Value resultRealAndImagAreNaN =
628 return cir::TernaryOp::create(
629 builder, loc, resultRealAndImagAreNaN,
630 [&](mlir::OpBuilder &, mlir::Location) {
633 lhsReal, lhsImag, rhsReal, rhsImag);
636 [&](mlir::OpBuilder &, mlir::Location) {
642void LoweringPreparePass::lowerComplexMulOp(cir::ComplexMulOp op) {
643 cir::CIRBaseBuilderTy builder(getContext());
644 builder.setInsertionPointAfter(op);
645 mlir::Location loc = op.getLoc();
646 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
647 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
652 mlir::Value loweredResult =
lowerComplexMul(*
this, builder, loc, op, lhsReal,
653 lhsImag, rhsReal, rhsImag);
654 op.replaceAllUsesWith(loweredResult);
658void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
659 mlir::Type ty = op.getType();
660 if (!mlir::isa<cir::ComplexType>(ty))
663 mlir::Location loc = op.getLoc();
664 cir::UnaryOpKind opKind = op.getKind();
666 CIRBaseBuilderTy builder(getContext());
667 builder.setInsertionPointAfter(op);
669 mlir::Value operand = op.getInput();
673 mlir::Value resultReal;
674 mlir::Value resultImag;
677 case cir::UnaryOpKind::Inc:
678 case cir::UnaryOpKind::Dec:
679 resultReal = builder.
createUnaryOp(loc, opKind, operandReal);
680 resultImag = operandImag;
683 case cir::UnaryOpKind::Plus:
684 case cir::UnaryOpKind::Minus:
685 resultReal = builder.
createUnaryOp(loc, opKind, operandReal);
686 resultImag = builder.
createUnaryOp(loc, opKind, operandImag);
689 case cir::UnaryOpKind::Not:
690 resultReal = operandReal;
692 builder.
createUnaryOp(loc, cir::UnaryOpKind::Minus, operandImag);
697 op.replaceAllUsesWith(result);
701cir::FuncOp LoweringPreparePass::getOrCreateDtorFunc(CIRBaseBuilderTy &builder,
703 mlir::Region &dtorRegion,
704 cir::CallOp &dtorCall) {
705 mlir::OpBuilder::InsertionGuard guard(builder);
709 cir::VoidType voidTy = builder.
getVoidTy();
710 auto voidPtrTy = cir::PointerType::get(voidTy);
713 mlir::Block &dtorBlock = dtorRegion.front();
717 auto opIt = dtorBlock.getOperations().begin();
718 cir::GetGlobalOp ggop = mlir::cast<cir::GetGlobalOp>(*opIt);
729 if (dtorBlock.getOperations().size() == 3) {
730 auto callOp = mlir::dyn_cast<cir::CallOp>(&*(++opIt));
731 auto yieldOp = mlir::dyn_cast<cir::YieldOp>(&*(++opIt));
732 if (yieldOp && callOp && callOp.getNumOperands() == 1 &&
733 callOp.getArgOperand(0) == ggop) {
742 builder.setInsertionPointAfter(op);
743 SmallString<256> fnName(
"__cxx_global_array_dtor");
744 uint32_t cnt = dynamicInitializerNames[fnName]++;
746 fnName +=
"." + std::to_string(cnt);
749 auto fnType = cir::FuncType::get({voidPtrTy}, voidTy);
750 cir::FuncOp dtorFunc =
751 buildRuntimeFunction(builder, fnName, op.getLoc(), fnType,
752 cir::GlobalLinkageKind::InternalLinkage);
753 mlir::Block *entryBB = dtorFunc.addEntryBlock();
756 entryBB->getOperations().splice(entryBB->begin(), dtorBlock.getOperations(),
757 dtorBlock.begin(), dtorBlock.end());
760 cir::GetGlobalOp dtorGGop =
761 mlir::cast<cir::GetGlobalOp>(entryBB->getOperations().front());
762 builder.setInsertionPointToStart(&dtorBlock);
763 builder.clone(*dtorGGop.getOperation());
767 mlir::Value dtorArg = entryBB->getArgument(0);
768 dtorGGop.replaceAllUsesWith(dtorArg);
772 mlir::Block &finalBlock = dtorFunc.getBody().back();
773 auto yieldOp = cast<cir::YieldOp>(finalBlock.getTerminator());
774 builder.setInsertionPoint(yieldOp);
775 cir::ReturnOp::create(builder, yieldOp->getLoc());
780 cir::GetGlobalOp origGGop =
781 mlir::cast<cir::GetGlobalOp>(dtorBlock.getOperations().front());
782 builder.setInsertionPointAfter(origGGop);
783 mlir::Value ggopResult = origGGop.getResult();
784 dtorCall = builder.
createCallOp(op.getLoc(), dtorFunc, ggopResult);
787 auto finalYield = cir::YieldOp::create(builder, op.getLoc());
790 dtorBlock.getOperations().erase(std::next(mlir::Block::iterator(finalYield)),
792 dtorRegion.getBlocks().erase(std::next(dtorRegion.begin()), dtorRegion.end());
798LoweringPreparePass::buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op) {
801 SmallString<256> fnName(
"__cxx_global_var_init");
803 uint32_t cnt = dynamicInitializerNames[fnName]++;
805 fnName +=
"." + std::to_string(cnt);
808 CIRBaseBuilderTy builder(getContext());
809 builder.setInsertionPointAfter(op);
810 cir::VoidType voidTy = builder.
getVoidTy();
811 auto fnType = cir::FuncType::get({}, voidTy);
812 FuncOp f = buildRuntimeFunction(builder, fnName, op.getLoc(), fnType,
813 cir::GlobalLinkageKind::InternalLinkage);
816 mlir::Block *entryBB = f.addEntryBlock();
817 if (!op.getCtorRegion().empty()) {
818 mlir::Block &block = op.getCtorRegion().front();
819 entryBB->getOperations().splice(entryBB->begin(), block.getOperations(),
820 block.begin(), std::prev(block.end()));
824 mlir::Region &dtorRegion = op.getDtorRegion();
825 if (!dtorRegion.empty()) {
830 builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
831 cir::GlobalOp handle = buildRuntimeVariable(
832 builder,
"__dso_handle", op.getLoc(), builder.getI8Type(),
833 cir::GlobalLinkageKind::ExternalLinkage, cir::VisibilityKind::Hidden);
839 cir::CallOp dtorCall;
840 cir::FuncOp dtorFunc =
841 getOrCreateDtorFunc(builder, op, dtorRegion, dtorCall);
845 auto voidPtrTy = cir::PointerType::get(voidTy);
846 auto voidFnTy = cir::FuncType::get({voidPtrTy}, voidTy);
847 auto voidFnPtrTy = cir::PointerType::get(voidFnTy);
848 auto handlePtrTy = cir::PointerType::get(handle.getSymType());
850 cir::FuncType::get({voidFnPtrTy, voidPtrTy, handlePtrTy}, voidTy);
851 const char *nameAtExit =
"__cxa_atexit";
852 cir::FuncOp fnAtExit =
853 buildRuntimeFunction(builder, nameAtExit, op.getLoc(), fnAtExitType);
857 builder.setInsertionPointAfter(dtorCall);
859 auto dtorPtrTy = cir::PointerType::get(dtorFunc.getFunctionType());
861 args[0] = cir::GetGlobalOp::create(builder, dtorCall.getLoc(), dtorPtrTy,
862 dtorFunc.getSymName());
863 args[0] = cir::CastOp::create(builder, dtorCall.getLoc(), voidFnPtrTy,
864 cir::CastKind::bitcast, args[0]);
866 cir::CastOp::create(builder, dtorCall.getLoc(), voidPtrTy,
867 cir::CastKind::bitcast, dtorCall.getArgOperand(0));
868 args[2] = cir::GetGlobalOp::create(builder, handle.getLoc(), handlePtrTy,
869 handle.getSymName());
870 builder.
createCallOp(dtorCall.getLoc(), fnAtExit, args);
872 mlir::Block &dtorBlock = dtorRegion.front();
873 entryBB->getOperations().splice(entryBB->end(), dtorBlock.getOperations(),
875 std::prev(dtorBlock.end()));
879 builder.setInsertionPointToEnd(entryBB);
880 mlir::Operation *yieldOp =
nullptr;
881 if (!op.getCtorRegion().empty()) {
882 mlir::Block &block = op.getCtorRegion().front();
883 yieldOp = &block.getOperations().back();
885 assert(!dtorRegion.empty());
886 mlir::Block &block = dtorRegion.front();
887 yieldOp = &block.getOperations().back();
890 assert(isa<cir::YieldOp>(*yieldOp));
891 cir::ReturnOp::create(builder, yieldOp->getLoc());
895void LoweringPreparePass::lowerGlobalOp(GlobalOp op) {
896 mlir::Region &ctorRegion = op.getCtorRegion();
897 mlir::Region &dtorRegion = op.getDtorRegion();
899 if (!ctorRegion.empty() || !dtorRegion.empty()) {
902 cir::FuncOp f = buildCXXGlobalVarDeclInitFunc(op);
905 ctorRegion.getBlocks().clear();
906 dtorRegion.getBlocks().clear();
909 dynamicInitializers.push_back(f);
915template <
typename AttributeTy>
916static llvm::SmallVector<mlir::Attribute>
920 for (
const auto &[name, priority] : list)
921 attrs.push_back(AttributeTy::get(context, name, priority));
925void LoweringPreparePass::buildGlobalCtorDtorList() {
926 if (!globalCtorList.empty()) {
927 llvm::SmallVector<mlir::Attribute> globalCtors =
931 mlirModule->setAttr(cir::CIRDialect::getGlobalCtorsAttrName(),
932 mlir::ArrayAttr::get(&getContext(), globalCtors));
935 if (!globalDtorList.empty()) {
936 llvm::SmallVector<mlir::Attribute> globalDtors =
939 mlirModule->setAttr(cir::CIRDialect::getGlobalDtorsAttrName(),
940 mlir::ArrayAttr::get(&getContext(), globalDtors));
944void LoweringPreparePass::buildCXXGlobalInitFunc() {
945 if (dynamicInitializers.empty())
952 SmallString<256> fnName;
960 llvm::raw_svector_ostream
out(fnName);
961 std::unique_ptr<clang::MangleContext> mangleCtx(
963 cast<clang::ItaniumMangleContext>(*mangleCtx)
966 fnName +=
"_GLOBAL__sub_I_";
970 CIRBaseBuilderTy builder(getContext());
971 builder.setInsertionPointToEnd(&mlirModule.getBodyRegion().back());
972 auto fnType = cir::FuncType::get({}, builder.
getVoidTy());
974 buildRuntimeFunction(builder, fnName, mlirModule.getLoc(), fnType,
975 cir::GlobalLinkageKind::ExternalLinkage);
976 builder.setInsertionPointToStart(f.addEntryBlock());
977 for (cir::FuncOp &f : dynamicInitializers)
981 globalCtorList.emplace_back(fnName,
982 cir::GlobalCtorAttr::getDefaultPriority());
984 cir::ReturnOp::create(builder, f.getLoc());
987void LoweringPreparePass::lowerDynamicCastOp(DynamicCastOp op) {
988 CIRBaseBuilderTy builder(getContext());
989 builder.setInsertionPointAfter(op);
991 assert(astCtx &&
"AST context is not available during lowering prepare");
992 auto loweredValue = cxxABI->lowerDynamicCast(builder, *astCtx, op);
994 op.replaceAllUsesWith(loweredValue);
1000 mlir::Operation *op, mlir::Type eltTy,
1001 mlir::Value arrayAddr, uint64_t arrayLen,
1004 mlir::Location loc = op->getLoc();
1008 const unsigned sizeTypeSize =
1010 uint64_t endOffset = isCtor ? arrayLen : arrayLen - 1;
1011 mlir::Value endOffsetVal =
1014 auto begin = cir::CastOp::create(builder, loc, eltTy,
1015 cir::CastKind::array_to_ptrdecay, arrayAddr);
1017 cir::PtrStrideOp::create(builder, loc, eltTy, begin, endOffsetVal);
1018 mlir::Value start = isCtor ? begin : end;
1019 mlir::Value stop = isCtor ? end : begin;
1029 [&](mlir::OpBuilder &
b, mlir::Location loc) {
1030 auto currentElement = cir::LoadOp::create(
b, loc, eltTy, tmpAddr);
1031 mlir::Type boolTy = cir::BoolType::get(
b.getContext());
1032 auto cmp = cir::CmpOp::create(builder, loc, boolTy, cir::CmpOpKind::ne,
1033 currentElement, stop);
1037 [&](mlir::OpBuilder &
b, mlir::Location loc) {
1038 auto currentElement = cir::LoadOp::create(
b, loc, eltTy, tmpAddr);
1040 cir::CallOp ctorCall;
1041 op->walk([&](cir::CallOp
c) { ctorCall =
c; });
1042 assert(ctorCall &&
"expected ctor call");
1051 ctorCall->moveBefore(stride.getDefiningOp());
1052 ctorCall->setOperand(0, currentElement);
1053 auto nextElement = cir::PtrStrideOp::create(builder, loc, eltTy,
1054 currentElement, stride);
1061 op->replaceAllUsesWith(loop);
1065void LoweringPreparePass::lowerArrayDtor(cir::ArrayDtor op) {
1066 CIRBaseBuilderTy builder(getContext());
1067 builder.setInsertionPointAfter(op.getOperation());
1069 mlir::Type eltTy = op->getRegion(0).getArgument(0).getType();
1072 mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize();
1077void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
1078 cir::CIRBaseBuilderTy builder(getContext());
1079 builder.setInsertionPointAfter(op.getOperation());
1081 mlir::Type eltTy = op->getRegion(0).getArgument(0).getType();
1084 mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize();
1089void LoweringPreparePass::runOnOp(mlir::Operation *op) {
1090 if (
auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) {
1091 lowerArrayCtor(arrayCtor);
1092 }
else if (
auto arrayDtor = dyn_cast<cir::ArrayDtor>(op)) {
1093 lowerArrayDtor(arrayDtor);
1094 }
else if (
auto cast = mlir::dyn_cast<cir::CastOp>(op)) {
1096 }
else if (
auto complexDiv = mlir::dyn_cast<cir::ComplexDivOp>(op)) {
1097 lowerComplexDivOp(complexDiv);
1098 }
else if (
auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op)) {
1099 lowerComplexMulOp(complexMul);
1100 }
else if (
auto glob = mlir::dyn_cast<cir::GlobalOp>(op)) {
1101 lowerGlobalOp(glob);
1102 }
else if (
auto dynamicCast = mlir::dyn_cast<cir::DynamicCastOp>(op)) {
1103 lowerDynamicCastOp(dynamicCast);
1104 }
else if (
auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) {
1105 lowerUnaryOp(unary);
1106 }
else if (
auto fnOp = dyn_cast<cir::FuncOp>(op)) {
1107 if (
auto globalCtor = fnOp.getGlobalCtorPriority())
1108 globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
1109 else if (
auto globalDtor = fnOp.getGlobalDtorPriority())
1110 globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
1114void LoweringPreparePass::runOnOperation() {
1115 mlir::Operation *op = getOperation();
1116 if (isa<::mlir::ModuleOp>(op))
1117 mlirModule = cast<::mlir::ModuleOp>(op);
1119 llvm::SmallVector<mlir::Operation *> opsToTransform;
1121 op->walk([&](mlir::Operation *op) {
1122 if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
1123 cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
1124 cir::FuncOp, cir::GlobalOp, cir::UnaryOp>(op))
1125 opsToTransform.push_back(op);
1128 for (mlir::Operation *o : opsToTransform)
1131 buildCXXGlobalInitFunc();
1132 buildGlobalCtorDtorList();
1136 return std::make_unique<LoweringPreparePass>();
1139std::unique_ptr<Pass>
1141 auto pass = std::make_unique<LoweringPreparePass>();
1142 pass->setASTContext(astCtx);
1143 return std::move(pass);
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 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 ...
MangleContext * createMangleContext(const TargetInfo *T=nullptr)
If T is null pointer, assume the target in ASTContext.
const LangOptions & getLangOpts() const
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
const TargetInfo & getTargetInfo() const
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.
Exposes information about the current target.
const llvm::fltSemantics & getDoubleFormat() const
const llvm::fltSemantics & getHalfFormat() const
const llvm::fltSemantics & getBFloat16Format() const
const llvm::fltSemantics & getLongDoubleFormat() const
const llvm::fltSemantics & getFloatFormat() const
const llvm::fltSemantics & getFloat128Format() const
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_.
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()