11#include "mlir/IR/Attributes.h"
12#include "mlir/IR/BuiltinAttributeInterfaces.h"
13#include "mlir/IR/IRMapping.h"
14#include "mlir/IR/Location.h"
15#include "mlir/IR/Value.h"
31#include "llvm/ADT/StringRef.h"
32#include "llvm/ADT/TypeSwitch.h"
33#include "llvm/IR/Instructions.h"
34#include "llvm/Support/ErrorHandling.h"
35#include "llvm/Support/Path.h"
36#include "llvm/Support/VersionTuple.h"
46#define GEN_PASS_DEF_LOWERINGPREPARE
47#include "clang/CIR/Dialect/Passes.h.inc"
51 SmallString<128> fileName;
53 if (mlirModule.getSymName())
54 fileName = llvm::sys::path::filename(mlirModule.getSymName()->str());
59 for (
size_t i = 0; i < fileName.size(); ++i) {
70struct LoweringPreparePass
71 :
public impl::LoweringPrepareBase<LoweringPreparePass> {
72 LoweringPreparePass() =
default;
82 LoweringPreparePass(
const LoweringPreparePass &other)
83 : impl::LoweringPrepareBase<LoweringPreparePass>(other) {}
85 void runOnOperation()
override;
87 void runOnOp(mlir::Operation *op);
88 void lowerCastOp(cir::CastOp op);
89 void lowerComplexConjOp(cir::ComplexConjOp op);
90 void lowerComplexDivOp(cir::ComplexDivOp op);
91 void lowerComplexMulOp(cir::ComplexMulOp op);
92 void lowerComplexFDivOp(cir::ComplexFDivOp op);
93 void lowerComplexFMulOp(cir::ComplexFMulOp op);
94 void lowerGetGlobalOp(cir::GetGlobalOp op);
95 void lowerGlobalOp(cir::GlobalOp op);
96 void lowerThreeWayCmpOp(cir::CmpThreeWayOp op);
97 void lowerArrayDtor(cir::ArrayDtor op);
98 void lowerArrayCtor(cir::ArrayCtor op);
99 void lowerTrivialCopyCall(cir::CallOp op);
100 void lowerStoreOfConstAggregate(cir::StoreOp op);
101 void lowerLocalInitOp(cir::LocalInitOp op);
102 void lowerRegisterExitDtorOp(cir::RegisterExitDtorOp op);
103 void lowerStdOp(cir::StdOpInterface op);
108 cir::FuncOp getCalledFunction(cir::CallOp callOp);
118 getOrCreateConstAggregateGlobal(CIRBaseBuilderTy &builder, mlir::Location loc,
119 llvm::StringRef baseName, mlir::Type ty,
120 mlir::TypedAttr constant, uint64_t alignment);
123 cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
126 void defineGlobalThreadLocalWrapper(cir::GlobalOp op, cir::FuncOp initAlias,
127 bool isVarDefinition);
129 cir::FuncOp defineGlobalThreadLocalInitAlias(cir::GlobalOp op,
130 cir::FuncOp aliasee);
132 cir::FuncOp getOrCreateThreadLocalWrapper(CIRBaseBuilderTy &builder,
139 cir::IfOp buildInitGuardCheck(CIRBaseBuilderTy &builder, mlir::Location loc,
140 cir::GlobalOp guard,
bool threadLocal);
142 cir::FuncOp getOrCreateDtorFunc(CIRBaseBuilderTy &builder, cir::GlobalOp op,
143 mlir::Region &dtorRegion,
144 cir::CallOp &dtorCall);
147 cir::FuncOp buildGlobalArrayDtorFunc(CIRBaseBuilderTy &builder,
148 mlir::Operation *op);
158 buildGlobalInitCallerFunc(llvm::StringRef fnName,
159 cir::GlobalLinkageKind linkage,
160 llvm::ArrayRef<cir::FuncOp> initializers,
161 uint32_t priority, cir::GlobalOp guard = {});
164 void buildCXXGlobalInitFunc();
170 void buildCXXGlobalPriorityInitFuncs(
171 llvm::SmallVectorImpl<cir::FuncOp> &importedInits);
174 void buildCXXGlobalTlsFunc();
177 void buildGlobalCtorDtorList();
179 cir::FuncOp buildRuntimeFunction(
180 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
182 cir::GlobalLinkageKind linkage = cir::GlobalLinkageKind::ExternalLinkage);
184 cir::GlobalOp getOrCreateRuntimeVariable(
185 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
187 cir::GlobalLinkageKind linkage = cir::GlobalLinkageKind::ExternalLinkage,
188 cir::VisibilityKind visibility = cir::VisibilityKind::Default);
194 llvm::StringMap<FuncOp> cudaKernelMap;
195 llvm::SmallVector<std::pair<cir::GlobalOp, cir::CUDAVarRegistrationInfoAttr>>
200 void buildCUDAModuleCtor();
201 std::optional<FuncOp> buildCUDAModuleDtor();
202 std::optional<FuncOp> buildHIPModuleDtor();
203 std::optional<FuncOp> buildCUDARegisterGlobals();
204 void buildCUDARegisterVars(cir::CIRBaseBuilderTy &builder,
205 FuncOp regGlobalFunc);
206 void buildCUDARegisterGlobalFunctions(cir::CIRBaseBuilderTy &builder,
207 FuncOp regGlobalFunc);
210 void handleStaticLocal(cir::GlobalOp globalOp, cir::LocalInitOp localInitOp);
214 void emitGuardedInit(CIRBaseBuilderTy &builder, cir::GlobalOp globalOp,
215 mlir::Region &ctorRegion, mlir::Region &dtorRegion);
227 cir::FuncOp getTlsInitFn();
230 cir::GlobalOp createGlobalThreadLocalGuard(CIRBaseBuilderTy &builder,
234 cir::GlobalOp createGuardGlobalOp(CIRBaseBuilderTy &builder,
235 mlir::Location loc, llvm::StringRef name,
236 cir::IntType guardTy,
237 cir::GlobalLinkageKind linkage);
241 void addUsedGlobal(cir::GlobalOp global);
244 cir::GlobalOp getStaticLocalDeclGuardAddress(llvm::StringRef globalSymName) {
245 auto it = staticLocalDeclGuardMap.find(globalSymName);
246 if (it != staticLocalDeclGuardMap.end())
252 void setStaticLocalDeclGuardAddress(llvm::StringRef globalSymName,
253 cir::GlobalOp guard) {
254 staticLocalDeclGuardMap[globalSymName] = guard;
258 cir::GlobalOp getOrCreateStaticLocalDeclGuardAddress(
259 CIRBaseBuilderTy &builder, cir::GlobalOp globalOp, StringRef guardName,
260 bool isLocalVarDecl,
bool useInt8GuardVariable) {
262 cir::CIRDataLayout dataLayout(mlirModule);
263 cir::IntType guardTy;
264 clang::CharUnits guardAlignment;
267 if (useInt8GuardVariable) {
268 guardTy = cir::IntType::get(&getContext(), 8,
true);
270 }
else if (useARMGuardVarABI()) {
272 const unsigned sizeTypeSize =
273 getTargetInfo().getTypeWidth(getTargetInfo().getSignedSizeType());
275 cir::IntType::get(&getContext(), sizeTypeSize,
true);
279 guardTy = cir::IntType::get(&getContext(), 64,
true);
283 assert(guardTy && guardAlignment.
getQuantity() != 0);
285 llvm::StringRef globalSymName = globalOp.getSymName();
286 cir::GlobalOp guard = getStaticLocalDeclGuardAddress(globalSymName);
289 guard = createGuardGlobalOp(builder, globalOp->getLoc(), guardName,
290 guardTy, globalOp.getLinkage());
291 guard.setInitialValueAttr(cir::IntAttr::get(guardTy, 0));
292 guard.setDSOLocal(globalOp.getDsoLocal());
293 guard.setAlignment(guardAlignment.
getAsAlign().value());
294 guard.setTlsModel(globalOp.getTlsModel());
295 guard.setGlobalVisibility(globalOp.getGlobalVisibility());
301 std::optional<llvm::StringRef> comdat = globalOp.getComdat();
302 const llvm::Triple &triple = getTargetInfo().getTriple();
303 if (!isLocalVarDecl && comdat.has_value() &&
304 (triple.isOSBinFormatELF() || triple.isOSBinFormatWasm())) {
305 guard.setComdat(comdat->empty() ? globalOp.getSymName() : *comdat);
306 }
else if (triple.supportsCOMDAT() && guard.isWeakForLinker()) {
309 guard.setSelfComdat();
312 setStaticLocalDeclGuardAddress(globalSymName, guard);
318 std::unique_ptr<cir::LowerModule> lowerModule;
320 const clang::TargetInfo &getTargetInfo()
const {
321 assert(lowerModule &&
"LoweringPrepare requires a module with a triple");
322 return lowerModule->getTarget();
325 const clang::LangOptions &getLangOpts()
const {
326 assert(lowerModule &&
"LoweringPrepare requires a module with LangOptions");
327 return lowerModule->getLangOpts();
336 std::optional<llvm::VersionTuple> getSDKVersion() {
337 auto sdkVersionAttr = mlirModule->getAttrOfType<mlir::StringAttr>(
338 CIRDialect::getSDKVersionAttrName());
340 return llvm::VersionTuple();
342 llvm::VersionTuple sdkVersion;
343 if (sdkVersion.tryParse(sdkVersionAttr.getValue())) {
344 mlirModule->emitError(
"cannot parse platform SDK version from ")
345 << CIRDialect::getSDKVersionAttrName() <<
" = '"
346 << sdkVersionAttr.getValue() <<
"'";
355 std::string addCUIDSuffix(llvm::StringRef name) {
356 std::string result =
name.str();
357 if (
auto cuidHash = mlirModule->getAttrOfType<mlir::StringAttr>(
358 CIRDialect::getCUIDHashAttrName()))
359 result += (
"_" + cuidHash.getValue()).str();
364 mlir::ModuleOp mlirModule;
384 mlir::SymbolTableCollection symbolTables;
387 llvm::StringMap<uint32_t> dynamicInitializerNames;
388 llvm::SmallVector<cir::FuncOp> dynamicInitializers;
393 std::map<unsigned, llvm::SmallVector<cir::FuncOp, 4>>
394 prioritizedDynamicInitializers;
395 llvm::SmallVector<cir::FuncOp> globalThreadLocalInitializers;
396 llvm::StringMap<cir::FuncOp> threadLocalWrappers;
397 llvm::StringMap<cir::FuncOp> threadLocalInitAliases;
400 llvm::StringMap<cir::GlobalOp> staticLocalDeclGuardMap;
402 llvm::StringMap<llvm::SmallVector<cir::GlobalOp, 1>> constAggregateGlobals;
405 llvm::SmallVector<cir::GlobalCtorDtorEntry, 4> globalCtorList;
407 llvm::SmallVector<cir::GlobalCtorDtorEntry, 4> globalDtorList;
411 bool useARMGuardVarABI()
const {
412 switch (lowerModule->getCXXABIKind()) {
413 case clang::TargetCXXABI::GenericARM:
414 case clang::TargetCXXABI::iOS:
415 case clang::TargetCXXABI::WatchOS:
416 case clang::TargetCXXABI::GenericAArch64:
417 case clang::TargetCXXABI::WebAssembly:
426 cir::CallOp emitAtExitCall(CIRBaseBuilderTy &builder, mlir::Location loc,
427 cir::FuncOp dtorFunc, mlir::Value arg,
bool tls) {
428 cir::GlobalOp handle;
429 cir::FuncOp fnAtExit;
431 cir::PointerType voidFnPtrTy = builder.
getVoidFnPtrTy({voidPtrTy});
433 mlir::OpBuilder::InsertionGuard guard(builder);
435 builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
436 handle = getOrCreateRuntimeVariable(
437 builder,
"__dso_handle", loc, builder.
getUIntNTy(8),
438 cir::GlobalLinkageKind::ExternalLinkage, cir::VisibilityKind::Hidden);
442 cir::PointerType handlePtrTy = builder.
getPointerTo(handle.getSymType());
445 cir::FuncType::get({voidFnPtrTy, voidPtrTy, handlePtrTy}, intTy);
447 llvm::StringLiteral nameAtExit =
"__cxa_atexit";
449 nameAtExit = getTargetInfo().getTriple().isOSDarwin()
450 ? llvm::StringLiteral(
"_tlv_atexit")
451 : llvm::StringLiteral(
"__cxa_thread_atexit");
453 fnAtExit = buildRuntimeFunction(builder, nameAtExit, loc, fnAtExitType);
457 auto dtorPtrTy = cir::PointerType::get(dtorFunc.getFunctionType());
458 args[0] = cir::GetGlobalOp::create(builder, loc, dtorPtrTy,
459 dtorFunc.getSymName());
460 args[0] = cir::CastOp::create(builder, loc, voidFnPtrTy,
461 cir::CastKind::bitcast, args[0]);
462 args[1] = cir::CastOp::create(builder, loc, voidPtrTy,
463 cir::CastKind::bitcast, arg);
464 args[2] = cir::GetGlobalOp::create(
465 builder, loc, builder.
getPointerTo(handle.getSymType()),
466 handle.getSymName());
472 void emitGlobalGuardedDtorRegion(CIRBaseBuilderTy &builder,
473 cir::GlobalOp global,
474 mlir::Region &dtorRegion,
bool tls,
475 mlir::Block &entryBB) {
480 cir::CallOp dtorCall;
481 cir::FuncOp dtorFunc =
482 getOrCreateDtorFunc(builder, global, dtorRegion, dtorCall);
486 builder.setInsertionPointAfter(dtorCall);
487 emitAtExitCall(builder, dtorCall.getLoc(), dtorFunc,
488 dtorCall.getArgOperand(0), tls);
490 mlir::Block &dtorBlock = dtorRegion.front();
491 entryBB.getOperations().splice(entryBB.end(), dtorBlock.getOperations(),
493 std::prev(dtorBlock.end()));
496 builder.setInsertionPointToEnd(&entryBB);
502 void emitCXXGuardedInitIf(CIRBaseBuilderTy &builder, cir::GlobalOp globalOp,
503 mlir::Region &ctorRegion, mlir::Region &dtorRegion,
504 bool isLocalVarDecl, mlir::Value guardPtr,
505 cir::PointerType guardPtrTy,
bool threadsafe) {
506 auto loc = globalOp->getLoc();
529 mlir::Block *insertBlock = builder.getInsertionBlock();
530 if (!ctorRegion.empty()) {
531 assert(ctorRegion.hasOneBlock() &&
"Enforced by MaxSizedRegion<1>");
533 mlir::Block &block = ctorRegion.front();
534 insertBlock->getOperations().splice(
535 insertBlock->end(), block.getOperations(), block.begin(),
536 std::prev(block.end()));
539 if (!dtorRegion.empty()) {
540 assert(dtorRegion.hasOneBlock() &&
"Enforced by MaxSizedRegion<1>");
546 emitGlobalGuardedDtorRegion(builder, globalOp, dtorRegion,
547 globalOp.getTlsModel().has_value(),
550 builder.setInsertionPointToEnd(insertBlock);
551 ctorRegion.getBlocks().clear();
559 mlir::Value acquireResult = acquireCall.getResult();
562 loc, mlir::cast<cir::IntType>(acquireResult.getType()), 0);
563 auto shouldInit = builder.
createCompare(loc, cir::CmpOpKind::ne,
564 acquireResult, acquireZero);
569 cir::IfOp::create(builder, loc, shouldInit,
false,
570 [](mlir::OpBuilder &, mlir::Location) {});
571 mlir::OpBuilder::InsertionGuard insertGuard(builder);
572 builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
584 if (getLangOpts().Exceptions) {
585 cir::CleanupScopeOp::create(
586 builder, loc, cir::CleanupKind::EH,
587 [&](mlir::OpBuilder &, mlir::Location bodyLoc) {
591 [&](mlir::OpBuilder &, mlir::Location cleanupLoc) {
592 cir::CallOp abortCall =
594 mlir::ValueRange{guardPtr});
598 abortCall.setNothrowAttr(builder.getUnitAttr());
601 builder.setInsertionPointToEnd(&ifOp.getThenRegion().front());
608 mlir::ValueRange{guardPtr});
611 }
else if (!isLocalVarDecl) {
616 guardPtr, cir::PointerType::get(builder.
getSIntNTy(8)));
627 guardPtr, cir::PointerType::get(builder.
getSIntNTy(8)));
639cir::GlobalOp LoweringPreparePass::getOrCreateRuntimeVariable(
640 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
641 mlir::Type type, cir::GlobalLinkageKind linkage,
642 cir::VisibilityKind visibility) {
643 cir::GlobalOp g = dyn_cast_or_null<cir::GlobalOp>(
644 mlir::SymbolTable::lookupNearestSymbolFrom(
645 mlirModule, mlir::StringAttr::get(mlirModule->getContext(), name)));
647 g = cir::GlobalOp::create(builder, loc, name, type);
649 cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
650 mlir::SymbolTable::setSymbolVisibility(
651 g, mlir::SymbolTable::Visibility::Private);
652 g.setGlobalVisibility(visibility);
657cir::FuncOp LoweringPreparePass::buildRuntimeFunction(
658 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
659 cir::FuncType type, cir::GlobalLinkageKind linkage) {
660 cir::FuncOp f = dyn_cast_or_null<FuncOp>(SymbolTable::lookupNearestSymbolFrom(
661 mlirModule, StringAttr::get(mlirModule->getContext(), name)));
663 f = cir::FuncOp::create(builder, loc, name, type);
665 cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
666 mlir::SymbolTable::setSymbolVisibility(
667 f, mlir::SymbolTable::Visibility::Private);
677 builder.setInsertionPoint(op);
679 mlir::Value src = op.getSrc();
680 mlir::Value imag = builder.
getNullValue(src.getType(), op.getLoc());
686 cir::CastKind elemToBoolKind) {
688 builder.setInsertionPoint(op);
690 mlir::Value src = op.getSrc();
691 if (!mlir::isa<cir::BoolType>(op.getType()))
698 cir::BoolType boolTy = builder.
getBoolTy();
699 mlir::Value srcRealToBool =
700 builder.
createCast(op.getLoc(), elemToBoolKind, srcReal, boolTy);
701 mlir::Value srcImagToBool =
702 builder.
createCast(op.getLoc(), elemToBoolKind, srcImag, boolTy);
703 return builder.
createLogicalOr(op.getLoc(), srcRealToBool, srcImagToBool);
708 cir::CastKind scalarCastKind) {
710 builder.setInsertionPoint(op);
712 mlir::Value src = op.getSrc();
713 auto dstComplexElemTy =
714 mlir::cast<cir::ComplexType>(op.getType()).getElementType();
719 mlir::Value dstReal = builder.
createCast(op.getLoc(), scalarCastKind, srcReal,
721 mlir::Value dstImag = builder.
createCast(op.getLoc(), scalarCastKind, srcImag,
726void LoweringPreparePass::lowerCastOp(cir::CastOp op) {
727 mlir::MLIRContext &ctx = getContext();
728 mlir::Value loweredValue = [&]() -> mlir::Value {
729 switch (op.getKind()) {
730 case cir::CastKind::float_to_complex:
731 case cir::CastKind::int_to_complex:
733 case cir::CastKind::float_complex_to_real:
734 case cir::CastKind::int_complex_to_real:
736 case cir::CastKind::float_complex_to_bool:
738 case cir::CastKind::int_complex_to_bool:
740 case cir::CastKind::float_complex:
742 case cir::CastKind::float_complex_to_int_complex:
744 case cir::CastKind::int_complex:
746 case cir::CastKind::int_complex_to_float_complex:
754 op.replaceAllUsesWith(loweredValue);
761 llvm::StringRef (*libFuncNameGetter)(llvm::APFloat::Semantics),
762 mlir::Location loc, cir::ComplexType ty, mlir::Value lhsReal,
763 mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag) {
764 cir::FPTypeInterface elementTy =
765 mlir::cast<cir::FPTypeInterface>(ty.getElementType());
767 llvm::StringRef libFuncName = libFuncNameGetter(
768 llvm::APFloat::SemanticsToEnum(elementTy.getFloatSemantics()));
771 cir::FuncType libFuncTy = cir::FuncType::get(libFuncInputTypes, ty);
777 mlir::OpBuilder::InsertionGuard ipGuard{builder};
778 builder.setInsertionPointToStart(pass.mlirModule.getBody());
779 libFunc = pass.buildRuntimeFunction(builder, libFuncName, loc, libFuncTy);
785 builder.
createCallOp(loc, libFunc, {lhsReal, lhsImag, rhsReal, rhsImag});
786 return call.getResult();
789static llvm::StringRef
792 case llvm::APFloat::S_IEEEhalf:
794 case llvm::APFloat::S_IEEEsingle:
796 case llvm::APFloat::S_IEEEdouble:
798 case llvm::APFloat::S_PPCDoubleDouble:
800 case llvm::APFloat::S_x87DoubleExtended:
802 case llvm::APFloat::S_IEEEquad:
805 llvm_unreachable(
"unsupported floating point type");
811 mlir::Value lhsReal, mlir::Value lhsImag,
812 mlir::Value rhsReal, mlir::Value rhsImag) {
814 mlir::Value &a = lhsReal;
815 mlir::Value &b = lhsImag;
816 mlir::Value &c = rhsReal;
817 mlir::Value &d = rhsImag;
821 bool isFP = cir::isFPOrVectorOfFPType(a.getType());
822 auto mul = [&](mlir::Location l, mlir::Value x, mlir::Value y) {
825 auto add = [&](mlir::Location l, mlir::Value x, mlir::Value y) {
828 auto sub = [&](mlir::Location l, mlir::Value x, mlir::Value y) {
831 auto div = [&](mlir::Location l, mlir::Value x, mlir::Value y) {
835 mlir::Value ac = mul(loc, a, c);
836 mlir::Value bd = mul(loc, b, d);
837 mlir::Value cc = mul(loc, c, c);
838 mlir::Value dd = mul(loc, d, d);
839 mlir::Value acbd = add(loc, ac, bd);
840 mlir::Value ccdd = add(loc, cc, dd);
841 mlir::Value resultReal = div(loc, acbd, ccdd);
843 mlir::Value bc = mul(loc, b, c);
844 mlir::Value ad = mul(loc, a, d);
845 mlir::Value bcad = sub(loc, bc, ad);
846 mlir::Value resultImag = div(loc, bcad, ccdd);
852 mlir::Value lhsReal, mlir::Value lhsImag,
853 mlir::Value rhsReal, mlir::Value rhsImag) {
874 mlir::Value &a = lhsReal;
875 mlir::Value &b = lhsImag;
876 mlir::Value &c = rhsReal;
877 mlir::Value &d = rhsImag;
880 assert(cir::isFPOrVectorOfFPType(a.getType()) &&
881 "range-reduction complex divide expects floating-point operands");
883 auto trueBranchBuilder = [&](mlir::OpBuilder &, mlir::Location) {
884 mlir::Value r = builder.
createFDiv(loc, d, c);
885 mlir::Value rd = builder.
createFMul(loc, r, d);
886 mlir::Value tmp = builder.
createFAdd(loc, c, rd);
888 mlir::Value br = builder.
createFMul(loc, b, r);
889 mlir::Value abr = builder.
createFAdd(loc, a, br);
890 mlir::Value e = builder.
createFDiv(loc, abr, tmp);
892 mlir::Value ar = builder.
createFMul(loc, a, r);
893 mlir::Value bar = builder.
createFSub(loc, b, ar);
894 mlir::Value f = builder.
createFDiv(loc, bar, tmp);
900 auto falseBranchBuilder = [&](mlir::OpBuilder &, mlir::Location) {
901 mlir::Value r = builder.
createFDiv(loc, c, d);
902 mlir::Value rc = builder.
createFMul(loc, r, c);
903 mlir::Value tmp = builder.
createFAdd(loc, d, rc);
905 mlir::Value ar = builder.
createFMul(loc, a, r);
906 mlir::Value arb = builder.
createFAdd(loc, ar, b);
907 mlir::Value e = builder.
createFDiv(loc, arb, tmp);
909 mlir::Value br = builder.
createFMul(loc, b, r);
910 mlir::Value bra = builder.
createFSub(loc, br, a);
911 mlir::Value f = builder.
createFDiv(loc, bra, tmp);
917 auto cFabs = cir::FAbsOp::create(builder, loc, c);
918 auto dFabs = cir::FAbsOp::create(builder, loc, d);
919 cir::CmpOp cmpResult =
920 builder.
createCompare(loc, cir::CmpOpKind::ge, cFabs, dFabs);
921 auto ternary = cir::TernaryOp::create(builder, loc, cmpResult,
922 trueBranchBuilder, falseBranchBuilder);
924 return ternary.getResult();
930 mlir::Type elementType) {
932 auto getHigherPrecisionFPType = [&context,
933 &targetInfo](mlir::Type type) -> mlir::Type {
934 if (mlir::isa<cir::FP16Type>(type))
935 return cir::SingleType::get(&context);
937 if (mlir::isa<cir::SingleType>(type) || mlir::isa<cir::BF16Type>(type))
938 return cir::DoubleType::get(&context);
940 if (mlir::isa<cir::DoubleType>(type)) {
942 mlir::Type underlying;
943 if (&format == &llvm::APFloat::IEEEdouble())
944 underlying = cir::DoubleType::get(&context);
945 else if (&format == &llvm::APFloat::x87DoubleExtended())
946 underlying = cir::FP80Type::get(&context);
947 else if (&format == &llvm::APFloat::IEEEquad())
948 underlying = cir::FP128Type::get(&context);
950 llvm_unreachable(
"NYI: unsupported long double format");
951 return cir::LongDoubleType::get(&context, underlying);
957 auto getFloatTypeSemantics =
958 [&langOpts, &targetInfo](mlir::Type type) ->
const llvm::fltSemantics & {
960 if (mlir::isa<cir::FP16Type>(type))
961 return info.getHalfFormat();
963 if (mlir::isa<cir::BF16Type>(type))
964 return info.getBFloat16Format();
966 if (mlir::isa<cir::SingleType>(type))
967 return info.getFloatFormat();
969 if (mlir::isa<cir::DoubleType>(type))
970 return info.getDoubleFormat();
972 if (mlir::isa<cir::LongDoubleType>(type)) {
973 if (langOpts.OpenMP && langOpts.OpenMPIsTargetDevice)
974 llvm_unreachable(
"NYI Float type semantics with OpenMP");
975 return info.getLongDoubleFormat();
978 if (mlir::isa<cir::FP128Type>(type)) {
979 if (langOpts.OpenMP && langOpts.OpenMPIsTargetDevice)
980 llvm_unreachable(
"NYI Float type semantics with OpenMP");
981 return info.getFloat128Format();
984 llvm_unreachable(
"Unsupported float type semantics");
987 const mlir::Type higherElementType = getHigherPrecisionFPType(elementType);
988 const llvm::fltSemantics &elementTypeSemantics =
989 getFloatTypeSemantics(elementType);
990 const llvm::fltSemantics &higherElementTypeSemantics =
991 getFloatTypeSemantics(higherElementType);
1000 if (llvm::APFloat::semanticsMaxExponent(elementTypeSemantics) * 2 + 1 <=
1001 llvm::APFloat::semanticsMaxExponent(higherElementTypeSemantics)) {
1002 return higherElementType;
1012 mlir::Location loc, cir::ComplexFDivOp op,
1013 mlir::Value lhsReal, mlir::Value lhsImag,
1014 mlir::Value rhsReal, mlir::Value rhsImag,
1015 mlir::MLIRContext &mlirCx,
1017 cir::ComplexType complexTy = op.getType();
1018 cir::ComplexRangeKind range = op.getRange();
1020 case ComplexRangeKind::Full: {
1022 loc, complexTy, lhsReal, lhsImag, rhsReal,
1025 case ComplexRangeKind::Improved: {
1029 case ComplexRangeKind::Promoted: {
1030 mlir::Type originalElementType = complexTy.getElementType();
1031 mlir::Type higherPrecisionElementType =
1033 mlirCx, targetInfo, pass.getLangOpts(), builder,
1034 originalElementType);
1036 if (!higherPrecisionElementType)
1040 cir::CastKind floatingCastKind = cir::CastKind::floating;
1041 lhsReal = builder.
createCast(floatingCastKind, lhsReal,
1042 higherPrecisionElementType);
1043 lhsImag = builder.
createCast(floatingCastKind, lhsImag,
1044 higherPrecisionElementType);
1045 rhsReal = builder.
createCast(floatingCastKind, rhsReal,
1046 higherPrecisionElementType);
1047 rhsImag = builder.
createCast(floatingCastKind, rhsImag,
1048 higherPrecisionElementType);
1051 builder, loc, lhsReal, lhsImag, rhsReal, rhsImag);
1056 mlir::Value finalReal =
1057 builder.
createCast(floatingCastKind, resultReal, originalElementType);
1058 mlir::Value finalImag =
1059 builder.
createCast(floatingCastKind, resultImag, originalElementType);
1062 case ComplexRangeKind::Basic: {
1067 llvm_unreachable(
"fully covered switch");
1070void LoweringPreparePass::lowerComplexFDivOp(cir::ComplexFDivOp op) {
1071 cir::CIRBaseBuilderTy builder(getContext());
1072 builder.setInsertionPointAfter(op);
1073 mlir::Location loc = op.getLoc();
1074 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
1075 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
1081 mlir::Value loweredResult =
1083 rhsImag, getContext(), getTargetInfo());
1084 op.replaceAllUsesWith(loweredResult);
1088void LoweringPreparePass::lowerComplexDivOp(cir::ComplexDivOp op) {
1089 cir::CIRBaseBuilderTy builder(getContext());
1090 builder.setInsertionPointAfter(op);
1091 mlir::Location loc = op.getLoc();
1092 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
1093 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
1100 builder, loc, lhsReal, lhsImag, rhsReal, rhsImag);
1101 op.replaceAllUsesWith(loweredResult);
1105static llvm::StringRef
1107 switch (semantics) {
1108 case llvm::APFloat::S_IEEEhalf:
1110 case llvm::APFloat::S_IEEEsingle:
1112 case llvm::APFloat::S_IEEEdouble:
1114 case llvm::APFloat::S_PPCDoubleDouble:
1116 case llvm::APFloat::S_x87DoubleExtended:
1118 case llvm::APFloat::S_IEEEquad:
1121 llvm_unreachable(
"unsupported floating point type");
1127 mlir::Location loc, cir::ComplexFMulOp op,
1128 mlir::Value lhsReal, mlir::Value lhsImag,
1129 mlir::Value rhsReal, mlir::Value rhsImag) {
1131 mlir::Value resultRealLhs = builder.
createFMul(loc, lhsReal, rhsReal);
1132 mlir::Value resultRealRhs = builder.
createFMul(loc, lhsImag, rhsImag);
1133 mlir::Value resultImagLhs = builder.
createFMul(loc, lhsReal, rhsImag);
1134 mlir::Value resultImagRhs = builder.
createFMul(loc, lhsImag, rhsReal);
1135 mlir::Value resultReal =
1136 builder.
createFSub(loc, resultRealLhs, resultRealRhs);
1137 mlir::Value resultImag =
1138 builder.
createFAdd(loc, resultImagLhs, resultImagRhs);
1139 mlir::Value algebraicResult =
1142 cir::ComplexType complexTy = op.getType();
1143 cir::ComplexRangeKind rangeKind = op.getRange();
1144 if (rangeKind == cir::ComplexRangeKind::Basic ||
1145 rangeKind == cir::ComplexRangeKind::Improved ||
1146 rangeKind == cir::ComplexRangeKind::Promoted)
1147 return algebraicResult;
1154 mlir::Value resultRealIsNaN = builder.
createIsNaN(loc, resultReal);
1155 mlir::Value resultImagIsNaN = builder.
createIsNaN(loc, resultImag);
1156 mlir::Value resultRealAndImagAreNaN =
1159 return cir::TernaryOp::create(
1160 builder, loc, resultRealAndImagAreNaN,
1161 [&](mlir::OpBuilder &, mlir::Location) {
1164 lhsReal, lhsImag, rhsReal, rhsImag);
1167 [&](mlir::OpBuilder &, mlir::Location) {
1173void LoweringPreparePass::lowerComplexFMulOp(cir::ComplexFMulOp op) {
1174 cir::CIRBaseBuilderTy builder(getContext());
1175 builder.setInsertionPointAfter(op);
1176 mlir::Location loc = op.getLoc();
1177 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
1178 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
1185 mlir::Value loweredResult =
lowerComplexFMul(*
this, builder, loc, op, lhsReal,
1186 lhsImag, rhsReal, rhsImag);
1187 op.replaceAllUsesWith(loweredResult);
1191void LoweringPreparePass::lowerComplexMulOp(cir::ComplexMulOp op) {
1192 cir::CIRBaseBuilderTy builder(getContext());
1193 builder.setInsertionPointAfter(op);
1194 mlir::Location loc = op.getLoc();
1195 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
1196 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
1202 mlir::Value resultRealLhs = builder.
createMul(loc, lhsReal, rhsReal);
1203 mlir::Value resultRealRhs = builder.
createMul(loc, lhsImag, rhsImag);
1204 mlir::Value resultImagLhs = builder.
createMul(loc, lhsReal, rhsImag);
1205 mlir::Value resultImagRhs = builder.
createMul(loc, lhsImag, rhsReal);
1206 mlir::Value resultReal = builder.
createSub(loc, resultRealLhs, resultRealRhs);
1207 mlir::Value resultImag = builder.
createAdd(loc, resultImagLhs, resultImagRhs);
1209 mlir::Value loweredResult =
1212 op.replaceAllUsesWith(loweredResult);
1216void LoweringPreparePass::lowerComplexConjOp(cir::ComplexConjOp op) {
1217 mlir::Location loc = op.getLoc();
1218 CIRBaseBuilderTy builder(getContext());
1219 builder.setInsertionPointAfter(op);
1221 mlir::Value operand = op.getOperand();
1226 const bool isFP = cir::isFPOrVectorOfFPType(operandReal.getType());
1227 mlir::Value resultImag = isFP ? builder.
createFNeg(loc, operandImag)
1230 mlir::Value result =
1232 op->replaceAllUsesWith(mlir::ValueRange{result});
1237LoweringPreparePass::buildGlobalArrayDtorFunc(CIRBaseBuilderTy &builder,
1238 mlir::Operation *op) {
1239 mlir::OpBuilder::InsertionGuard guard(builder);
1240 builder.setInsertionPointAfter(op);
1241 SmallString<256> fnName(
"__cxx_global_array_dtor");
1242 uint32_t cnt = dynamicInitializerNames[fnName]++;
1244 fnName +=
"." + std::to_string(cnt);
1248 cir::FuncOp dtorFunc =
1249 buildRuntimeFunction(builder, fnName, op->getLoc(), fnType,
1250 cir::GlobalLinkageKind::InternalLinkage);
1252 SmallVector<mlir::NamedAttribute> paramAttrs;
1253 paramAttrs.push_back(
1254 builder.getNamedAttr(
"llvm.noundef", builder.getUnitAttr()));
1255 SmallVector<mlir::Attribute> argAttrDicts;
1256 argAttrDicts.push_back(
1257 mlir::DictionaryAttr::get(builder.getContext(), paramAttrs));
1258 dtorFunc.setArgAttrsAttr(
1259 mlir::ArrayAttr::get(builder.getContext(), argAttrDicts));
1261 dtorFunc.addEntryBlock();
1265void LoweringPreparePass::lowerRegisterExitDtorOp(cir::RegisterExitDtorOp op) {
1266 CIRBaseBuilderTy builder(getContext());
1267 mlir::Location loc = op.getLoc();
1268 auto object = symbolTables.lookupNearestSymbolFrom<cir::GlobalOp>(
1269 op, op.getObjectAttr());
1270 assert(
object &&
"register_exit_dtor must reference a cir.global");
1271 mlir::Block &body = op.getBody().front();
1272 builder.setInsertionPoint(op);
1276 cir::FuncOp dtorFunc;
1278 if (body.getOperations().size() == 3) {
1279 auto getGlobal = mlir::dyn_cast<cir::GetGlobalOp>(body.front());
1280 auto call = mlir::dyn_cast<cir::CallOp>(*std::next(body.begin()));
1281 if (getGlobal && call && getGlobal.getName() == op.getObject() &&
1282 call.getNumArgOperands() == 1 &&
1283 call.getArgOperand(0) == getGlobal.getResult()) {
1284 dtorFunc = getCalledFunction(call);
1286 arg = builder.clone(*getGlobal)->getResult(0);
1293 dtorFunc = buildGlobalArrayDtorFunc(builder,
object);
1294 mlir::Block *entryBB = &dtorFunc.getBody().front();
1295 entryBB->getOperations().splice(entryBB->end(), body.getOperations());
1296 auto yieldOp = mlir::cast<cir::YieldOp>(entryBB->getTerminator());
1298 mlir::OpBuilder::InsertionGuard guard(builder);
1299 builder.setInsertionPoint(yieldOp);
1300 cir::ReturnOp::create(builder, yieldOp.getLoc());
1306 cir::CallOp atExitCall = emitAtExitCall(builder, loc, dtorFunc, arg,
1307 object.getTlsModel().has_value());
1310 atExitCall.setNothrowAttr(builder.getUnitAttr());
1314cir::FuncOp LoweringPreparePass::getOrCreateDtorFunc(CIRBaseBuilderTy &builder,
1316 mlir::Region &dtorRegion,
1317 cir::CallOp &dtorCall) {
1318 mlir::OpBuilder::InsertionGuard guard(builder);
1322 mlir::Block &dtorBlock = dtorRegion.front();
1326 auto opIt = dtorBlock.getOperations().begin();
1327 cir::GetGlobalOp ggop = mlir::cast<cir::GetGlobalOp>(*opIt);
1338 if (dtorBlock.getOperations().size() == 3) {
1339 auto callOp = mlir::dyn_cast<cir::CallOp>(&*(++opIt));
1340 auto yieldOp = mlir::dyn_cast<cir::YieldOp>(&*(++opIt));
1341 if (yieldOp && callOp && callOp.getNumOperands() == 1 &&
1342 callOp.getArgOperand(0) == ggop) {
1344 return getCalledFunction(callOp);
1349 cir::FuncOp dtorFunc = buildGlobalArrayDtorFunc(builder, op);
1350 mlir::Block *entryBB = &dtorFunc.getBody().front();
1353 entryBB->getOperations().splice(entryBB->begin(), dtorBlock.getOperations(),
1354 dtorBlock.begin(), dtorBlock.end());
1357 cir::GetGlobalOp dtorGGop =
1358 mlir::cast<cir::GetGlobalOp>(entryBB->getOperations().front());
1359 builder.setInsertionPointToStart(&dtorBlock);
1360 builder.clone(*dtorGGop.getOperation());
1364 mlir::Value dtorArg = entryBB->getArgument(0);
1367 if (dtorArg.getType() != dtorGGop.getType()) {
1368 builder.setInsertionPointToStart(entryBB);
1370 builder.
createBitcast(dtorGGop.getLoc(), dtorArg, dtorGGop.getType());
1372 dtorGGop.replaceAllUsesWith(dtorArg);
1376 mlir::Block &finalBlock = dtorFunc.getBody().back();
1377 auto yieldOp = cast<cir::YieldOp>(finalBlock.getTerminator());
1378 builder.setInsertionPoint(yieldOp);
1379 cir::ReturnOp::create(builder, yieldOp->getLoc());
1384 cir::GetGlobalOp origGGop =
1385 mlir::cast<cir::GetGlobalOp>(dtorBlock.getOperations().front());
1386 builder.setInsertionPointAfter(origGGop);
1387 mlir::Value ggopResult = origGGop.getResult();
1388 dtorCall = builder.
createCallOp(op.getLoc(), dtorFunc, ggopResult,
1390 {}, dtorFunc.getCallingConv());
1393 auto finalYield = cir::YieldOp::create(builder, op.getLoc());
1396 dtorBlock.getOperations().erase(std::next(mlir::Block::iterator(finalYield)),
1398 dtorRegion.getBlocks().erase(std::next(dtorRegion.begin()), dtorRegion.end());
1404LoweringPreparePass::buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op) {
1407 SmallString<256> fnName(
"__cxx_global_var_init");
1409 uint32_t cnt = dynamicInitializerNames[fnName]++;
1411 fnName +=
"." + std::to_string(cnt);
1414 CIRBaseBuilderTy builder(getContext());
1415 builder.setInsertionPointAfter(op);
1416 cir::VoidType voidTy = builder.
getVoidTy();
1417 auto fnType = cir::FuncType::get({}, voidTy);
1418 FuncOp f = buildRuntimeFunction(builder, fnName, op.getLoc(), fnType,
1419 cir::GlobalLinkageKind::InternalLinkage);
1424 if (op.getStrictfp()) {
1425 f->setAttr(cir::CIRDialect::getStrictFPAttrName(),
1426 mlir::UnitAttr::get(&getContext()));
1427 op.setStrictfp(
false);
1436 mlir::Block *entryBB = f.addEntryBlock();
1437 builder.setInsertionPointToStart(entryBB);
1441 bool needsTlsGuard = op.getTlsRefs() && op.getTlsRefs()->getGuardName();
1445 if (!needsTlsGuard && op.getDynamicInitGuard()) {
1446 if (!op.getDynamicInitInfo()) {
1448 "guarded global with a guard is missing 'dynamic_init_info'");
1452 if (op.getDynamicInitInfo()->getLocal()) {
1453 op->emitError(
"guarded global is marked local");
1456 emitGuardedInit(builder, op, op.getCtorRegion(), op.getDtorRegion());
1457 builder.setInsertionPointToEnd(entryBB);
1458 cir::ReturnOp::create(builder, op.getLoc());
1463 if (needsTlsGuard) {
1464 guardIf = buildInitGuardCheck(
1465 builder, op.getLoc(),
1466 getOrCreateStaticLocalDeclGuardAddress(
1467 builder, op, op.getTlsRefs()->getGuardName().getValue(),
1469 op.hasInternalLinkage()),
1471 builder.setInsertionPointToEnd(&guardIf.getThenRegion().front());
1474 if (!op.getCtorRegion().empty()) {
1475 mlir::Block &block = op.getCtorRegion().front();
1476 mlir::Block *insertBlock = builder.getBlock();
1477 insertBlock->getOperations().splice(insertBlock->end(),
1478 block.getOperations(), block.begin(),
1479 std::prev(block.end()));
1483 mlir::Region &dtorRegion = op.getDtorRegion();
1484 if (!dtorRegion.empty()) {
1487 emitGlobalGuardedDtorRegion(builder, op, dtorRegion,
1488 op.getTlsModel().has_value(),
1489 *builder.getBlock());
1493 if (needsTlsGuard) {
1494 builder.setInsertionPointToEnd(&guardIf.getThenRegion().back());
1495 cir::YieldOp::create(builder, op.getLoc());
1499 builder.setInsertionPointToEnd(entryBB);
1500 mlir::Operation *yieldOp =
nullptr;
1501 if (!op.getCtorRegion().empty()) {
1502 mlir::Block &block = op.getCtorRegion().front();
1503 yieldOp = &block.getOperations().back();
1505 assert(!dtorRegion.empty());
1506 mlir::Block &block = dtorRegion.front();
1507 yieldOp = &block.getOperations().back();
1510 assert(isa<cir::YieldOp>(*yieldOp));
1511 cir::ReturnOp::create(builder, yieldOp->getLoc());
1516LoweringPreparePass::getGuardAcquireFn(cir::PointerType guardPtrTy) {
1518 CIRBaseBuilderTy builder(getContext());
1519 mlir::OpBuilder::InsertionGuard ipGuard{builder};
1520 builder.setInsertionPointToStart(mlirModule.getBody());
1521 mlir::Location loc = mlirModule.getLoc();
1522 cir::IntType intTy = cir::IntType::get(&getContext(), 32,
true);
1523 auto fnType = cir::FuncType::get({guardPtrTy}, intTy);
1524 return buildRuntimeFunction(builder,
"__cxa_guard_acquire", loc, fnType);
1528LoweringPreparePass::getGuardReleaseFn(cir::PointerType guardPtrTy) {
1530 CIRBaseBuilderTy builder(getContext());
1531 mlir::OpBuilder::InsertionGuard ipGuard{builder};
1532 builder.setInsertionPointToStart(mlirModule.getBody());
1533 mlir::Location loc = mlirModule.getLoc();
1534 cir::VoidType voidTy = cir::VoidType::get(&getContext());
1535 auto fnType = cir::FuncType::get({guardPtrTy}, voidTy);
1536 return buildRuntimeFunction(builder,
"__cxa_guard_release", loc, fnType);
1539cir::FuncOp LoweringPreparePass::getGuardAbortFn(cir::PointerType guardPtrTy) {
1541 CIRBaseBuilderTy builder(getContext());
1542 mlir::OpBuilder::InsertionGuard ipGuard{builder};
1543 builder.setInsertionPointToStart(mlirModule.getBody());
1544 mlir::Location loc = mlirModule.getLoc();
1545 cir::VoidType voidTy = cir::VoidType::get(&getContext());
1546 auto fnType = cir::FuncType::get({guardPtrTy}, voidTy);
1547 return buildRuntimeFunction(builder,
"__cxa_guard_abort", loc, fnType);
1550cir::FuncOp LoweringPreparePass::getTlsInitFn() {
1552 CIRBaseBuilderTy builder(getContext());
1553 mlir::OpBuilder::InsertionGuard _{builder};
1554 builder.setInsertionPointToStart(mlirModule.getBody());
1555 mlir::Location loc = mlirModule.getLoc();
1557 return buildRuntimeFunction(builder,
"__tls_init", loc, fnType,
1558 cir::GlobalLinkageKind::InternalLinkage);
1561cir::GlobalOp LoweringPreparePass::createGuardGlobalOp(
1562 CIRBaseBuilderTy &builder, mlir::Location loc, llvm::StringRef name,
1563 cir::IntType guardTy, cir::GlobalLinkageKind linkage) {
1564 mlir::OpBuilder::InsertionGuard guard(builder);
1565 builder.setInsertionPointToStart(mlirModule.getBody());
1566 cir::GlobalOp g = cir::GlobalOp::create(builder, loc, name, guardTy);
1568 cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
1569 mlir::SymbolTable::setSymbolVisibility(
1570 g, mlir::SymbolTable::Visibility::Private);
1574void LoweringPreparePass::addUsedGlobal(cir::GlobalOp global) {
1575 CIRBaseBuilderTy builder(getContext());
1576 mlir::ptr::MemorySpaceAttrInterface eltAS;
1577 if (
unsigned targetAS =
1579 eltAS = cir::TargetAddressSpaceAttr::get(&getContext(), targetAS);
1580 cir::PointerType voidPtrTy = builder.
getVoidPtrTy(eltAS);
1581 mlir::Attribute entry = cir::GlobalViewAttr::get(
1582 voidPtrTy, mlir::FlatSymbolRefAttr::get(global.getSymNameAttr()));
1584 mlir::StringAttr usedName = builder.getStringAttr(
"llvm.used");
1585 cir::GlobalOp used =
1586 symbolTables.lookupSymbolIn<cir::GlobalOp>(mlirModule, usedName);
1588 llvm::SmallVector<mlir::Attribute, 4> elements;
1590 auto existing = mlir::cast<cir::ConstArrayAttr>(*used.getInitialValue());
1591 llvm::append_range(elements,
1592 mlir::cast<mlir::ArrayAttr>(existing.getElts()));
1594 elements.push_back(entry);
1596 cir::ArrayType arrayTy = cir::ArrayType::get(voidPtrTy, elements.size());
1597 cir::ConstArrayAttr initAttr = cir::ConstArrayAttr::get(
1598 arrayTy, mlir::ArrayAttr::get(&getContext(), elements));
1601 used.setSymType(arrayTy);
1602 used.setInitialValueAttr(initAttr);
1606 builder.setInsertionPointToStart(mlirModule.getBody());
1607 used = cir::GlobalOp::create(
1608 builder, mlirModule.getLoc(), usedName.getValue(), arrayTy,
1610 cir::CIRDataLayout(mlirModule).getDefaultGlobalsAddrSpace(&getContext()));
1611 used.setLinkage(cir::GlobalLinkageKind::AppendingLinkage);
1612 used.setInitialValueAttr(initAttr);
1613 used.setSectionAttr(builder.getStringAttr(
"llvm.metadata"));
1614 symbolTables.getSymbolTable(mlirModule).insert(used);
1617void LoweringPreparePass::handleStaticLocal(cir::GlobalOp globalOp,
1618 cir::LocalInitOp localInitOp) {
1619 CIRBaseBuilderTy builder(getContext());
1621 builder.setInsertionPointAfter(localInitOp);
1622 mlir::Block *localInitBlock = builder.getInsertionBlock();
1625 mlir::Operation *ret = localInitBlock->getTerminator();
1629 builder.setInsertionPointAfter(localInitOp);
1631 emitGuardedInit(builder, globalOp, localInitOp.getCtorRegion(),
1632 localInitOp.getDtorRegion());
1635 builder.getInsertionBlock()->push_back(ret);
1638void LoweringPreparePass::emitGuardedInit(CIRBaseBuilderTy &builder,
1639 cir::GlobalOp globalOp,
1640 mlir::Region &ctorRegion,
1641 mlir::Region &dtorRegion) {
1645 std::optional<cir::DynamicInitInfoAttr> infoOption =
1646 globalOp.getDynamicInitInfo();
1651 if (!infoOption.has_value()) {
1652 globalOp->emitError(
1653 "dynamic-init-guarded global is missing 'dynamic_init_info'");
1657 cir::DynamicInitInfoAttr
info = infoOption.value();
1661 bool nonTemplateInline =
1662 info.getIsInline() && !
info.isTemplateInstantiation();
1667 bool threadsafe = getLangOpts().ThreadsafeStatics &&
1668 (
info.getLocal() || nonTemplateInline) &&
1669 info.getTls() == cir::TLSKind::None;
1673 bool useInt8GuardVariable = !threadsafe && globalOp.hasInternalLinkage();
1676 cir::GlobalOp guard = getOrCreateStaticLocalDeclGuardAddress(
1677 builder, globalOp, globalOp.getDynamicInitGuard()->getName().getValue(),
1678 info.getLocal(), useInt8GuardVariable);
1683 mlir::Value guardPtr =
1706 unsigned maxInlineWidthInBits = getTargetInfo().getMaxAtomicInlineWidth();
1708 if (!threadsafe || maxInlineWidthInBits) {
1710 auto bytePtrTy = cir::PointerType::get(builder.
getSIntNTy(8));
1711 mlir::Value bytePtr = builder.
createBitcast(guardPtr, bytePtrTy);
1713 globalOp.getLoc(), bytePtr, *guard.getAlignment());
1722 auto loadOp = mlir::cast<cir::LoadOp>(guardLoad.getDefiningOp());
1723 loadOp.setMemOrder(cir::MemOrder::Acquire);
1724 loadOp.setSyncScope(cir::SyncScopeKind::System);
1747 if (useARMGuardVarABI() && !useInt8GuardVariable) {
1749 globalOp.getLoc(), mlir::cast<cir::IntType>(guardLoad.getType()), 1);
1750 guardLoad = builder.
createAnd(globalOp.getLoc(), guardLoad, one);
1755 globalOp.getLoc(), mlir::cast<cir::IntType>(guardLoad.getType()), 0);
1757 cir::CmpOpKind::eq, guardLoad, zero);
1761 builder, globalOp.getLoc(), needsInit,
1762 false, [&](mlir::OpBuilder &, mlir::Location) {
1763 emitCXXGuardedInitIf(
1764 builder, globalOp, ctorRegion, dtorRegion, info.getLocal(),
1765 guardPtr, builder.getPointerTo(guard.getSymType()), threadsafe);
1770 globalOp->emitError(
"NYI: guarded init without inline atomics support");
1775void LoweringPreparePass::lowerLocalInitOp(cir::LocalInitOp initOp) {
1778 if (initOp.getCtorRegion().empty() && initOp.getDtorRegion().empty()) {
1783 cir::GlobalOp globalOp = initOp.getReferencedGlobal(symbolTables);
1784 assert(globalOp &&
"No global-op found");
1786 handleStaticLocal(globalOp, initOp);
1796 return targetInfo.
getTriple().isOSDarwin();
1799static cir::GlobalLinkageKind
1802 return op.getLinkage();
1807 return op.getLinkage();
1811 if (op.isDeclaration())
1812 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
1813 return cir::GlobalLinkageKind::WeakODRLinkage;
1817LoweringPreparePass::getOrCreateThreadLocalWrapper(CIRBaseBuilderTy &builder,
1819 mlir::OpBuilder::InsertionGuard insertGuard(builder);
1820 builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
1822 mlir::StringAttr wrapperName = op.getTlsRefs()->getWrapperName();
1824 auto existingWrapperIter = threadLocalWrappers.find(wrapperName.getValue());
1825 if (existingWrapperIter != threadLocalWrappers.end())
1826 return existingWrapperIter->second;
1829 auto funcType = cir::FuncType::get({}, builder.
getPointerTo(op.getSymType()));
1831 cir::FuncOp::create(builder, op.getLoc(), wrapperName, funcType);
1833 cir::GlobalLinkageKind linkageKind =
1835 func.setLinkageAttr(
1836 cir::GlobalLinkageKindAttr::get(&getContext(), linkageKind));
1838 if (getTargetInfo().
getTriple().supportsCOMDAT() && func.isWeakForLinker())
1839 func.setSelfComdat();
1841 mlir::SymbolTable::setSymbolVisibility(
1842 func, mlir::SymbolTable::Visibility::Private);
1847 op.getGlobalVisibility() == cir::VisibilityKind::Hidden)
1848 func.setGlobalVisibility(cir::VisibilityKind::Hidden);
1851 op->emitError(
"Unhandled thread wrapper attributes for CC and Nounwind");
1853 threadLocalWrappers.insert({wrapperName.getValue(), func});
1857void LoweringPreparePass::defineGlobalThreadLocalWrapper(cir::GlobalOp op,
1858 cir::FuncOp initAlias,
1859 bool isVarDefinition) {
1860 CIRBaseBuilderTy builder(getContext());
1861 cir::FuncOp wrapper = getOrCreateThreadLocalWrapper(builder, op);
1862 mlir::Block *entryBB = wrapper.addEntryBlock();
1863 builder.setInsertionPointToStart(entryBB);
1867 mlir::Location aliasLoc = initAlias.getLoc();
1868 if (!isVarDefinition) {
1870 mlir::Value funcLoad = cir::GetGlobalOp::create(
1871 builder, aliasLoc, cir::PointerType::get(initAlias.getFunctionType()),
1872 initAlias.getSymName());
1873 mlir::Value nullCheck =
1875 mlir::Value cmp = cir::CmpOp::create(
1876 builder, aliasLoc, cir::CmpOpKind::ne, funcLoad, nullCheck);
1877 cir::IfOp::create(builder, aliasLoc, cmp,
false,
1878 [&](mlir::OpBuilder &, mlir::Location loc) {
1882 initAlias.getCallingConv());
1883 cir::YieldOp::create(builder, aliasLoc);
1890 initAlias.getCallingConv());
1894 cir::ReturnOp::create(builder, op.getLoc(), {get});
1898LoweringPreparePass::defineGlobalThreadLocalInitAlias(cir::GlobalOp op,
1899 cir::FuncOp aliasee) {
1900 CIRBaseBuilderTy builder(getContext());
1901 mlir::OpBuilder::InsertionGuard insertGuard(builder);
1902 builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
1903 mlir::StringAttr aliasName = op.getTlsRefs()->getInitName();
1904 auto existingAliasIter = threadLocalInitAliases.find(aliasName.getValue());
1906 if (existingAliasIter != threadLocalInitAliases.end())
1907 return existingAliasIter->second;
1911 cir::FuncOp::create(builder, op.getLoc(), aliasName, funcType);
1912 alias.setLinkage(op.getLinkage());
1915 alias.setAliasee(aliasee.getSymName());
1920 alias.setLinkage(cir::GlobalLinkageKind::ExternalWeakLinkage);
1921 mlir::SymbolTable::setSymbolVisibility(
1922 alias, mlir::SymbolTable::Visibility::Private);
1925 threadLocalInitAliases.insert({aliasName.getValue(), alias});
1929void LoweringPreparePass::lowerGlobalOp(GlobalOp op) {
1931 if (op.getDynamicInitGuard() &&
1932 (!op.getDynamicInitInfo() || op.getDynamicInitInfo()->getLocal()))
1935 mlir::Region &ctorRegion = op.getCtorRegion();
1936 mlir::Region &dtorRegion = op.getDtorRegion();
1937 cir::FuncOp initAlias;
1939 if (!ctorRegion.empty() || !dtorRegion.empty()) {
1942 cir::FuncOp f = buildCXXGlobalVarDeclInitFunc(op);
1945 ctorRegion.getBlocks().clear();
1946 dtorRegion.getBlocks().clear();
1949 if (op.getTlsModel()) {
1961 if (op.getTlsRefs()->getGuardName()) {
1963 initAlias = defineGlobalThreadLocalInitAlias(op, f);
1966 initAlias = defineGlobalThreadLocalInitAlias(op, getTlsInitFn());
1970 globalThreadLocalInitializers.push_back(f);
1972 }
else if (std::optional<uint32_t> priority = op.getInitPriority()) {
1973 prioritizedDynamicInitializers[*priority].push_back(f);
1974 }
else if (op.getDynamicInitInfo() &&
1975 (op.getDynamicInitInfo()->getIsInline() ||
1976 op.getDynamicInitInfo()->isTemplateInstantiation()) &&
1977 getTargetInfo().
getTriple().supportsCOMDAT() &&
1978 !op.hasInternalLinkage()) {
1989 globalCtorList.emplace_back(f.getSymName(),
1990 cir::GlobalCtorAttr::getDefaultPriority(),
1996 if (getTargetInfo().
getTriple().isOSBinFormatELF() ||
1997 getTargetInfo().getCXXABI().isMicrosoft())
2002 std::optional<llvm::StringRef> comdat = op.getComdat();
2003 if (comdat && (getTargetInfo().
getTriple().isOSBinFormatELF() ||
2004 getTargetInfo().
getTriple().isOSBinFormatWasm()))
2005 f.setComdat(comdat->empty() ? op.getSymName() : *comdat);
2007 dynamicInitializers.push_back(f);
2009 }
else if (op.getTlsModel() && op.getTlsRefs() && op.isDeclaration()) {
2012 initAlias = defineGlobalThreadLocalInitAlias(op, {});
2018 if (op.getTlsModel() && op.getTlsRefs())
2019 defineGlobalThreadLocalWrapper(op, initAlias, !op.isDeclaration());
2024void LoweringPreparePass::lowerGetGlobalOp(GetGlobalOp op) {
2027 auto globalOp = mlir::cast<cir::GlobalOp>(
2028 symbolTables.lookupNearestSymbolFrom(op, op.getNameAttr()));
2034 if (!globalOp.getTlsModel() || !globalOp.getTlsRefs())
2052 mlir::Operation *parentOp = op->getParentOp();
2053 if (parentOp == globalOp) {
2054 mlir::Region *ctorRegion = &globalOp.getCtorRegion();
2055 mlir::Region *dtorRegion = &globalOp.getDtorRegion();
2057 if (!ctorRegion->empty() && &*ctorRegion->op_begin() == op.getOperation())
2059 if (!dtorRegion->empty() && &*dtorRegion->op_begin() == op.getOperation())
2063 CIRBaseBuilderTy builder(getContext());
2064 cir::FuncOp wrapperFunc = getOrCreateThreadLocalWrapper(builder, globalOp);
2066 builder.setInsertionPoint(op);
2068 wrapperFunc.getLoc(),
2069 mlir::FlatSymbolRefAttr::get(wrapperFunc.getSymNameAttr()),
2070 wrapperFunc.getFunctionType().getReturnType(), {}, {},
2071 {}, {}, wrapperFunc.getCallingConv());
2072 op->replaceAllUsesWith(call);
2076void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
2077 CIRBaseBuilderTy builder(getContext());
2078 builder.setInsertionPointAfter(op);
2080 mlir::Location loc = op->getLoc();
2081 cir::CmpThreeWayInfoAttr cmpInfo = op.getInfo();
2090 mlir::Value transformedResult;
2091 if (cmpInfo.getOrdering() != CmpOrdering::Partial) {
2094 builder.
createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
2095 mlir::Value selectOnLt = builder.
createSelect(loc, lt, ltRes, gtRes);
2097 builder.
createCompare(loc, CmpOpKind::eq, op.getLhs(), op.getRhs());
2098 transformedResult = builder.
createSelect(loc, eq, eqRes, selectOnLt);
2102 loc, op.getType(), cmpInfo.getUnordered().value());
2105 builder.
createCompare(loc, CmpOpKind::eq, op.getLhs(), op.getRhs());
2106 mlir::Value selectOnEq = builder.
createSelect(loc, eq, eqRes, unorderedRes);
2108 builder.
createCompare(loc, CmpOpKind::gt, op.getLhs(), op.getRhs());
2109 mlir::Value selectOnGt = builder.
createSelect(loc, gt, gtRes, selectOnEq);
2111 builder.
createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
2112 transformedResult = builder.
createSelect(loc, lt, ltRes, selectOnGt);
2115 op.replaceAllUsesWith(transformedResult);
2119template <
typename AttributeTy>
2120static llvm::SmallVector<mlir::Attribute>
2124 for (
const auto &entry : list) {
2125 mlir::FlatSymbolRefAttr associated;
2126 if (!entry.associated.empty())
2127 associated = mlir::FlatSymbolRefAttr::get(context, entry.associated);
2129 AttributeTy::get(context, entry.name, entry.priority, associated));
2134void LoweringPreparePass::buildGlobalCtorDtorList() {
2135 if (!globalCtorList.empty()) {
2136 llvm::SmallVector<mlir::Attribute> globalCtors =
2140 mlirModule->setAttr(cir::CIRDialect::getGlobalCtorsAttrName(),
2141 mlir::ArrayAttr::get(&getContext(), globalCtors));
2144 if (!globalDtorList.empty()) {
2145 llvm::SmallVector<mlir::Attribute> globalDtors =
2148 mlirModule->setAttr(cir::CIRDialect::getGlobalDtorsAttrName(),
2149 mlir::ArrayAttr::get(&getContext(), globalDtors));
2154LoweringPreparePass::createGlobalThreadLocalGuard(CIRBaseBuilderTy &builder,
2155 mlir::Location loc) {
2156 mlir::OpBuilder::InsertionGuard guard(builder);
2157 builder.setInsertionPointToStart(mlirModule.getBody());
2160 cir::IntType guardTy = builder.
getSIntNTy(8);
2161 auto g = cir::GlobalOp::create(builder, loc,
"__tls_guard", guardTy);
2162 g.setLinkageAttr(cir::GlobalLinkageKindAttr::get(
2163 builder.getContext(), cir::GlobalLinkageKind::InternalLinkage));
2166 if (
auto defTlsModel = mlirModule->getAttrOfType<TLSModelAttr>(
2167 cir::CIRDialect::getDefaultTlsModelAttrName())) {
2168 g.setTlsModel(defTlsModel.getValue());
2171 g.setTlsModel(TLSModel::GeneralDynamic);
2174 g.setInitialValueAttr(cir::IntAttr::get(guardTy, 0));
2178cir::IfOp LoweringPreparePass::buildInitGuardCheck(CIRBaseBuilderTy &builder,
2180 cir::GlobalOp guard,
2182 cir::GetGlobalOp getGuard = builder.
createGetGlobal(guard, threadLocal);
2183 mlir::Value getGuardValue = getGuard;
2188 if (guard.getSymType() != builder.
getSIntNTy(8))
2190 getGuard, cir::PointerType::get(builder.
getSIntNTy(8)));
2192 mlir::Value guardLoad =
2196 builder.
createCompare(loc, cir::CmpOpKind::eq, guardLoad, zero);
2197 return cir::IfOp::create(
2199 false, [&](mlir::OpBuilder &, mlir::Location loc) {
2203 loc, builder.
getConstantInt(loc, guard.getSymType(), 1), getGuard);
2207void LoweringPreparePass::buildCXXGlobalTlsFunc() {
2208 if (globalThreadLocalInitializers.empty())
2214 cir::FuncOp tlsInit = getTlsInitFn();
2215 mlir::Location loc = tlsInit.getLoc();
2216 CIRBaseBuilderTy builder(getContext());
2217 mlir::Block *entryBB = tlsInit.addEntryBlock();
2218 builder.setInsertionPointToStart(entryBB);
2220 cir::IfOp ifOperation = buildInitGuardCheck(
2221 builder, loc, createGlobalThreadLocalGuard(builder, loc),
2225 builder.setInsertionPointToEnd(&ifOperation.getThenRegion().front());
2226 for (cir::FuncOp initFunc : globalThreadLocalInitializers)
2228 {}, initFunc.getCallingConv());
2229 cir::YieldOp::create(builder, loc);
2231 builder.setInsertionPointAfter(ifOperation);
2232 cir::ReturnOp::create(builder, loc);
2239 assert(priority <= 65535 &&
"Priority should always be <= 65535.");
2240 std::string prioritySuffix = llvm::utostr(priority);
2241 assert(prioritySuffix.size() < 6);
2242 prioritySuffix = std::string(6 - prioritySuffix.size(),
'0') + prioritySuffix;
2243 return prioritySuffix;
2246cir::FuncOp LoweringPreparePass::buildGlobalInitCallerFunc(
2247 llvm::StringRef fnName, cir::GlobalLinkageKind linkage,
2248 llvm::ArrayRef<cir::FuncOp> initializers,
uint32_t priority,
2249 cir::GlobalOp guard) {
2250 CIRBaseBuilderTy builder(getContext());
2251 builder.setInsertionPointToEnd(&mlirModule.getBodyRegion().back());
2252 auto fnType = cir::FuncType::get({}, builder.
getVoidTy());
2253 cir::FuncOp fn = buildRuntimeFunction(builder, fnName, mlirModule.getLoc(),
2255 builder.setInsertionPointToStart(fn.addEntryBlock());
2256 mlir::Location loc = fn.getLoc();
2257 auto emitCalls = [&] {
2258 for (cir::FuncOp init : initializers)
2261 init.getCallingConv());
2265 buildInitGuardCheck(builder, loc, guard,
false);
2266 builder.setInsertionPointToEnd(&guardIf.getThenRegion().front());
2268 cir::YieldOp::create(builder, loc);
2269 builder.setInsertionPointAfter(guardIf);
2273 cir::ReturnOp::create(builder, loc);
2274 globalCtorList.emplace_back(fnName, priority);
2278void LoweringPreparePass::buildCXXGlobalPriorityInitFuncs(
2279 llvm::SmallVectorImpl<cir::FuncOp> &importedInits) {
2283 for (
const auto &[priority, initializers] : prioritizedDynamicInitializers) {
2284 SmallString<256> fnName;
2285 fnName +=
"_GLOBAL__I_";
2288 llvm::SmallVector<cir::FuncOp> calls(importedInits.begin(),
2289 importedInits.end());
2290 calls.append(initializers.begin(), initializers.end());
2291 importedInits.clear();
2292 buildGlobalInitCallerFunc(fnName, cir::GlobalLinkageKind::InternalLinkage,
2297void LoweringPreparePass::buildCXXGlobalInitFunc() {
2298 CIRBaseBuilderTy builder(getContext());
2299 builder.setInsertionPointToEnd(&mlirModule.getBodyRegion().back());
2300 mlir::Location loc = mlirModule.getLoc();
2305 llvm::SmallVector<cir::FuncOp> importedInits;
2306 if (
auto inits = mlirModule->getAttrOfType<mlir::ArrayAttr>(
2307 cir::CIRDialect::getCXXModuleImportedInitsAttrName()))
2308 for (
auto init :
inits.getAsRange<cir::CXXModuleInitAttr>())
2309 importedInits.push_back(
2310 buildRuntimeFunction(builder, init.getName().getValue(),
2319 if (
auto moduleInitFnName = mlirModule->getAttrOfType<mlir::StringAttr>(
2320 cir::CIRDialect::getCXXModuleInitFnNameAttrName())) {
2328 llvm::SmallVector<cir::FuncOp> initializers(importedInits.begin(),
2329 importedInits.end());
2330 for (
const auto &[priority, inits] : prioritizedDynamicInitializers)
2331 initializers.append(
inits.begin(),
inits.end());
2332 initializers.append(dynamicInitializers.begin(), dynamicInitializers.end());
2334 llvm::StringRef fnName = moduleInitFnName.getValue();
2335 cir::GlobalOp guard;
2336 if (!initializers.empty()) {
2337 cir::IntType guardTy = builder.
getSIntNTy(8);
2339 createGuardGlobalOp(builder, loc, (fnName +
"__in_chrg").str(),
2340 guardTy, cir::GlobalLinkageKind::InternalLinkage);
2342 guard.setInitialValueAttr(cir::IntAttr::get(guardTy, 0));
2344 buildGlobalInitCallerFunc(fnName, cir::GlobalLinkageKind::ExternalLinkage,
2346 cir::GlobalCtorAttr::getDefaultPriority(), guard);
2354 buildCXXGlobalPriorityInitFuncs(importedInits);
2355 if (importedInits.empty() && dynamicInitializers.empty())
2358 llvm::SmallVector<cir::FuncOp> initializers(importedInits.begin(),
2359 importedInits.end());
2360 initializers.append(dynamicInitializers.begin(), dynamicInitializers.end());
2366 SmallString<256> fnName;
2367 fnName +=
"_GLOBAL__sub_I_";
2369 buildGlobalInitCallerFunc(fnName, cir::GlobalLinkageKind::InternalLinkage,
2371 cir::GlobalCtorAttr::getDefaultPriority());
2380 mlir::Operation *op, mlir::Type eltTy,
2382 mlir::Value numElements,
2383 uint64_t arrayLen,
bool isCtor) {
2384 mlir::Location loc = op->getLoc();
2385 bool isDynamic = numElements !=
nullptr;
2389 const unsigned sizeTypeSize =
2395 mlir::Value begin, end;
2398 end = cir::PtrStrideOp::create(builder, loc, eltTy, begin, numElements);
2400 mlir::Value endOffsetVal =
2402 begin = cir::CastOp::create(builder, loc, eltTy,
2403 cir::CastKind::array_to_ptrdecay, addr);
2404 end = cir::PtrStrideOp::create(builder, loc, eltTy, begin, endOffsetVal);
2407 mlir::Value start = isCtor ? begin : end;
2408 mlir::Value stop = isCtor ? end : begin;
2414 mlir::Value guardCond;
2417 guardCond = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne,
2423 cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, start, stop);
2425 ifOp = cir::IfOp::create(builder, loc, guardCond,
2427 [&](mlir::OpBuilder &, mlir::Location) {});
2428 builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
2435 loc, tmpAddrTy,
"__array_idx",
2439 mlir::Block *bodyBlock = &op->getRegion(0).front();
2444 auto cloneRegionBodyInto = [&](mlir::Block *srcBlock,
2445 mlir::Value replacement) {
2446 mlir::IRMapping map;
2447 map.map(srcBlock->getArgument(0), replacement);
2448 for (mlir::Operation ®ionOp : *srcBlock) {
2449 if (!mlir::isa<cir::YieldOp>(®ionOp))
2450 builder.clone(regionOp, map);
2454 mlir::Block *partialDtorBlock =
nullptr;
2455 if (
auto arrayCtor = mlir::dyn_cast<cir::ArrayCtor>(op)) {
2456 mlir::Region &partialDtor = arrayCtor.getPartialDtor();
2457 if (!partialDtor.empty())
2458 partialDtorBlock = &partialDtor.front();
2459 }
else if (
auto arrayDtor = mlir::dyn_cast<cir::ArrayDtor>(op)) {
2468 if (arrayDtor.getDtorMayThrow())
2469 partialDtorBlock = bodyBlock;
2472 auto emitCtorDtorLoop = [&]() {
2476 [&](mlir::OpBuilder &b, mlir::Location loc) {
2477 auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
2478 auto cmp = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne,
2479 currentElement, stop);
2483 [&](mlir::OpBuilder &b, mlir::Location loc) {
2484 auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
2486 cloneRegionBodyInto(bodyBlock, currentElement);
2487 mlir::Value stride = builder.
getUnsignedInt(loc, 1, sizeTypeSize);
2488 auto nextElement = cir::PtrStrideOp::create(builder, loc, eltTy,
2489 currentElement, stride);
2492 mlir::Value stride = builder.
getSignedInt(loc, -1, sizeTypeSize);
2493 auto prevElement = cir::PtrStrideOp::create(builder, loc, eltTy,
2494 currentElement, stride);
2496 cloneRegionBodyInto(bodyBlock, prevElement);
2499 cir::YieldOp::create(b, loc);
2503 if (partialDtorBlock) {
2504 cir::CleanupScopeOp::create(
2505 builder, loc, cir::CleanupKind::EH,
2507 [&](mlir::OpBuilder &b, mlir::Location loc) {
2509 cir::YieldOp::create(b, loc);
2512 [&](mlir::OpBuilder &b, mlir::Location loc) {
2513 auto cur = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
2515 cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, cur, begin);
2517 builder, loc, cmp,
false,
2518 [&](mlir::OpBuilder &b, mlir::Location loc) {
2522 [&](mlir::OpBuilder &b, mlir::Location loc) {
2523 auto el = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
2524 auto neq = cir::CmpOp::create(
2525 builder, loc, cir::CmpOpKind::ne, el, begin);
2529 [&](mlir::OpBuilder &b, mlir::Location loc) {
2530 auto el = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
2531 mlir::Value negOne =
2533 auto prev = cir::PtrStrideOp::create(builder, loc, eltTy,
2536 cloneRegionBodyInto(partialDtorBlock, prev);
2539 cir::YieldOp::create(builder, loc);
2541 cir::YieldOp::create(b, loc);
2548 cir::YieldOp::create(builder, loc);
2553void LoweringPreparePass::lowerArrayDtor(cir::ArrayDtor op) {
2554 CIRBaseBuilderTy builder(getContext());
2555 builder.setInsertionPointAfter(op.getOperation());
2557 mlir::Type eltTy = op->getRegion(0).getArgument(0).getType();
2559 if (op.getNumElements()) {
2561 op.getAddr(), op.getNumElements(),
2568 mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize();
2574void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
2575 cir::CIRBaseBuilderTy builder(getContext());
2576 builder.setInsertionPointAfter(op.getOperation());
2578 mlir::Type eltTy = op->getRegion(0).getArgument(0).getType();
2580 if (op.getNumElements()) {
2582 op.getAddr(), op.getNumElements(),
2589 mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize();
2595cir::FuncOp LoweringPreparePass::getCalledFunction(cir::CallOp callOp) {
2596 mlir::SymbolRefAttr sym = llvm::dyn_cast_if_present<mlir::SymbolRefAttr>(
2597 callOp.getCallableForCallee());
2600 return symbolTables.lookupNearestSymbolFrom<cir::FuncOp>(callOp, sym);
2603void LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {
2604 cir::FuncOp funcOp = getCalledFunction(op);
2608 std::optional<cir::CtorKind> ctorKind = funcOp.getCxxConstructorKind();
2609 if (ctorKind && *ctorKind == cir::CtorKind::Copy &&
2610 funcOp.isCxxTrivialMemberFunction()) {
2612 CIRBaseBuilderTy builder(getContext());
2613 mlir::ValueRange operands = op.getOperands();
2614 mlir::Value dest = operands[0];
2615 mlir::Value src = operands[1];
2616 builder.setInsertionPoint(op);
2622cir::GlobalOp LoweringPreparePass::getOrCreateConstAggregateGlobal(
2623 CIRBaseBuilderTy &builder, mlir::Location loc, llvm::StringRef baseName,
2624 mlir::Type ty, mlir::TypedAttr constant, uint64_t alignment) {
2626 llvm::SmallVector<cir::GlobalOp, 1> &versions =
2627 constAggregateGlobals[baseName];
2630 for (cir::GlobalOp gv : versions) {
2631 if (gv.getSymType() == ty && gv.getInitialValue() == constant &&
2632 gv.getAlignment() == alignment)
2640 llvm::SmallString<128>
name(baseName);
2641 size_t baseLen =
name.size();
2642 unsigned version = versions.size();
2644 name.resize(baseLen);
2646 name.push_back(
'.');
2647 llvm::Twine(version).toVector(name);
2649 auto existingGv = symbolTables.lookupSymbolIn<cir::GlobalOp>(
2650 mlirModule, mlir::StringAttr::get(&getContext(), name));
2653 versions.push_back(existingGv);
2654 if (existingGv.getSymType() == ty &&
2655 existingGv.getInitialValue() == constant &&
2656 existingGv.getAlignment() == alignment)
2662 mlir::OpBuilder::InsertionGuard guard(builder);
2663 builder.setInsertionPointToStart(mlirModule.getBody());
2665 cir::GlobalOp::create(builder, loc, name, ty,
2667 cir::LangAddressSpaceAttr::get(
2668 &getContext(), cir::LangAddressSpace::Default),
2669 cir::GlobalLinkageKind::PrivateLinkage);
2670 mlir::SymbolTable::setSymbolVisibility(
2671 gv, mlir::SymbolTable::Visibility::Private);
2672 gv.setInitialValueAttr(constant);
2673 gv.setAlignment(alignment);
2677 symbolTables.getSymbolTable(mlirModule).insert(gv);
2679 versions.push_back(gv);
2683void LoweringPreparePass::lowerStoreOfConstAggregate(cir::StoreOp op) {
2685 auto constOp = op.getValue().getDefiningOp<cir::ConstantOp>();
2689 mlir::Type ty = constOp.getType();
2690 if (!mlir::isa<cir::ArrayType, cir::RecordType>(ty))
2696 auto alloca = op.getAddr().getDefiningOp<cir::AllocaOp>();
2700 mlir::TypedAttr constant = constOp.getValue();
2711 auto func = op->getParentOfType<cir::FuncOp>();
2714 llvm::StringRef funcName = func.getSymName();
2717 llvm::StringRef varName = alloca.getName();
2720 std::string baseName = (
"__const." + funcName +
"." + varName).str();
2721 CIRBaseBuilderTy builder(getContext());
2725 cir::GlobalOp gv = getOrCreateConstAggregateGlobal(
2726 builder, op.getLoc(), baseName, ty, constant, alloca.getAlignment());
2729 builder.setInsertionPoint(op);
2731 auto ptrTy = cir::PointerType::get(ty);
2732 mlir::Value globalPtr =
2733 cir::GetGlobalOp::create(builder, op.getLoc(), ptrTy, gv.getSymName());
2736 cir::CopyOp copyOp = builder.
createCopy(op.getAddr(), globalPtr);
2738 cir::CIRDataLayout dataLayout(mlirModule);
2739 uint64_t naturalAlign = dataLayout.getABITypeAlign(ty).value();
2740 if (alloca.getAlignment() != naturalAlign)
2741 copyOp.setDstAlignment(alloca.getAlignment());
2742 uint64_t srcAlign = gv.getAlignment().value_or(naturalAlign);
2743 if (srcAlign != naturalAlign)
2744 copyOp.setSrcAlignment(srcAlign);
2750 if (constOp.use_empty())
2757void LoweringPreparePass::lowerStdOp(cir::StdOpInterface typedOp) {
2758 mlir::Operation *op = typedOp.getOperation();
2759 cir::CIRBaseBuilderTy builder(getContext());
2760 builder.setInsertionPointAfter(op);
2761 mlir::Type resultType;
2762 if (op->getNumResults())
2763 resultType = op->getResult(0).getType();
2765 op->getLoc(), typedOp.getOriginalFnAttr(), resultType, op->getOperands());
2779 for (mlir::NamedAttribute attr : op->getDiscardableAttrs()) {
2780 if (call->getInherentAttr(
attr.getName()).has_value())
2781 call->setInherentAttr(
attr.getName(),
attr.getValue());
2783 call->setDiscardableAttr(
attr.getName(),
attr.getValue());
2786 op->replaceAllUsesWith(call);
2790void LoweringPreparePass::runOnOp(mlir::Operation *op) {
2791 if (
auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) {
2792 lowerArrayCtor(arrayCtor);
2793 }
else if (
auto arrayDtor = dyn_cast<cir::ArrayDtor>(op)) {
2794 lowerArrayDtor(arrayDtor);
2795 }
else if (
auto registerOp = dyn_cast<cir::RegisterExitDtorOp>(op)) {
2796 lowerRegisterExitDtorOp(registerOp);
2797 }
else if (
auto stdOp = mlir::dyn_cast<cir::StdOpInterface>(op)) {
2799 }
else if (
auto cast = mlir::dyn_cast<cir::CastOp>(op)) {
2801 }
else if (
auto complexConj = mlir::dyn_cast<cir::ComplexConjOp>(op)) {
2802 lowerComplexConjOp(complexConj);
2803 }
else if (
auto complexDiv = mlir::dyn_cast<cir::ComplexFDivOp>(op)) {
2804 lowerComplexFDivOp(complexDiv);
2805 }
else if (
auto complexMul = mlir::dyn_cast<cir::ComplexFMulOp>(op)) {
2806 lowerComplexFMulOp(complexMul);
2807 }
else if (
auto complexDiv = mlir::dyn_cast<cir::ComplexDivOp>(op)) {
2808 lowerComplexDivOp(complexDiv);
2809 }
else if (
auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op)) {
2810 lowerComplexMulOp(complexMul);
2811 }
else if (
auto glob = mlir::dyn_cast<cir::GlobalOp>(op)) {
2812 lowerGlobalOp(glob);
2813 if (
auto regAttr = glob->getAttrOfType<CUDAVarRegistrationInfoAttr>(
2814 CUDAVarRegistrationInfoAttr::getMnemonic()))
2815 cudaDeviceVars.emplace_back(glob, regAttr);
2816 }
else if (
auto getGlob = mlir::dyn_cast<cir::GetGlobalOp>(op)) {
2817 lowerGetGlobalOp(getGlob);
2818 }
else if (
auto callOp = dyn_cast<cir::CallOp>(op)) {
2819 lowerTrivialCopyCall(callOp);
2820 }
else if (
auto storeOp = dyn_cast<cir::StoreOp>(op)) {
2821 lowerStoreOfConstAggregate(storeOp);
2822 }
else if (
auto fnOp = dyn_cast<cir::FuncOp>(op)) {
2823 if (
auto globalCtor = fnOp.getGlobalCtorPriority())
2824 globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
2825 else if (
auto globalDtor = fnOp.getGlobalDtorPriority())
2826 globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
2828 if (mlir::Attribute attr =
2829 fnOp->getAttr(cir::CUDAKernelNameAttr::getMnemonic());
2830 attr && !fnOp.isDeclaration()) {
2831 auto kernelNameAttr = dyn_cast<CUDAKernelNameAttr>(attr);
2832 llvm::StringRef kernelName = kernelNameAttr.getKernelName();
2833 cudaKernelMap[kernelName] = fnOp;
2835 }
else if (
auto threeWayCmp = dyn_cast<cir::CmpThreeWayOp>(op)) {
2836 lowerThreeWayCmpOp(threeWayCmp);
2837 }
else if (
auto initOp = dyn_cast<cir::LocalInitOp>(op)) {
2838 lowerLocalInitOp(initOp);
2849 llvm::StringRef name) {
2850 return (
"__" + prefix + name).str();
2872void LoweringPreparePass::buildCUDAModuleCtor() {
2873 bool isHIP = getLangOpts().HIP;
2875 if (getLangOpts().GPURelocatableDeviceCode)
2876 llvm_unreachable(
"GPU RDC NYI");
2880 if (cudaKernelMap.empty() && cudaDeviceVars.empty())
2885 auto deviceBinaryAttr = mlirModule->getAttrOfType<mlir::StringAttr>(
2886 CIRDialect::getCUDADeviceBinaryAttrName());
2887 if (!deviceBinaryAttr && !isHIP)
2892 mlir::Location loc = mlirModule->getLoc();
2893 CIRBaseBuilderTy builder(getContext());
2894 builder.setInsertionPointToStart(mlirModule.getBody());
2898 PointerType voidPtrPtrTy = builder.
getPointerTo(voidPtrTy);
2904 llvm::StringRef fatbinConstName =
2905 getLangOpts().HIP ?
".hip_fatbin" :
".nv_fatbin";
2907 llvm::StringRef fatbinSectionName =
2908 getLangOpts().HIP ?
".hipFatBinSegment" :
".nvFatBinSegment";
2911 if (deviceBinaryAttr) {
2914 auto fatbinType = mlir::cast<ArrayType>(deviceBinaryAttr.getType());
2916 fatbinStr = GlobalOp::create(builder, loc, fatbinStrName, fatbinType,
2918 GlobalLinkageKind::PrivateLinkage);
2919 constexpr unsigned HIPCodeObjectAlign = 4096;
2920 fatbinStr.setAlignment(isHIP ? HIPCodeObjectAlign : 8);
2922 fatbinStr.setInitialValueAttr(
2923 cir::ConstArrayAttr::get(fatbinType, deviceBinaryAttr));
2928 fatbinStr = GlobalOp::create(
2929 builder, loc, addCUIDSuffix(
"__hip_fatbin"), builder.
getUIntNTy(8),
2930 true, {}, GlobalLinkageKind::ExternalLinkage);
2932 fatbinStr.setSection(fatbinConstName);
2933 fatbinStr.setPrivate();
2937 mlir::Type fatbinWrapperMembers[] = {intTy, intTy, voidPtrTy, voidPtrTy};
2938 auto fatbinWrapperType = cir::StructType::get(
2939 &getContext(), fatbinWrapperMembers,
false,
false,
2941 std::string fatbinWrapperName =
2943 GlobalOp fatbinWrapper = GlobalOp::create(
2944 builder, loc, fatbinWrapperName, fatbinWrapperType,
2945 true, {}, GlobalLinkageKind::PrivateLinkage);
2946 fatbinWrapper.setSection(fatbinSectionName);
2948 constexpr unsigned cudaFatMagic = 0x466243b1;
2949 constexpr unsigned hipFatMagic = 0x48495046;
2950 unsigned fatMagic =
isHIP ? hipFatMagic : cudaFatMagic;
2952 auto magicInit = IntAttr::get(intTy, fatMagic);
2953 auto versionInit = IntAttr::get(intTy, 1);
2954 auto fatbinStrSymbol =
2955 mlir::FlatSymbolRefAttr::get(fatbinStr.getSymNameAttr());
2956 auto fatbinInit = GlobalViewAttr::get(voidPtrTy, fatbinStrSymbol);
2958 fatbinWrapper.setInitialValueAttr(cir::ConstRecordAttr::get(
2960 mlir::ArrayAttr::get(&getContext(),
2961 {magicInit, versionInit, fatbinInit, unusedInit})));
2964 std::string gpubinHandleName =
2967 gpubinHandleName = addCUIDSuffix(gpubinHandleName);
2969 GlobalOp gpuBinHandle = GlobalOp::create(
2970 builder, loc, gpubinHandleName, voidPtrPtrTy,
2971 false, {}, cir::GlobalLinkageKind::InternalLinkage);
2973 gpuBinHandle.setPrivate();
2978 std::string regFuncName =
2980 FuncType regFuncType = FuncType::get({voidPtrTy}, voidPtrPtrTy);
2981 cir::FuncOp regFunc =
2982 buildRuntimeFunction(builder, regFuncName, loc, regFuncType);
2985 cir::FuncOp moduleCtor = buildRuntimeFunction(
2986 builder, moduleCtorName, loc, FuncType::get({}, voidTy),
2987 GlobalLinkageKind::InternalLinkage);
2989 globalCtorList.emplace_back(moduleCtorName,
2990 cir::GlobalCtorAttr::getDefaultPriority());
2991 builder.setInsertionPointToStart(moduleCtor.addEntryBlock());
2999 mlir::Block *entryBlock = builder.getInsertionBlock();
3000 mlir::Region *parent = entryBlock->getParent();
3001 mlir::Block *ifBlock = builder.createBlock(parent);
3002 mlir::Block *exitBlock = builder.createBlock(parent);
3004 mlir::OpBuilder::InsertionGuard guard(builder);
3005 builder.setInsertionPointToEnd(entryBlock);
3006 mlir::Value handle =
3008 auto handlePtrTy = mlir::cast<cir::PointerType>(handle.getType());
3009 mlir::Value nullPtr = builder.
getNullPtr(handlePtrTy, loc);
3010 mlir::Value isNull =
3011 builder.
createCompare(loc, cir::CmpOpKind::eq, handle, nullPtr);
3012 cir::BrCondOp::create(builder, loc, isNull, ifBlock, exitBlock);
3016 mlir::OpBuilder::InsertionGuard guard(builder);
3017 builder.setInsertionPointToStart(ifBlock);
3019 mlir::Value fatbinVoidPtr = builder.
createBitcast(wrapper, voidPtrTy);
3020 cir::CallOp gpuBinaryHandleCall =
3022 mlir::Value gpuBinaryHandle = gpuBinaryHandleCall.getResult();
3024 mlir::Value gpuBinaryHandleGlobal = builder.
createGetGlobal(gpuBinHandle);
3025 builder.
createStore(loc, gpuBinaryHandle, gpuBinaryHandleGlobal);
3026 cir::BrOp::create(builder, loc, exitBlock);
3031 mlir::OpBuilder::InsertionGuard guard(builder);
3032 builder.setInsertionPointToStart(exitBlock);
3033 mlir::Value gHandle =
3036 if (std::optional<FuncOp> regGlobal = buildCUDARegisterGlobals())
3039 if (std::optional<FuncOp> dtor = buildHIPModuleDtor()) {
3040 cir::CIRBaseBuilderTy globalBuilder(getContext());
3041 globalBuilder.setInsertionPointToStart(mlirModule.getBody());
3042 FuncOp atexit = buildRuntimeFunction(
3043 globalBuilder,
"atexit", loc,
3044 FuncType::get(PointerType::get(dtor->getFunctionType()), intTy));
3045 mlir::Value dtorFunc = GetGlobalOp::create(
3046 builder, loc, PointerType::get(dtor->getFunctionType()),
3047 mlir::FlatSymbolRefAttr::get(dtor->getSymNameAttr()));
3050 cir::ReturnOp::create(builder, loc);
3054 if (!getLangOpts().GPURelocatableDeviceCode) {
3062 mlir::Value fatbinVoidPtr = builder.
createBitcast(wrapper, voidPtrTy);
3063 cir::CallOp gpuBinaryHandleCall =
3065 mlir::Value gpuBinaryHandle = gpuBinaryHandleCall.getResult();
3067 mlir::Value gpuBinaryHandleGlobal = builder.
createGetGlobal(gpuBinHandle);
3068 builder.
createStore(loc, gpuBinaryHandle, gpuBinaryHandleGlobal);
3071 if (std::optional<FuncOp> regGlobal = buildCUDARegisterGlobals()) {
3072 builder.
createCallOp(loc, *regGlobal, gpuBinaryHandle);
3078 std::optional<llvm::VersionTuple> sdkVersion = getSDKVersion();
3083 cir::CIRBaseBuilderTy globalBuilder(getContext());
3084 globalBuilder.setInsertionPointToStart(mlirModule.getBody());
3086 buildRuntimeFunction(globalBuilder,
"__cudaRegisterFatBinaryEnd", loc,
3087 FuncType::get({voidPtrPtrTy}, voidTy));
3091 llvm_unreachable(
"GPU RDC NYI");
3096 if (std::optional<FuncOp> dtor = buildCUDAModuleDtor()) {
3099 cir::CIRBaseBuilderTy globalBuilder(getContext());
3100 globalBuilder.setInsertionPointToStart(mlirModule.getBody());
3101 FuncOp atexit = buildRuntimeFunction(
3102 globalBuilder,
"atexit", loc,
3103 FuncType::get(PointerType::get(dtor->getFunctionType()), intTy));
3104 mlir::Value dtorFunc = GetGlobalOp::create(
3105 builder, loc, PointerType::get(dtor->getFunctionType()),
3106 mlir::FlatSymbolRefAttr::get(dtor->getSymNameAttr()));
3109 cir::ReturnOp::create(builder, loc);
3112std::optional<FuncOp> LoweringPreparePass::buildCUDAModuleDtor() {
3113 if (!mlirModule->getAttr(CIRDialect::getCUDADeviceBinaryAttrName()))
3118 VoidType voidTy = VoidType::get(&getContext());
3119 PointerType voidPtrPtrTy = PointerType::get(PointerType::get(voidTy));
3121 mlir::Location loc = mlirModule.getLoc();
3123 cir::CIRBaseBuilderTy builder(getContext());
3124 builder.setInsertionPointToStart(mlirModule.getBody());
3127 std::string unregisterFuncName =
3129 FuncOp unregisterFunc = buildRuntimeFunction(
3130 builder, unregisterFuncName, loc, FuncType::get({voidPtrPtrTy}, voidTy));
3139 buildRuntimeFunction(builder, dtorName, loc, FuncType::get({}, voidTy),
3140 GlobalLinkageKind::InternalLinkage);
3142 builder.setInsertionPointToStart(dtor.addEntryBlock());
3148 GlobalOp gpubinGlobal = cast<GlobalOp>(mlirModule.lookupSymbol(gpubinName));
3150 mlir::Value gpubin = builder.
createLoad(loc, gpubinAddress);
3152 ReturnOp::create(builder, loc);
3169std::optional<FuncOp> LoweringPreparePass::buildHIPModuleDtor() {
3172 VoidType voidTy = VoidType::get(&getContext());
3173 PointerType voidPtrPtrTy = PointerType::get(PointerType::get(voidTy));
3175 mlir::Location loc = mlirModule.getLoc();
3177 cir::CIRBaseBuilderTy builder(getContext());
3178 builder.setInsertionPointToStart(mlirModule.getBody());
3181 std::string unregisterFuncName =
3183 FuncOp unregisterFunc = buildRuntimeFunction(
3184 builder, unregisterFuncName, loc, FuncType::get({voidPtrPtrTy}, voidTy));
3188 buildRuntimeFunction(builder, dtorName, loc, FuncType::get({}, voidTy),
3189 GlobalLinkageKind::InternalLinkage);
3191 std::string gpubinName =
3193 GlobalOp gpuBinGlobal = cast<GlobalOp>(mlirModule.lookupSymbol(gpubinName));
3195 mlir::Block *entryBlock = dtor.addEntryBlock();
3196 mlir::Block *ifBlock = builder.createBlock(&dtor.getBody());
3197 mlir::Block *exitBlock = builder.createBlock(&dtor.getBody());
3199 mlir::OpBuilder::InsertionGuard guard(builder);
3200 builder.setInsertionPointToEnd(entryBlock);
3201 mlir::Value handle =
3203 auto handlePtrTy = mlir::cast<cir::PointerType>(handle.getType());
3204 mlir::Value nullPtr = builder.
getNullPtr(handlePtrTy, loc);
3205 mlir::Value isNotNull =
3206 builder.
createCompare(loc, cir::CmpOpKind::ne, handle, nullPtr);
3207 cir::BrCondOp::create(builder, loc, isNotNull, ifBlock, exitBlock);
3211 mlir::OpBuilder::InsertionGuard ifGuard(builder);
3212 builder.setInsertionPointToStart(ifBlock);
3215 cir::BrOp::create(builder, loc, exitBlock);
3218 mlir::OpBuilder::InsertionGuard exitGuard(builder);
3219 builder.setInsertionPointToStart(exitBlock);
3220 cir::ReturnOp::create(builder, loc);
3226std::optional<FuncOp> LoweringPreparePass::buildCUDARegisterGlobals() {
3227 if (cudaKernelMap.empty() && cudaDeviceVars.empty())
3230 cir::CIRBaseBuilderTy builder(getContext());
3231 builder.setInsertionPointToStart(mlirModule.getBody());
3233 mlir::Location loc = mlirModule.getLoc();
3236 auto voidTy = VoidType::get(&getContext());
3237 auto voidPtrTy = PointerType::get(voidTy);
3238 auto voidPtrPtrTy = PointerType::get(voidPtrTy);
3242 std::string regGlobalFuncName =
3244 auto regGlobalFuncTy = FuncType::get({voidPtrPtrTy}, voidTy);
3245 FuncOp regGlobalFunc =
3246 buildRuntimeFunction(builder, regGlobalFuncName, loc, regGlobalFuncTy,
3247 GlobalLinkageKind::InternalLinkage);
3248 builder.setInsertionPointToStart(regGlobalFunc.addEntryBlock());
3250 buildCUDARegisterGlobalFunctions(builder, regGlobalFunc);
3251 buildCUDARegisterVars(builder, regGlobalFunc);
3253 ReturnOp::create(builder, loc);
3254 return regGlobalFunc;
3257void LoweringPreparePass::buildCUDARegisterGlobalFunctions(
3258 cir::CIRBaseBuilderTy &builder, FuncOp regGlobalFunc) {
3259 mlir::Location loc = mlirModule.getLoc();
3261 cir::CIRDataLayout dataLayout(mlirModule);
3263 auto voidTy = VoidType::get(&getContext());
3264 auto voidPtrTy = PointerType::get(voidTy);
3265 auto voidPtrPtrTy = PointerType::get(voidPtrTy);
3268 cir::IntType::get(&getContext(), getTargetInfo().
getCharWidth(),
3272 mlir::Value fatbinHandle = *regGlobalFunc.args_begin();
3274 cir::CIRBaseBuilderTy globalBuilder(getContext());
3275 globalBuilder.setInsertionPointToStart(mlirModule.getBody());
3289 FuncOp cudaRegisterFunction = buildRuntimeFunction(
3291 FuncType::get({voidPtrPtrTy, voidPtrTy, voidPtrTy, voidPtrTy, intTy,
3292 voidPtrTy, voidPtrTy, voidPtrTy, voidPtrTy, voidPtrTy},
3295 auto makeConstantString = [&](llvm::StringRef str) -> GlobalOp {
3296 auto strType = ArrayType::get(&getContext(), charTy, 1 + str.size());
3297 auto tmpString = cir::GlobalOp::create(
3298 globalBuilder, loc, (
".str" + str).str(), strType,
3300 cir::GlobalLinkageKind::PrivateLinkage);
3303 tmpString.setInitialValueAttr(
3304 ConstArrayAttr::get(strType, StringAttr::get(str +
"\0", strType)));
3305 tmpString.setPrivate();
3309 cir::ConstantOp cirNullPtr = builder.
getNullPtr(voidPtrTy, loc);
3310 bool isHIP = getLangOpts().HIP;
3311 for (
auto kernelName : cudaKernelMap.keys()) {
3312 FuncOp deviceStub = cudaKernelMap[kernelName];
3313 GlobalOp deviceFuncStr = makeConstantString(kernelName);
3317 mlir::Value hostFunc;
3324 auto funcHandle = cast<GlobalOp>(mlirModule.lookupSymbol(kernelName));
3329 GetGlobalOp::create(
3330 builder, loc, PointerType::get(deviceStub.getFunctionType()),
3331 mlir::FlatSymbolRefAttr::get(deviceStub.getSymNameAttr())),
3335 loc, cudaRegisterFunction,
3336 {fatbinHandle, hostFunc, deviceFunc, deviceFunc,
3337 ConstantOp::create(builder, loc, IntAttr::get(intTy, -1)), cirNullPtr,
3338 cirNullPtr, cirNullPtr, cirNullPtr, cirNullPtr});
3345void LoweringPreparePass::buildCUDARegisterVars(cir::CIRBaseBuilderTy &builder,
3346 FuncOp regGlobalFunc) {
3347 mlir::Location loc = mlirModule.getLoc();
3349 cir::CIRDataLayout dataLayout(mlirModule);
3352 PointerType voidPtrPtrTy = builder.
getPointerTo(voidPtrTy);
3354 IntType sizeTy = builder.
getUIntNTy(getTargetInfo().getMaxPointerWidth());
3356 cir::IntType::get(&getContext(), getTargetInfo().
getCharWidth(),
3359 if (cudaDeviceVars.empty())
3362 cir::CIRBaseBuilderTy globalBuilder(getContext());
3363 globalBuilder.setInsertionPointToStart(mlirModule.getBody());
3365 cir::VoidType voidTy = builder.
getVoidTy();
3366 FuncOp cudaRegisterVar;
3367 FuncOp cudaRegisterManagedVar;
3374 FuncOp cudaRegisterSurface = buildRuntimeFunction(
3377 {voidPtrPtrTy, voidPtrTy, voidPtrTy, voidPtrTy, intTy, intTy},
3380 auto makeConstantString = [&](llvm::StringRef str) -> GlobalOp {
3381 auto strType = ArrayType::get(&getContext(), charTy, 1 + str.size());
3382 auto tmpString = cir::GlobalOp::create(
3383 globalBuilder, loc, (
".str" + str).str(), strType,
3385 cir::GlobalLinkageKind::PrivateLinkage);
3386 tmpString.setInitialValueAttr(
3387 ConstArrayAttr::get(strType, StringAttr::get(str +
"\0", strType)));
3388 tmpString.setPrivate();
3392 mlir::Value fatbinHandle = *regGlobalFunc.args_begin();
3394 for (
auto &[global, regAttr] : cudaDeviceVars) {
3396 if (regAttr.getIsManaged() && global.isDeclaration())
3399 GlobalOp deviceNameStr = makeConstantString(regAttr.getDeviceSideName());
3402 mlir::Value hostVar =
3405 llvm::TypeSize size = dataLayout.getTypeAllocSize(global.getSymType());
3407 if (regAttr.getIsManaged()) {
3411 if (!cudaRegisterManagedVar)
3412 cudaRegisterManagedVar = buildRuntimeFunction(
3416 {voidPtrPtrTy, voidPtrTy, voidPtrTy, voidPtrTy, sizeTy, intTy},
3419 llvm::StringRef
name = global.getSymName();
3420 assert(
name.ends_with(
".managed") &&
3421 "HIP managed variables not transformed");
3422 auto managedVar = mlirModule.lookupSymbol<GlobalOp>(
3423 name.drop_back(llvm::StringRef(
".managed").size()));
3424 mlir::Value managedPtr =
3426 auto varSize = ConstantOp::create(
3427 builder, loc, IntAttr::get(sizeTy, size.getFixedValue()));
3428 auto align = ConstantOp::create(
3429 builder, loc, IntAttr::get(intTy, global.getAlignment().value_or(1)));
3431 loc, cudaRegisterManagedVar,
3432 {fatbinHandle, managedPtr, hostVar, deviceName, varSize,
align});
3434 auto isExtern = ConstantOp::create(
3435 builder, loc, IntAttr::get(intTy, regAttr.getIsExtern() ? 1 : 0));
3437 switch (regAttr.getKind()) {
3438 case cir::CUDADeviceVarKind::Variable: {
3445 if (!cudaRegisterVar)
3446 cudaRegisterVar = buildRuntimeFunction(
3449 FuncType::get({voidPtrPtrTy, voidPtrTy, voidPtrTy, voidPtrTy,
3450 intTy, sizeTy, intTy, intTy},
3453 auto varSize = ConstantOp::create(
3454 builder, loc, IntAttr::get(sizeTy, size.getFixedValue()));
3455 auto isConstant = ConstantOp::create(
3456 builder, loc, IntAttr::get(intTy, regAttr.getIsConstant() ? 1 : 0));
3458 ConstantOp::create(builder, loc, IntAttr::get(intTy, 0));
3461 {fatbinHandle, hostVar, deviceName, deviceName,
3462 isExtern, varSize, isConstant, normalized});
3466 case cir::CUDADeviceVarKind::Surface: {
3467 cir::ConstantOp surfaceType = ConstantOp::create(
3468 builder, loc, IntAttr::get(intTy, regAttr.getSurfTexType()));
3470 {fatbinHandle, hostVar, deviceName, deviceName,
3471 surfaceType, isExtern});
3475 case cir::CUDADeviceVarKind::Texture:
3476 llvm_unreachable(
"Texture registration NYI");
3482void LoweringPreparePass::runOnOperation() {
3483 mlirModule = getOperation();
3488 <<
" requires a module with a triple";
3489 return signalPassFailure();
3492 llvm::SmallVector<mlir::Operation *> opsToTransform;
3494 mlirModule->walk([&](mlir::Operation *op) {
3495 if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
3496 cir::ComplexConjOp, cir::ComplexMulOp, cir::ComplexDivOp,
3497 cir::ComplexFMulOp, cir::ComplexFDivOp, cir::DynamicCastOp,
3498 cir::FuncOp, cir::CallOp, cir::GetGlobalOp, cir::GlobalOp,
3499 cir::StoreOp, cir::CmpThreeWayOp, cir::LocalInitOp,
3500 cir::RegisterExitDtorOp, cir::StdOpInterface>(op))
3501 opsToTransform.push_back(op);
3504 for (mlir::Operation *o : opsToTransform)
3510 for (
auto globalOp : mlirModule.getOps<cir::GlobalOp>())
3511 globalOp.removeTlsRefsAttr();
3513 buildCXXGlobalInitFunc();
3517 mlirModule->removeAttr(CIRDialect::getCXXModuleInitFnNameAttrName());
3518 mlirModule->removeAttr(CIRDialect::getCXXModuleImportedInitsAttrName());
3519 buildCXXGlobalTlsFunc();
3520 if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice) {
3521 buildCUDAModuleCtor();
3526 mlirModule->removeAttr(CIRDialect::getCUDADeviceBinaryAttrName());
3530 for (
auto &entry : cudaKernelMap)
3531 entry.getValue()->removeAttr(CUDAKernelNameAttr::getMnemonic());
3532 for (
auto &deviceVar : cudaDeviceVars)
3533 deviceVar.first->removeAttr(CUDAVarRegistrationInfoAttr::getMnemonic());
3536 buildGlobalCtorDtorList();
3540 return std::make_unique<LoweringPreparePass>();
static void emitBody(CodeGenFunction &CGF, const Stmt *S, const Stmt *NextLoop, int MaxLevel, int Level=0)
static llvm::FunctionCallee getGuardReleaseFn(CodeGenModule &CGM, llvm::PointerType *GuardPtrTy)
static llvm::FunctionCallee getGuardAbortFn(CodeGenModule &CGM, llvm::PointerType *GuardPtrTy)
static llvm::FunctionCallee getGuardAcquireFn(CodeGenModule &CGM, llvm::PointerType *GuardPtrTy)
static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target)
static mlir::Value buildRangeReductionComplexDiv(CIRBaseBuilderTy &builder, mlir::Location loc, mlir::Value lhsReal, mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag)
static cir::GlobalLinkageKind getThreadLocalWrapperLinkage(GlobalOp op, const clang::TargetInfo &targetInfo)
static llvm::StringRef getComplexDivLibCallName(llvm::APFloat::Semantics semantics)
static llvm::StringRef getComplexMulLibCallName(llvm::APFloat::Semantics semantics)
static std::string getPrioritySuffix(unsigned priority)
Compute the zero-padded priority suffix used to name priority-specific global init functions,...
static bool isThreadWrapperReplaceable(const clang::TargetInfo &targetInfo)
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 std::string addUnderscoredPrefix(llvm::StringRef prefix, llvm::StringRef name)
static SmallString< 128 > getTransformedFileName(mlir::ModuleOp mlirModule)
static mlir::Value lowerComplexToComplexCast(mlir::MLIRContext &ctx, cir::CastOp op, cir::CastKind scalarCastKind)
static llvm::SmallVector< mlir::Attribute > prepareCtorDtorAttrList(mlir::MLIRContext *context, llvm::ArrayRef< cir::GlobalCtorDtorEntry > list)
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 mlir::Value lowerComplexFDiv(LoweringPreparePass &pass, CIRBaseBuilderTy &builder, mlir::Location loc, cir::ComplexFDivOp op, mlir::Value lhsReal, mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag, mlir::MLIRContext &mlirCx, const clang::TargetInfo &targetInfo)
static llvm::StringRef getCUDAPrefix(const clang::LangOptions &langOpts)
static mlir::Type higherPrecisionElementTypeForComplexArithmetic(mlir::MLIRContext &context, const clang::TargetInfo &targetInfo, const clang::LangOptions &langOpts, CIRBaseBuilderTy &builder, mlir::Type elementType)
static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, const clang::TargetInfo &targetInfo, mlir::Operation *op, mlir::Type eltTy, mlir::Value addr, mlir::Value numElements, uint64_t arrayLen, bool isCtor)
Lower a cir.array.ctor or cir.array.dtor into a do-while loop that iterates over every element.
static mlir::Value lowerScalarToComplexCast(mlir::MLIRContext &ctx, cir::CastOp op)
static mlir::Value lowerComplexFMul(LoweringPreparePass &pass, CIRBaseBuilderTy &builder, mlir::Location loc, cir::ComplexFMulOp op, mlir::Value lhsReal, mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag)
static StringRef getTriple(const Command &Job)
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y)
Defines the SourceManager interface.
Defines various enumerations that describe declaration and type specifiers.
Defines the TargetCXXABI class, which abstracts details of the C++ ABI that we're targeting.
static const TemplateArgument & getArgument(const TemplateArgument &A)
mlir::Value createDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::TypedAttr getConstNullPtrAttr(mlir::Type t)
mlir::Value createLogicalOr(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
cir::ConditionOp createCondition(mlir::Value condition)
Create a loop condition.
cir::CopyOp createCopy(mlir::Value dst, mlir::Value src, bool isVolatile=false, bool skipTailPadding=false)
Create a copy with inferred length.
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 getVoidFnPtrTy(mlir::TypeRange argTypes={})
Returns void (*)(T...) as a cir::PointerType.
mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
cir::PointerType getPointerTo(mlir::Type ty)
mlir::Value createFNeg(mlir::Location loc, mlir::Value operand)
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::Type returnType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={}, llvm::ArrayRef< mlir::NamedAttrList > argAttrs={}, llvm::ArrayRef< mlir::NamedAttribute > resAttrs={}, cir::CallingConv callingConv=cir::CallingConv::C)
mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand)
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc)
cir::IntType getUIntNTy(int n)
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::GetGlobalOp createGetGlobal(mlir::Location loc, cir::GlobalOp global, bool threadLocal=false)
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, llvm::StringRef name, mlir::IntegerAttr alignment, mlir::Value dynAllocSize)
cir::LoadOp createLoad(mlir::Location loc, mlir::Value ptr, bool isVolatile=false, uint64_t alignment=0, bool isNontemporal=false)
mlir::Value getSignedInt(mlir::Location loc, int64_t val, unsigned numBits)
mlir::Value createAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::FuncType getVoidFnTy(mlir::TypeRange argTypes={})
Returns void (T...) as a cir::FuncType.
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
mlir::IntegerAttr getAlignmentAttr(clang::CharUnits alignment)
mlir::Value createSelect(mlir::Location loc, mlir::Value condition, mlir::Value trueValue, mlir::Value falseValue)
mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
mlir::Value createMinus(mlir::Location loc, mlir::Value input, bool nsw=false)
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty, int64_t value)
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real, mlir::Value imag)
cir::PointerType getVoidPtrTy(clang::LangAS langAS=clang::LangAS::Default)
mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand)
cir::IntType getSIntNTy(int n)
mlir::Value createAlignedLoad(mlir::Location loc, mlir::Value ptr, uint64_t alignment)
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 createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst, bool isVolatile=false, bool isNontemporal=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::BoolType getBoolTy()
mlir::Value getUnsignedInt(mlir::Location loc, uint64_t val, unsigned numBits)
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand)
mlir::ptr::MemorySpaceAttrInterface getAllocaAddrSpace(mlir::MLIRContext *ctx)
llvm::Align getABITypeAlign(mlir::Type ty) const
static llvm::SmallVector< RecordMemberKind > getAllDataKinds(llvm::ArrayRef< mlir::Type > members)
One Data kind per member.
llvm::Align getAsAlign() const
Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit bytes.
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
static CharUnits One()
Construct a CharUnits quantity of one.
static CharUnits fromQuantity(QuantityType Quantity)
Construct a CharUnits quantity from a raw integer type.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Exposes information about the current target.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
unsigned getTypeWidth(IntType T) const
Return the width (in bits) of the specified integer type enum.
IntType getSignedSizeType() const
const llvm::fltSemantics & getLongDoubleFormat() const
Defines the clang::TargetInfo interface.
static bool isLocalLinkage(GlobalLinkageKind linkage)
static bool isWeakODRLinkage(GlobalLinkageKind linkage)
static bool isLinkOnceLinkage(GlobalLinkageKind linkage)
std::unique_ptr< LowerModule > createLowerModule(mlir::ModuleOp module)
const internal::VariadicAllOfMatcher< Attr > attr
bool isHIP(ID Id)
isHIP - Is this a HIP input.
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
void info(bool Verbose, unsigned Level, const char *Fmt, Ts &&...Args)
Prints an indented note to stderr when Verbose is set.
bool CudaFeatureEnabled(llvm::VersionTuple, CudaFeature)
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_.
@ CUDA_USES_FATBIN_REGISTER_END
std::unique_ptr< Pass > createLoweringPreparePass()
__DEVICE__ _Tp arg(const std::complex< _Tp > &__c)
static bool opGlobalAnnotations()
static bool opGlobalCtorPriority()
static bool shouldSplitConstantStore()
static bool shouldUseMemSetToInitialize()
static bool opFuncExtraAttrs()
static bool shouldUseBZeroPlusStoresToInitialize()
static bool opFuncCallingConv()
static bool fastMathFlags()
static bool astVarDeclInterface()