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() <<
"'";
354 mlir::ModuleOp mlirModule;
374 mlir::SymbolTableCollection symbolTables;
377 llvm::StringMap<uint32_t> dynamicInitializerNames;
378 llvm::SmallVector<cir::FuncOp> dynamicInitializers;
383 std::map<unsigned, llvm::SmallVector<cir::FuncOp, 4>>
384 prioritizedDynamicInitializers;
385 llvm::SmallVector<cir::FuncOp> globalThreadLocalInitializers;
386 llvm::StringMap<cir::FuncOp> threadLocalWrappers;
387 llvm::StringMap<cir::FuncOp> threadLocalInitAliases;
390 llvm::StringMap<cir::GlobalOp> staticLocalDeclGuardMap;
392 llvm::StringMap<llvm::SmallVector<cir::GlobalOp, 1>> constAggregateGlobals;
395 llvm::SmallVector<cir::GlobalCtorDtorEntry, 4> globalCtorList;
397 llvm::SmallVector<cir::GlobalCtorDtorEntry, 4> globalDtorList;
401 bool useARMGuardVarABI()
const {
402 switch (lowerModule->getCXXABIKind()) {
403 case clang::TargetCXXABI::GenericARM:
404 case clang::TargetCXXABI::iOS:
405 case clang::TargetCXXABI::WatchOS:
406 case clang::TargetCXXABI::GenericAArch64:
407 case clang::TargetCXXABI::WebAssembly:
416 cir::CallOp emitAtExitCall(CIRBaseBuilderTy &builder, mlir::Location loc,
417 cir::FuncOp dtorFunc, mlir::Value arg,
bool tls) {
418 cir::GlobalOp handle;
419 cir::FuncOp fnAtExit;
421 cir::PointerType voidFnPtrTy = builder.
getVoidFnPtrTy({voidPtrTy});
423 mlir::OpBuilder::InsertionGuard guard(builder);
425 builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
426 handle = getOrCreateRuntimeVariable(
427 builder,
"__dso_handle", loc, builder.
getUIntNTy(8),
428 cir::GlobalLinkageKind::ExternalLinkage, cir::VisibilityKind::Hidden);
432 cir::PointerType handlePtrTy = builder.
getPointerTo(handle.getSymType());
435 cir::FuncType::get({voidFnPtrTy, voidPtrTy, handlePtrTy}, intTy);
437 llvm::StringLiteral nameAtExit =
"__cxa_atexit";
439 nameAtExit = getTargetInfo().getTriple().isOSDarwin()
440 ? llvm::StringLiteral(
"_tlv_atexit")
441 : llvm::StringLiteral(
"__cxa_thread_atexit");
443 fnAtExit = buildRuntimeFunction(builder, nameAtExit, loc, fnAtExitType);
447 auto dtorPtrTy = cir::PointerType::get(dtorFunc.getFunctionType());
448 args[0] = cir::GetGlobalOp::create(builder, loc, dtorPtrTy,
449 dtorFunc.getSymName());
450 args[0] = cir::CastOp::create(builder, loc, voidFnPtrTy,
451 cir::CastKind::bitcast, args[0]);
452 args[1] = cir::CastOp::create(builder, loc, voidPtrTy,
453 cir::CastKind::bitcast, arg);
454 args[2] = cir::GetGlobalOp::create(
455 builder, loc, builder.
getPointerTo(handle.getSymType()),
456 handle.getSymName());
462 void emitGlobalGuardedDtorRegion(CIRBaseBuilderTy &builder,
463 cir::GlobalOp global,
464 mlir::Region &dtorRegion,
bool tls,
465 mlir::Block &entryBB) {
470 cir::CallOp dtorCall;
471 cir::FuncOp dtorFunc =
472 getOrCreateDtorFunc(builder, global, dtorRegion, dtorCall);
476 builder.setInsertionPointAfter(dtorCall);
477 emitAtExitCall(builder, dtorCall.getLoc(), dtorFunc,
478 dtorCall.getArgOperand(0), tls);
480 mlir::Block &dtorBlock = dtorRegion.front();
481 entryBB.getOperations().splice(entryBB.end(), dtorBlock.getOperations(),
483 std::prev(dtorBlock.end()));
486 builder.setInsertionPointToEnd(&entryBB);
492 void emitCXXGuardedInitIf(CIRBaseBuilderTy &builder, cir::GlobalOp globalOp,
493 mlir::Region &ctorRegion, mlir::Region &dtorRegion,
494 bool isLocalVarDecl, mlir::Value guardPtr,
495 cir::PointerType guardPtrTy,
bool threadsafe) {
496 auto loc = globalOp->getLoc();
519 mlir::Block *insertBlock = builder.getInsertionBlock();
520 if (!ctorRegion.empty()) {
521 assert(ctorRegion.hasOneBlock() &&
"Enforced by MaxSizedRegion<1>");
523 mlir::Block &block = ctorRegion.front();
524 insertBlock->getOperations().splice(
525 insertBlock->end(), block.getOperations(), block.begin(),
526 std::prev(block.end()));
529 if (!dtorRegion.empty()) {
530 assert(dtorRegion.hasOneBlock() &&
"Enforced by MaxSizedRegion<1>");
536 emitGlobalGuardedDtorRegion(builder, globalOp, dtorRegion,
537 globalOp.getTlsModel().has_value(),
540 builder.setInsertionPointToEnd(insertBlock);
541 ctorRegion.getBlocks().clear();
549 mlir::Value acquireResult = acquireCall.getResult();
552 loc, mlir::cast<cir::IntType>(acquireResult.getType()), 0);
553 auto shouldInit = builder.
createCompare(loc, cir::CmpOpKind::ne,
554 acquireResult, acquireZero);
559 cir::IfOp::create(builder, loc, shouldInit,
false,
560 [](mlir::OpBuilder &, mlir::Location) {});
561 mlir::OpBuilder::InsertionGuard insertGuard(builder);
562 builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
574 if (getLangOpts().Exceptions) {
575 cir::CleanupScopeOp::create(
576 builder, loc, cir::CleanupKind::EH,
577 [&](mlir::OpBuilder &, mlir::Location bodyLoc) {
581 [&](mlir::OpBuilder &, mlir::Location cleanupLoc) {
582 cir::CallOp abortCall =
584 mlir::ValueRange{guardPtr});
588 abortCall.setNothrowAttr(builder.getUnitAttr());
591 builder.setInsertionPointToEnd(&ifOp.getThenRegion().front());
598 mlir::ValueRange{guardPtr});
601 }
else if (!isLocalVarDecl) {
606 guardPtr, cir::PointerType::get(builder.
getSIntNTy(8)));
617 guardPtr, cir::PointerType::get(builder.
getSIntNTy(8)));
629cir::GlobalOp LoweringPreparePass::getOrCreateRuntimeVariable(
630 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
631 mlir::Type type, cir::GlobalLinkageKind linkage,
632 cir::VisibilityKind visibility) {
633 cir::GlobalOp g = dyn_cast_or_null<cir::GlobalOp>(
634 mlir::SymbolTable::lookupNearestSymbolFrom(
635 mlirModule, mlir::StringAttr::get(mlirModule->getContext(), name)));
637 g = cir::GlobalOp::create(builder, loc, name, type);
639 cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
640 mlir::SymbolTable::setSymbolVisibility(
641 g, mlir::SymbolTable::Visibility::Private);
642 g.setGlobalVisibility(visibility);
647cir::FuncOp LoweringPreparePass::buildRuntimeFunction(
648 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
649 cir::FuncType type, cir::GlobalLinkageKind linkage) {
650 cir::FuncOp f = dyn_cast_or_null<FuncOp>(SymbolTable::lookupNearestSymbolFrom(
651 mlirModule, StringAttr::get(mlirModule->getContext(), name)));
653 f = cir::FuncOp::create(builder, loc, name, type);
655 cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
656 mlir::SymbolTable::setSymbolVisibility(
657 f, mlir::SymbolTable::Visibility::Private);
667 builder.setInsertionPoint(op);
669 mlir::Value src = op.getSrc();
670 mlir::Value imag = builder.
getNullValue(src.getType(), op.getLoc());
676 cir::CastKind elemToBoolKind) {
678 builder.setInsertionPoint(op);
680 mlir::Value src = op.getSrc();
681 if (!mlir::isa<cir::BoolType>(op.getType()))
688 cir::BoolType boolTy = builder.
getBoolTy();
689 mlir::Value srcRealToBool =
690 builder.
createCast(op.getLoc(), elemToBoolKind, srcReal, boolTy);
691 mlir::Value srcImagToBool =
692 builder.
createCast(op.getLoc(), elemToBoolKind, srcImag, boolTy);
693 return builder.
createLogicalOr(op.getLoc(), srcRealToBool, srcImagToBool);
698 cir::CastKind scalarCastKind) {
700 builder.setInsertionPoint(op);
702 mlir::Value src = op.getSrc();
703 auto dstComplexElemTy =
704 mlir::cast<cir::ComplexType>(op.getType()).getElementType();
709 mlir::Value dstReal = builder.
createCast(op.getLoc(), scalarCastKind, srcReal,
711 mlir::Value dstImag = builder.
createCast(op.getLoc(), scalarCastKind, srcImag,
716void LoweringPreparePass::lowerCastOp(cir::CastOp op) {
717 mlir::MLIRContext &ctx = getContext();
718 mlir::Value loweredValue = [&]() -> mlir::Value {
719 switch (op.getKind()) {
720 case cir::CastKind::float_to_complex:
721 case cir::CastKind::int_to_complex:
723 case cir::CastKind::float_complex_to_real:
724 case cir::CastKind::int_complex_to_real:
726 case cir::CastKind::float_complex_to_bool:
728 case cir::CastKind::int_complex_to_bool:
730 case cir::CastKind::float_complex:
732 case cir::CastKind::float_complex_to_int_complex:
734 case cir::CastKind::int_complex:
736 case cir::CastKind::int_complex_to_float_complex:
744 op.replaceAllUsesWith(loweredValue);
751 llvm::StringRef (*libFuncNameGetter)(llvm::APFloat::Semantics),
752 mlir::Location loc, cir::ComplexType ty, mlir::Value lhsReal,
753 mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag) {
754 cir::FPTypeInterface elementTy =
755 mlir::cast<cir::FPTypeInterface>(ty.getElementType());
757 llvm::StringRef libFuncName = libFuncNameGetter(
758 llvm::APFloat::SemanticsToEnum(elementTy.getFloatSemantics()));
761 cir::FuncType libFuncTy = cir::FuncType::get(libFuncInputTypes, ty);
767 mlir::OpBuilder::InsertionGuard ipGuard{builder};
768 builder.setInsertionPointToStart(pass.mlirModule.getBody());
769 libFunc = pass.buildRuntimeFunction(builder, libFuncName, loc, libFuncTy);
775 builder.
createCallOp(loc, libFunc, {lhsReal, lhsImag, rhsReal, rhsImag});
776 return call.getResult();
779static llvm::StringRef
782 case llvm::APFloat::S_IEEEhalf:
784 case llvm::APFloat::S_IEEEsingle:
786 case llvm::APFloat::S_IEEEdouble:
788 case llvm::APFloat::S_PPCDoubleDouble:
790 case llvm::APFloat::S_x87DoubleExtended:
792 case llvm::APFloat::S_IEEEquad:
795 llvm_unreachable(
"unsupported floating point type");
801 mlir::Value lhsReal, mlir::Value lhsImag,
802 mlir::Value rhsReal, mlir::Value rhsImag) {
804 mlir::Value &a = lhsReal;
805 mlir::Value &b = lhsImag;
806 mlir::Value &c = rhsReal;
807 mlir::Value &d = rhsImag;
811 bool isFP = cir::isFPOrVectorOfFPType(a.getType());
812 auto mul = [&](mlir::Location l, mlir::Value x, mlir::Value y) {
815 auto add = [&](mlir::Location l, mlir::Value x, mlir::Value y) {
818 auto sub = [&](mlir::Location l, mlir::Value x, mlir::Value y) {
821 auto div = [&](mlir::Location l, mlir::Value x, mlir::Value y) {
825 mlir::Value ac = mul(loc, a, c);
826 mlir::Value bd = mul(loc, b, d);
827 mlir::Value cc = mul(loc, c, c);
828 mlir::Value dd = mul(loc, d, d);
829 mlir::Value acbd = add(loc, ac, bd);
830 mlir::Value ccdd = add(loc, cc, dd);
831 mlir::Value resultReal = div(loc, acbd, ccdd);
833 mlir::Value bc = mul(loc, b, c);
834 mlir::Value ad = mul(loc, a, d);
835 mlir::Value bcad = sub(loc, bc, ad);
836 mlir::Value resultImag = div(loc, bcad, ccdd);
842 mlir::Value lhsReal, mlir::Value lhsImag,
843 mlir::Value rhsReal, mlir::Value rhsImag) {
864 mlir::Value &a = lhsReal;
865 mlir::Value &b = lhsImag;
866 mlir::Value &c = rhsReal;
867 mlir::Value &d = rhsImag;
870 assert(cir::isFPOrVectorOfFPType(a.getType()) &&
871 "range-reduction complex divide expects floating-point operands");
873 auto trueBranchBuilder = [&](mlir::OpBuilder &, mlir::Location) {
874 mlir::Value r = builder.
createFDiv(loc, d, c);
875 mlir::Value rd = builder.
createFMul(loc, r, d);
876 mlir::Value tmp = builder.
createFAdd(loc, c, rd);
878 mlir::Value br = builder.
createFMul(loc, b, r);
879 mlir::Value abr = builder.
createFAdd(loc, a, br);
880 mlir::Value e = builder.
createFDiv(loc, abr, tmp);
882 mlir::Value ar = builder.
createFMul(loc, a, r);
883 mlir::Value bar = builder.
createFSub(loc, b, ar);
884 mlir::Value f = builder.
createFDiv(loc, bar, tmp);
890 auto falseBranchBuilder = [&](mlir::OpBuilder &, mlir::Location) {
891 mlir::Value r = builder.
createFDiv(loc, c, d);
892 mlir::Value rc = builder.
createFMul(loc, r, c);
893 mlir::Value tmp = builder.
createFAdd(loc, d, rc);
895 mlir::Value ar = builder.
createFMul(loc, a, r);
896 mlir::Value arb = builder.
createFAdd(loc, ar, b);
897 mlir::Value e = builder.
createFDiv(loc, arb, tmp);
899 mlir::Value br = builder.
createFMul(loc, b, r);
900 mlir::Value bra = builder.
createFSub(loc, br, a);
901 mlir::Value f = builder.
createFDiv(loc, bra, tmp);
907 auto cFabs = cir::FAbsOp::create(builder, loc, c);
908 auto dFabs = cir::FAbsOp::create(builder, loc, d);
909 cir::CmpOp cmpResult =
910 builder.
createCompare(loc, cir::CmpOpKind::ge, cFabs, dFabs);
911 auto ternary = cir::TernaryOp::create(builder, loc, cmpResult,
912 trueBranchBuilder, falseBranchBuilder);
914 return ternary.getResult();
920 mlir::Type elementType) {
922 auto getHigherPrecisionFPType = [&context](mlir::Type type) -> mlir::Type {
923 if (mlir::isa<cir::FP16Type>(type))
924 return cir::SingleType::get(&context);
926 if (mlir::isa<cir::SingleType>(type) || mlir::isa<cir::BF16Type>(type))
927 return cir::DoubleType::get(&context);
929 if (mlir::isa<cir::DoubleType>(type))
930 return cir::LongDoubleType::get(&context, type);
935 auto getFloatTypeSemantics =
936 [&langOpts, &targetInfo](mlir::Type type) ->
const llvm::fltSemantics & {
938 if (mlir::isa<cir::FP16Type>(type))
939 return info.getHalfFormat();
941 if (mlir::isa<cir::BF16Type>(type))
942 return info.getBFloat16Format();
944 if (mlir::isa<cir::SingleType>(type))
945 return info.getFloatFormat();
947 if (mlir::isa<cir::DoubleType>(type))
948 return info.getDoubleFormat();
950 if (mlir::isa<cir::LongDoubleType>(type)) {
951 if (langOpts.OpenMP && langOpts.OpenMPIsTargetDevice)
952 llvm_unreachable(
"NYI Float type semantics with OpenMP");
953 return info.getLongDoubleFormat();
956 if (mlir::isa<cir::FP128Type>(type)) {
957 if (langOpts.OpenMP && langOpts.OpenMPIsTargetDevice)
958 llvm_unreachable(
"NYI Float type semantics with OpenMP");
959 return info.getFloat128Format();
962 llvm_unreachable(
"Unsupported float type semantics");
965 const mlir::Type higherElementType = getHigherPrecisionFPType(elementType);
966 const llvm::fltSemantics &elementTypeSemantics =
967 getFloatTypeSemantics(elementType);
968 const llvm::fltSemantics &higherElementTypeSemantics =
969 getFloatTypeSemantics(higherElementType);
978 if (llvm::APFloat::semanticsMaxExponent(elementTypeSemantics) * 2 + 1 <=
979 llvm::APFloat::semanticsMaxExponent(higherElementTypeSemantics)) {
980 return higherElementType;
990 mlir::Location loc, cir::ComplexFDivOp op,
991 mlir::Value lhsReal, mlir::Value lhsImag,
992 mlir::Value rhsReal, mlir::Value rhsImag,
993 mlir::MLIRContext &mlirCx,
995 cir::ComplexType complexTy = op.getType();
996 cir::ComplexRangeKind range = op.getRange();
998 case ComplexRangeKind::Full: {
1000 loc, complexTy, lhsReal, lhsImag, rhsReal,
1003 case ComplexRangeKind::Improved: {
1007 case ComplexRangeKind::Promoted: {
1008 mlir::Type originalElementType = complexTy.getElementType();
1009 mlir::Type higherPrecisionElementType =
1011 mlirCx, targetInfo, pass.getLangOpts(), builder,
1012 originalElementType);
1014 if (!higherPrecisionElementType)
1018 cir::CastKind floatingCastKind = cir::CastKind::floating;
1019 lhsReal = builder.
createCast(floatingCastKind, lhsReal,
1020 higherPrecisionElementType);
1021 lhsImag = builder.
createCast(floatingCastKind, lhsImag,
1022 higherPrecisionElementType);
1023 rhsReal = builder.
createCast(floatingCastKind, rhsReal,
1024 higherPrecisionElementType);
1025 rhsImag = builder.
createCast(floatingCastKind, rhsImag,
1026 higherPrecisionElementType);
1029 builder, loc, lhsReal, lhsImag, rhsReal, rhsImag);
1034 mlir::Value finalReal =
1035 builder.
createCast(floatingCastKind, resultReal, originalElementType);
1036 mlir::Value finalImag =
1037 builder.
createCast(floatingCastKind, resultImag, originalElementType);
1040 case ComplexRangeKind::Basic: {
1047void LoweringPreparePass::lowerComplexFDivOp(cir::ComplexFDivOp op) {
1048 cir::CIRBaseBuilderTy builder(getContext());
1049 builder.setInsertionPointAfter(op);
1050 mlir::Location loc = op.getLoc();
1051 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
1052 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
1058 mlir::Value loweredResult =
1060 rhsImag, getContext(), getTargetInfo());
1061 op.replaceAllUsesWith(loweredResult);
1065void LoweringPreparePass::lowerComplexDivOp(cir::ComplexDivOp op) {
1066 cir::CIRBaseBuilderTy builder(getContext());
1067 builder.setInsertionPointAfter(op);
1068 mlir::Location loc = op.getLoc();
1069 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
1070 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
1077 builder, loc, lhsReal, lhsImag, rhsReal, rhsImag);
1078 op.replaceAllUsesWith(loweredResult);
1082static llvm::StringRef
1084 switch (semantics) {
1085 case llvm::APFloat::S_IEEEhalf:
1087 case llvm::APFloat::S_IEEEsingle:
1089 case llvm::APFloat::S_IEEEdouble:
1091 case llvm::APFloat::S_PPCDoubleDouble:
1093 case llvm::APFloat::S_x87DoubleExtended:
1095 case llvm::APFloat::S_IEEEquad:
1098 llvm_unreachable(
"unsupported floating point type");
1104 mlir::Location loc, cir::ComplexFMulOp op,
1105 mlir::Value lhsReal, mlir::Value lhsImag,
1106 mlir::Value rhsReal, mlir::Value rhsImag) {
1108 mlir::Value resultRealLhs = builder.
createFMul(loc, lhsReal, rhsReal);
1109 mlir::Value resultRealRhs = builder.
createFMul(loc, lhsImag, rhsImag);
1110 mlir::Value resultImagLhs = builder.
createFMul(loc, lhsReal, rhsImag);
1111 mlir::Value resultImagRhs = builder.
createFMul(loc, lhsImag, rhsReal);
1112 mlir::Value resultReal =
1113 builder.
createFSub(loc, resultRealLhs, resultRealRhs);
1114 mlir::Value resultImag =
1115 builder.
createFAdd(loc, resultImagLhs, resultImagRhs);
1116 mlir::Value algebraicResult =
1119 cir::ComplexType complexTy = op.getType();
1120 cir::ComplexRangeKind rangeKind = op.getRange();
1121 if (rangeKind == cir::ComplexRangeKind::Basic ||
1122 rangeKind == cir::ComplexRangeKind::Improved ||
1123 rangeKind == cir::ComplexRangeKind::Promoted)
1124 return algebraicResult;
1131 mlir::Value resultRealIsNaN = builder.
createIsNaN(loc, resultReal);
1132 mlir::Value resultImagIsNaN = builder.
createIsNaN(loc, resultImag);
1133 mlir::Value resultRealAndImagAreNaN =
1136 return cir::TernaryOp::create(
1137 builder, loc, resultRealAndImagAreNaN,
1138 [&](mlir::OpBuilder &, mlir::Location) {
1141 lhsReal, lhsImag, rhsReal, rhsImag);
1144 [&](mlir::OpBuilder &, mlir::Location) {
1150void LoweringPreparePass::lowerComplexFMulOp(cir::ComplexFMulOp op) {
1151 cir::CIRBaseBuilderTy builder(getContext());
1152 builder.setInsertionPointAfter(op);
1153 mlir::Location loc = op.getLoc();
1154 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
1155 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
1162 mlir::Value loweredResult =
lowerComplexFMul(*
this, builder, loc, op, lhsReal,
1163 lhsImag, rhsReal, rhsImag);
1164 op.replaceAllUsesWith(loweredResult);
1168void LoweringPreparePass::lowerComplexMulOp(cir::ComplexMulOp op) {
1169 cir::CIRBaseBuilderTy builder(getContext());
1170 builder.setInsertionPointAfter(op);
1171 mlir::Location loc = op.getLoc();
1172 mlir::TypedValue<cir::ComplexType> lhs = op.getLhs();
1173 mlir::TypedValue<cir::ComplexType> rhs = op.getRhs();
1179 mlir::Value resultRealLhs = builder.
createMul(loc, lhsReal, rhsReal);
1180 mlir::Value resultRealRhs = builder.
createMul(loc, lhsImag, rhsImag);
1181 mlir::Value resultImagLhs = builder.
createMul(loc, lhsReal, rhsImag);
1182 mlir::Value resultImagRhs = builder.
createMul(loc, lhsImag, rhsReal);
1183 mlir::Value resultReal = builder.
createSub(loc, resultRealLhs, resultRealRhs);
1184 mlir::Value resultImag = builder.
createAdd(loc, resultImagLhs, resultImagRhs);
1186 mlir::Value loweredResult =
1189 op.replaceAllUsesWith(loweredResult);
1193void LoweringPreparePass::lowerComplexConjOp(cir::ComplexConjOp op) {
1194 mlir::Location loc = op.getLoc();
1195 CIRBaseBuilderTy builder(getContext());
1196 builder.setInsertionPointAfter(op);
1198 mlir::Value operand = op.getOperand();
1203 const bool isFP = cir::isFPOrVectorOfFPType(operandReal.getType());
1204 mlir::Value resultImag = isFP ? builder.
createFNeg(loc, operandImag)
1207 mlir::Value result =
1209 op->replaceAllUsesWith(mlir::ValueRange{result});
1214LoweringPreparePass::buildGlobalArrayDtorFunc(CIRBaseBuilderTy &builder,
1215 mlir::Operation *op) {
1216 mlir::OpBuilder::InsertionGuard guard(builder);
1217 builder.setInsertionPointAfter(op);
1218 SmallString<256> fnName(
"__cxx_global_array_dtor");
1219 uint32_t cnt = dynamicInitializerNames[fnName]++;
1221 fnName +=
"." + std::to_string(cnt);
1225 cir::FuncOp dtorFunc =
1226 buildRuntimeFunction(builder, fnName, op->getLoc(), fnType,
1227 cir::GlobalLinkageKind::InternalLinkage);
1229 SmallVector<mlir::NamedAttribute> paramAttrs;
1230 paramAttrs.push_back(
1231 builder.getNamedAttr(
"llvm.noundef", builder.getUnitAttr()));
1232 SmallVector<mlir::Attribute> argAttrDicts;
1233 argAttrDicts.push_back(
1234 mlir::DictionaryAttr::get(builder.getContext(), paramAttrs));
1235 dtorFunc.setArgAttrsAttr(
1236 mlir::ArrayAttr::get(builder.getContext(), argAttrDicts));
1238 dtorFunc.addEntryBlock();
1242void LoweringPreparePass::lowerRegisterExitDtorOp(cir::RegisterExitDtorOp op) {
1243 CIRBaseBuilderTy builder(getContext());
1244 mlir::Location loc = op.getLoc();
1245 auto object = symbolTables.lookupNearestSymbolFrom<cir::GlobalOp>(
1246 op, op.getObjectAttr());
1247 assert(
object &&
"register_exit_dtor must reference a cir.global");
1248 mlir::Block &body = op.getBody().front();
1249 builder.setInsertionPoint(op);
1253 cir::FuncOp dtorFunc;
1255 if (body.getOperations().size() == 3) {
1256 auto getGlobal = mlir::dyn_cast<cir::GetGlobalOp>(body.front());
1257 auto call = mlir::dyn_cast<cir::CallOp>(*std::next(body.begin()));
1258 if (getGlobal && call && getGlobal.getName() == op.getObject() &&
1259 call.getNumArgOperands() == 1 &&
1260 call.getArgOperand(0) == getGlobal.getResult()) {
1261 dtorFunc = getCalledFunction(call);
1263 arg = builder.clone(*getGlobal)->getResult(0);
1270 dtorFunc = buildGlobalArrayDtorFunc(builder,
object);
1271 mlir::Block *entryBB = &dtorFunc.getBody().front();
1272 entryBB->getOperations().splice(entryBB->end(), body.getOperations());
1273 auto yieldOp = mlir::cast<cir::YieldOp>(entryBB->getTerminator());
1275 mlir::OpBuilder::InsertionGuard guard(builder);
1276 builder.setInsertionPoint(yieldOp);
1277 cir::ReturnOp::create(builder, yieldOp.getLoc());
1283 cir::CallOp atExitCall = emitAtExitCall(builder, loc, dtorFunc, arg,
1284 object.getTlsModel().has_value());
1287 atExitCall.setNothrowAttr(builder.getUnitAttr());
1291cir::FuncOp LoweringPreparePass::getOrCreateDtorFunc(CIRBaseBuilderTy &builder,
1293 mlir::Region &dtorRegion,
1294 cir::CallOp &dtorCall) {
1295 mlir::OpBuilder::InsertionGuard guard(builder);
1299 mlir::Block &dtorBlock = dtorRegion.front();
1303 auto opIt = dtorBlock.getOperations().begin();
1304 cir::GetGlobalOp ggop = mlir::cast<cir::GetGlobalOp>(*opIt);
1315 if (dtorBlock.getOperations().size() == 3) {
1316 auto callOp = mlir::dyn_cast<cir::CallOp>(&*(++opIt));
1317 auto yieldOp = mlir::dyn_cast<cir::YieldOp>(&*(++opIt));
1318 if (yieldOp && callOp && callOp.getNumOperands() == 1 &&
1319 callOp.getArgOperand(0) == ggop) {
1321 return getCalledFunction(callOp);
1326 cir::FuncOp dtorFunc = buildGlobalArrayDtorFunc(builder, op);
1327 mlir::Block *entryBB = &dtorFunc.getBody().front();
1330 entryBB->getOperations().splice(entryBB->begin(), dtorBlock.getOperations(),
1331 dtorBlock.begin(), dtorBlock.end());
1334 cir::GetGlobalOp dtorGGop =
1335 mlir::cast<cir::GetGlobalOp>(entryBB->getOperations().front());
1336 builder.setInsertionPointToStart(&dtorBlock);
1337 builder.clone(*dtorGGop.getOperation());
1341 mlir::Value dtorArg = entryBB->getArgument(0);
1344 if (dtorArg.getType() != dtorGGop.getType()) {
1345 builder.setInsertionPointToStart(entryBB);
1347 builder.
createBitcast(dtorGGop.getLoc(), dtorArg, dtorGGop.getType());
1349 dtorGGop.replaceAllUsesWith(dtorArg);
1353 mlir::Block &finalBlock = dtorFunc.getBody().back();
1354 auto yieldOp = cast<cir::YieldOp>(finalBlock.getTerminator());
1355 builder.setInsertionPoint(yieldOp);
1356 cir::ReturnOp::create(builder, yieldOp->getLoc());
1361 cir::GetGlobalOp origGGop =
1362 mlir::cast<cir::GetGlobalOp>(dtorBlock.getOperations().front());
1363 builder.setInsertionPointAfter(origGGop);
1364 mlir::Value ggopResult = origGGop.getResult();
1365 dtorCall = builder.
createCallOp(op.getLoc(), dtorFunc, ggopResult,
1367 {}, dtorFunc.getCallingConv());
1370 auto finalYield = cir::YieldOp::create(builder, op.getLoc());
1373 dtorBlock.getOperations().erase(std::next(mlir::Block::iterator(finalYield)),
1375 dtorRegion.getBlocks().erase(std::next(dtorRegion.begin()), dtorRegion.end());
1381LoweringPreparePass::buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op) {
1384 SmallString<256> fnName(
"__cxx_global_var_init");
1386 uint32_t cnt = dynamicInitializerNames[fnName]++;
1388 fnName +=
"." + std::to_string(cnt);
1391 CIRBaseBuilderTy builder(getContext());
1392 builder.setInsertionPointAfter(op);
1393 cir::VoidType voidTy = builder.
getVoidTy();
1394 auto fnType = cir::FuncType::get({}, voidTy);
1395 FuncOp f = buildRuntimeFunction(builder, fnName, op.getLoc(), fnType,
1396 cir::GlobalLinkageKind::InternalLinkage);
1401 if (op.getStrictfp()) {
1402 f->setAttr(cir::CIRDialect::getStrictFPAttrName(),
1403 mlir::UnitAttr::get(&getContext()));
1404 op.setStrictfp(
false);
1413 mlir::Block *entryBB = f.addEntryBlock();
1414 builder.setInsertionPointToStart(entryBB);
1418 bool needsTlsGuard = op.getTlsRefs() && op.getTlsRefs()->getGuardName();
1422 if (!needsTlsGuard && op.getDynamicInitGuard()) {
1423 if (!op.getDynamicInitInfo()) {
1425 "guarded global with a guard is missing 'dynamic_init_info'");
1429 if (op.getDynamicInitInfo()->getLocal()) {
1430 op->emitError(
"guarded global is marked local");
1433 emitGuardedInit(builder, op, op.getCtorRegion(), op.getDtorRegion());
1434 builder.setInsertionPointToEnd(entryBB);
1435 cir::ReturnOp::create(builder, op.getLoc());
1440 if (needsTlsGuard) {
1441 guardIf = buildInitGuardCheck(
1442 builder, op.getLoc(),
1443 getOrCreateStaticLocalDeclGuardAddress(
1444 builder, op, op.getTlsRefs()->getGuardName().getValue(),
1446 op.hasInternalLinkage()),
1448 builder.setInsertionPointToEnd(&guardIf.getThenRegion().front());
1451 if (!op.getCtorRegion().empty()) {
1452 mlir::Block &block = op.getCtorRegion().front();
1453 mlir::Block *insertBlock = builder.getBlock();
1454 insertBlock->getOperations().splice(insertBlock->end(),
1455 block.getOperations(), block.begin(),
1456 std::prev(block.end()));
1460 mlir::Region &dtorRegion = op.getDtorRegion();
1461 if (!dtorRegion.empty()) {
1464 emitGlobalGuardedDtorRegion(builder, op, dtorRegion,
1465 op.getTlsModel().has_value(),
1466 *builder.getBlock());
1470 if (needsTlsGuard) {
1471 builder.setInsertionPointToEnd(&guardIf.getThenRegion().back());
1472 cir::YieldOp::create(builder, op.getLoc());
1476 builder.setInsertionPointToEnd(entryBB);
1477 mlir::Operation *yieldOp =
nullptr;
1478 if (!op.getCtorRegion().empty()) {
1479 mlir::Block &block = op.getCtorRegion().front();
1480 yieldOp = &block.getOperations().back();
1482 assert(!dtorRegion.empty());
1483 mlir::Block &block = dtorRegion.front();
1484 yieldOp = &block.getOperations().back();
1487 assert(isa<cir::YieldOp>(*yieldOp));
1488 cir::ReturnOp::create(builder, yieldOp->getLoc());
1493LoweringPreparePass::getGuardAcquireFn(cir::PointerType guardPtrTy) {
1495 CIRBaseBuilderTy builder(getContext());
1496 mlir::OpBuilder::InsertionGuard ipGuard{builder};
1497 builder.setInsertionPointToStart(mlirModule.getBody());
1498 mlir::Location loc = mlirModule.getLoc();
1499 cir::IntType intTy = cir::IntType::get(&getContext(), 32,
true);
1500 auto fnType = cir::FuncType::get({guardPtrTy}, intTy);
1501 return buildRuntimeFunction(builder,
"__cxa_guard_acquire", loc, fnType);
1505LoweringPreparePass::getGuardReleaseFn(cir::PointerType guardPtrTy) {
1507 CIRBaseBuilderTy builder(getContext());
1508 mlir::OpBuilder::InsertionGuard ipGuard{builder};
1509 builder.setInsertionPointToStart(mlirModule.getBody());
1510 mlir::Location loc = mlirModule.getLoc();
1511 cir::VoidType voidTy = cir::VoidType::get(&getContext());
1512 auto fnType = cir::FuncType::get({guardPtrTy}, voidTy);
1513 return buildRuntimeFunction(builder,
"__cxa_guard_release", loc, fnType);
1516cir::FuncOp LoweringPreparePass::getGuardAbortFn(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::VoidType voidTy = cir::VoidType::get(&getContext());
1523 auto fnType = cir::FuncType::get({guardPtrTy}, voidTy);
1524 return buildRuntimeFunction(builder,
"__cxa_guard_abort", loc, fnType);
1527cir::FuncOp LoweringPreparePass::getTlsInitFn() {
1529 CIRBaseBuilderTy builder(getContext());
1530 mlir::OpBuilder::InsertionGuard _{builder};
1531 builder.setInsertionPointToStart(mlirModule.getBody());
1532 mlir::Location loc = mlirModule.getLoc();
1534 return buildRuntimeFunction(builder,
"__tls_init", loc, fnType,
1535 cir::GlobalLinkageKind::InternalLinkage);
1538cir::GlobalOp LoweringPreparePass::createGuardGlobalOp(
1539 CIRBaseBuilderTy &builder, mlir::Location loc, llvm::StringRef name,
1540 cir::IntType guardTy, cir::GlobalLinkageKind linkage) {
1541 mlir::OpBuilder::InsertionGuard guard(builder);
1542 builder.setInsertionPointToStart(mlirModule.getBody());
1543 cir::GlobalOp g = cir::GlobalOp::create(builder, loc, name, guardTy);
1545 cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
1546 mlir::SymbolTable::setSymbolVisibility(
1547 g, mlir::SymbolTable::Visibility::Private);
1551void LoweringPreparePass::addUsedGlobal(cir::GlobalOp global) {
1552 CIRBaseBuilderTy builder(getContext());
1553 mlir::Attribute entry = cir::GlobalViewAttr::get(
1555 mlir::FlatSymbolRefAttr::get(global.getSymNameAttr()));
1557 mlir::StringAttr usedName = builder.getStringAttr(
"llvm.used");
1558 cir::GlobalOp used =
1559 symbolTables.lookupSymbolIn<cir::GlobalOp>(mlirModule, usedName);
1561 llvm::SmallVector<mlir::Attribute, 4> elements;
1563 auto existing = mlir::cast<cir::ConstArrayAttr>(*used.getInitialValue());
1564 llvm::append_range(elements,
1565 mlir::cast<mlir::ArrayAttr>(existing.getElts()));
1567 elements.push_back(entry);
1569 cir::ArrayType arrayTy =
1570 cir::ArrayType::get(builder.
getVoidPtrTy(), elements.size());
1571 cir::ConstArrayAttr initAttr = cir::ConstArrayAttr::get(
1572 arrayTy, mlir::ArrayAttr::get(&getContext(), elements));
1575 used.setSymType(arrayTy);
1576 used.setInitialValueAttr(initAttr);
1580 builder.setInsertionPointToStart(mlirModule.getBody());
1581 used = cir::GlobalOp::create(builder, mlirModule.getLoc(),
1582 usedName.getValue(), arrayTy);
1583 used.setLinkage(cir::GlobalLinkageKind::AppendingLinkage);
1584 used.setInitialValueAttr(initAttr);
1585 used.setSectionAttr(builder.getStringAttr(
"llvm.metadata"));
1586 symbolTables.getSymbolTable(mlirModule).insert(used);
1589void LoweringPreparePass::handleStaticLocal(cir::GlobalOp globalOp,
1590 cir::LocalInitOp localInitOp) {
1591 CIRBaseBuilderTy builder(getContext());
1593 builder.setInsertionPointAfter(localInitOp);
1594 mlir::Block *localInitBlock = builder.getInsertionBlock();
1597 mlir::Operation *ret = localInitBlock->getTerminator();
1601 builder.setInsertionPointAfter(localInitOp);
1603 emitGuardedInit(builder, globalOp, localInitOp.getCtorRegion(),
1604 localInitOp.getDtorRegion());
1607 builder.getInsertionBlock()->push_back(ret);
1610void LoweringPreparePass::emitGuardedInit(CIRBaseBuilderTy &builder,
1611 cir::GlobalOp globalOp,
1612 mlir::Region &ctorRegion,
1613 mlir::Region &dtorRegion) {
1617 std::optional<cir::DynamicInitInfoAttr> infoOption =
1618 globalOp.getDynamicInitInfo();
1623 if (!infoOption.has_value()) {
1624 globalOp->emitError(
1625 "dynamic-init-guarded global is missing 'dynamic_init_info'");
1629 cir::DynamicInitInfoAttr
info = infoOption.value();
1633 bool nonTemplateInline =
1634 info.getIsInline() && !
info.isTemplateInstantiation();
1639 bool threadsafe = getLangOpts().ThreadsafeStatics &&
1640 (
info.getLocal() || nonTemplateInline) &&
1641 info.getTls() == cir::TLSKind::None;
1645 bool useInt8GuardVariable = !threadsafe && globalOp.hasInternalLinkage();
1648 cir::GlobalOp guard = getOrCreateStaticLocalDeclGuardAddress(
1649 builder, globalOp, globalOp.getDynamicInitGuard()->getName().getValue(),
1650 info.getLocal(), useInt8GuardVariable);
1655 mlir::Value guardPtr =
1678 unsigned maxInlineWidthInBits = getTargetInfo().getMaxAtomicInlineWidth();
1680 if (!threadsafe || maxInlineWidthInBits) {
1682 auto bytePtrTy = cir::PointerType::get(builder.
getSIntNTy(8));
1683 mlir::Value bytePtr = builder.
createBitcast(guardPtr, bytePtrTy);
1685 globalOp.getLoc(), bytePtr, *guard.getAlignment());
1694 auto loadOp = mlir::cast<cir::LoadOp>(guardLoad.getDefiningOp());
1695 loadOp.setMemOrder(cir::MemOrder::Acquire);
1696 loadOp.setSyncScope(cir::SyncScopeKind::System);
1719 if (useARMGuardVarABI() && !useInt8GuardVariable) {
1721 globalOp.getLoc(), mlir::cast<cir::IntType>(guardLoad.getType()), 1);
1722 guardLoad = builder.
createAnd(globalOp.getLoc(), guardLoad, one);
1727 globalOp.getLoc(), mlir::cast<cir::IntType>(guardLoad.getType()), 0);
1729 cir::CmpOpKind::eq, guardLoad, zero);
1733 builder, globalOp.getLoc(), needsInit,
1734 false, [&](mlir::OpBuilder &, mlir::Location) {
1735 emitCXXGuardedInitIf(
1736 builder, globalOp, ctorRegion, dtorRegion, info.getLocal(),
1737 guardPtr, builder.getPointerTo(guard.getSymType()), threadsafe);
1742 globalOp->emitError(
"NYI: guarded init without inline atomics support");
1747void LoweringPreparePass::lowerLocalInitOp(cir::LocalInitOp initOp) {
1750 if (initOp.getCtorRegion().empty() && initOp.getDtorRegion().empty()) {
1755 cir::GlobalOp globalOp = initOp.getReferencedGlobal(symbolTables);
1756 assert(globalOp &&
"No global-op found");
1758 handleStaticLocal(globalOp, initOp);
1768 return targetInfo.
getTriple().isOSDarwin();
1771static cir::GlobalLinkageKind
1774 return op.getLinkage();
1779 return op.getLinkage();
1783 if (op.isDeclaration())
1784 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
1785 return cir::GlobalLinkageKind::WeakODRLinkage;
1789LoweringPreparePass::getOrCreateThreadLocalWrapper(CIRBaseBuilderTy &builder,
1791 mlir::OpBuilder::InsertionGuard insertGuard(builder);
1792 builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
1794 mlir::StringAttr wrapperName = op.getTlsRefs()->getWrapperName();
1796 auto existingWrapperIter = threadLocalWrappers.find(wrapperName.getValue());
1797 if (existingWrapperIter != threadLocalWrappers.end())
1798 return existingWrapperIter->second;
1801 auto funcType = cir::FuncType::get({}, builder.
getPointerTo(op.getSymType()));
1803 cir::FuncOp::create(builder, op.getLoc(), wrapperName, funcType);
1805 cir::GlobalLinkageKind linkageKind =
1807 func.setLinkageAttr(
1808 cir::GlobalLinkageKindAttr::get(&getContext(), linkageKind));
1810 if (getTargetInfo().
getTriple().supportsCOMDAT() && func.isWeakForLinker())
1811 func.setSelfComdat();
1813 mlir::SymbolTable::setSymbolVisibility(
1814 func, mlir::SymbolTable::Visibility::Private);
1819 op.getGlobalVisibility() == cir::VisibilityKind::Hidden)
1820 func.setGlobalVisibility(cir::VisibilityKind::Hidden);
1823 op->emitError(
"Unhandled thread wrapper attributes for CC and Nounwind");
1825 threadLocalWrappers.insert({wrapperName.getValue(), func});
1829void LoweringPreparePass::defineGlobalThreadLocalWrapper(cir::GlobalOp op,
1830 cir::FuncOp initAlias,
1831 bool isVarDefinition) {
1832 CIRBaseBuilderTy builder(getContext());
1833 cir::FuncOp wrapper = getOrCreateThreadLocalWrapper(builder, op);
1834 mlir::Block *entryBB = wrapper.addEntryBlock();
1835 builder.setInsertionPointToStart(entryBB);
1839 mlir::Location aliasLoc = initAlias.getLoc();
1840 if (!isVarDefinition) {
1842 mlir::Value funcLoad = cir::GetGlobalOp::create(
1843 builder, aliasLoc, cir::PointerType::get(initAlias.getFunctionType()),
1844 initAlias.getSymName());
1845 mlir::Value nullCheck =
1847 mlir::Value cmp = cir::CmpOp::create(
1848 builder, aliasLoc, cir::CmpOpKind::ne, funcLoad, nullCheck);
1849 cir::IfOp::create(builder, aliasLoc, cmp,
false,
1850 [&](mlir::OpBuilder &, mlir::Location loc) {
1854 initAlias.getCallingConv());
1855 cir::YieldOp::create(builder, aliasLoc);
1862 initAlias.getCallingConv());
1866 cir::ReturnOp::create(builder, op.getLoc(), {get});
1870LoweringPreparePass::defineGlobalThreadLocalInitAlias(cir::GlobalOp op,
1871 cir::FuncOp aliasee) {
1872 CIRBaseBuilderTy builder(getContext());
1873 mlir::OpBuilder::InsertionGuard insertGuard(builder);
1874 builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
1875 mlir::StringAttr aliasName = op.getTlsRefs()->getInitName();
1876 auto existingAliasIter = threadLocalInitAliases.find(aliasName.getValue());
1878 if (existingAliasIter != threadLocalInitAliases.end())
1879 return existingAliasIter->second;
1883 cir::FuncOp::create(builder, op.getLoc(), aliasName, funcType);
1884 alias.setLinkage(op.getLinkage());
1887 alias.setAliasee(aliasee.getSymName());
1892 alias.setLinkage(cir::GlobalLinkageKind::ExternalWeakLinkage);
1893 mlir::SymbolTable::setSymbolVisibility(
1894 alias, mlir::SymbolTable::Visibility::Private);
1897 threadLocalInitAliases.insert({aliasName.getValue(), alias});
1901void LoweringPreparePass::lowerGlobalOp(GlobalOp op) {
1903 if (op.getDynamicInitGuard() &&
1904 (!op.getDynamicInitInfo() || op.getDynamicInitInfo()->getLocal()))
1907 mlir::Region &ctorRegion = op.getCtorRegion();
1908 mlir::Region &dtorRegion = op.getDtorRegion();
1909 cir::FuncOp initAlias;
1911 if (!ctorRegion.empty() || !dtorRegion.empty()) {
1914 cir::FuncOp f = buildCXXGlobalVarDeclInitFunc(op);
1917 ctorRegion.getBlocks().clear();
1918 dtorRegion.getBlocks().clear();
1921 if (op.getTlsModel()) {
1933 if (op.getTlsRefs()->getGuardName()) {
1935 initAlias = defineGlobalThreadLocalInitAlias(op, f);
1938 initAlias = defineGlobalThreadLocalInitAlias(op, getTlsInitFn());
1942 globalThreadLocalInitializers.push_back(f);
1944 }
else if (std::optional<uint32_t> priority = op.getInitPriority()) {
1945 prioritizedDynamicInitializers[*priority].push_back(f);
1946 }
else if (op.getDynamicInitInfo() &&
1947 (op.getDynamicInitInfo()->getIsInline() ||
1948 op.getDynamicInitInfo()->isTemplateInstantiation()) &&
1949 getTargetInfo().
getTriple().supportsCOMDAT() &&
1950 !op.hasInternalLinkage()) {
1961 globalCtorList.emplace_back(f.getSymName(),
1962 cir::GlobalCtorAttr::getDefaultPriority(),
1968 if (getTargetInfo().
getTriple().isOSBinFormatELF() ||
1969 getTargetInfo().getCXXABI().isMicrosoft())
1974 std::optional<llvm::StringRef> comdat = op.getComdat();
1975 if (comdat && (getTargetInfo().
getTriple().isOSBinFormatELF() ||
1976 getTargetInfo().
getTriple().isOSBinFormatWasm()))
1977 f.setComdat(comdat->empty() ? op.getSymName() : *comdat);
1979 dynamicInitializers.push_back(f);
1981 }
else if (op.getTlsModel() && op.getTlsRefs() && op.isDeclaration()) {
1984 initAlias = defineGlobalThreadLocalInitAlias(op, {});
1990 if (op.getTlsModel() && op.getTlsRefs())
1991 defineGlobalThreadLocalWrapper(op, initAlias, !op.isDeclaration());
1996void LoweringPreparePass::lowerGetGlobalOp(GetGlobalOp op) {
1999 auto globalOp = mlir::cast<cir::GlobalOp>(
2000 symbolTables.lookupNearestSymbolFrom(op, op.getNameAttr()));
2006 if (!globalOp.getTlsModel() || !globalOp.getTlsRefs())
2024 mlir::Operation *parentOp = op->getParentOp();
2025 if (parentOp == globalOp) {
2026 mlir::Region *ctorRegion = &globalOp.getCtorRegion();
2027 mlir::Region *dtorRegion = &globalOp.getDtorRegion();
2029 if (!ctorRegion->empty() && &*ctorRegion->op_begin() == op.getOperation())
2031 if (!dtorRegion->empty() && &*dtorRegion->op_begin() == op.getOperation())
2035 CIRBaseBuilderTy builder(getContext());
2036 cir::FuncOp wrapperFunc = getOrCreateThreadLocalWrapper(builder, globalOp);
2038 builder.setInsertionPoint(op);
2040 wrapperFunc.getLoc(),
2041 mlir::FlatSymbolRefAttr::get(wrapperFunc.getSymNameAttr()),
2042 wrapperFunc.getFunctionType().getReturnType(), {}, {},
2043 {}, {}, wrapperFunc.getCallingConv());
2044 op->replaceAllUsesWith(call);
2048void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
2049 CIRBaseBuilderTy builder(getContext());
2050 builder.setInsertionPointAfter(op);
2052 mlir::Location loc = op->getLoc();
2053 cir::CmpThreeWayInfoAttr cmpInfo = op.getInfo();
2062 mlir::Value transformedResult;
2063 if (cmpInfo.getOrdering() != CmpOrdering::Partial) {
2066 builder.
createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
2067 mlir::Value selectOnLt = builder.
createSelect(loc, lt, ltRes, gtRes);
2069 builder.
createCompare(loc, CmpOpKind::eq, op.getLhs(), op.getRhs());
2070 transformedResult = builder.
createSelect(loc, eq, eqRes, selectOnLt);
2074 loc, op.getType(), cmpInfo.getUnordered().value());
2077 builder.
createCompare(loc, CmpOpKind::eq, op.getLhs(), op.getRhs());
2078 mlir::Value selectOnEq = builder.
createSelect(loc, eq, eqRes, unorderedRes);
2080 builder.
createCompare(loc, CmpOpKind::gt, op.getLhs(), op.getRhs());
2081 mlir::Value selectOnGt = builder.
createSelect(loc, gt, gtRes, selectOnEq);
2083 builder.
createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
2084 transformedResult = builder.
createSelect(loc, lt, ltRes, selectOnGt);
2087 op.replaceAllUsesWith(transformedResult);
2091template <
typename AttributeTy>
2092static llvm::SmallVector<mlir::Attribute>
2096 for (
const auto &entry : list) {
2097 mlir::FlatSymbolRefAttr associated;
2098 if (!entry.associated.empty())
2099 associated = mlir::FlatSymbolRefAttr::get(context, entry.associated);
2101 AttributeTy::get(context, entry.name, entry.priority, associated));
2106void LoweringPreparePass::buildGlobalCtorDtorList() {
2107 if (!globalCtorList.empty()) {
2108 llvm::SmallVector<mlir::Attribute> globalCtors =
2112 mlirModule->setAttr(cir::CIRDialect::getGlobalCtorsAttrName(),
2113 mlir::ArrayAttr::get(&getContext(), globalCtors));
2116 if (!globalDtorList.empty()) {
2117 llvm::SmallVector<mlir::Attribute> globalDtors =
2120 mlirModule->setAttr(cir::CIRDialect::getGlobalDtorsAttrName(),
2121 mlir::ArrayAttr::get(&getContext(), globalDtors));
2126LoweringPreparePass::createGlobalThreadLocalGuard(CIRBaseBuilderTy &builder,
2127 mlir::Location loc) {
2128 mlir::OpBuilder::InsertionGuard guard(builder);
2129 builder.setInsertionPointToStart(mlirModule.getBody());
2132 cir::IntType guardTy = builder.
getSIntNTy(8);
2133 auto g = cir::GlobalOp::create(builder, loc,
"__tls_guard", guardTy);
2134 g.setLinkageAttr(cir::GlobalLinkageKindAttr::get(
2135 builder.getContext(), cir::GlobalLinkageKind::InternalLinkage));
2138 if (
auto defTlsModel = mlirModule->getAttrOfType<TLSModelAttr>(
2139 cir::CIRDialect::getDefaultTlsModelAttrName())) {
2140 g.setTlsModel(defTlsModel.getValue());
2143 g.setTlsModel(TLSModel::GeneralDynamic);
2146 g.setInitialValueAttr(cir::IntAttr::get(guardTy, 0));
2150cir::IfOp LoweringPreparePass::buildInitGuardCheck(CIRBaseBuilderTy &builder,
2152 cir::GlobalOp guard,
2154 cir::GetGlobalOp getGuard = builder.
createGetGlobal(guard, threadLocal);
2155 mlir::Value getGuardValue = getGuard;
2160 if (guard.getSymType() != builder.
getSIntNTy(8))
2162 getGuard, cir::PointerType::get(builder.
getSIntNTy(8)));
2164 mlir::Value guardLoad =
2168 builder.
createCompare(loc, cir::CmpOpKind::eq, guardLoad, zero);
2169 return cir::IfOp::create(
2171 false, [&](mlir::OpBuilder &, mlir::Location loc) {
2175 loc, builder.
getConstantInt(loc, guard.getSymType(), 1), getGuard);
2179void LoweringPreparePass::buildCXXGlobalTlsFunc() {
2180 if (globalThreadLocalInitializers.empty())
2186 cir::FuncOp tlsInit = getTlsInitFn();
2187 mlir::Location loc = tlsInit.getLoc();
2188 CIRBaseBuilderTy builder(getContext());
2189 mlir::Block *entryBB = tlsInit.addEntryBlock();
2190 builder.setInsertionPointToStart(entryBB);
2192 cir::IfOp ifOperation = buildInitGuardCheck(
2193 builder, loc, createGlobalThreadLocalGuard(builder, loc),
2197 builder.setInsertionPointToEnd(&ifOperation.getThenRegion().front());
2198 for (cir::FuncOp initFunc : globalThreadLocalInitializers)
2200 {}, initFunc.getCallingConv());
2201 cir::YieldOp::create(builder, loc);
2203 builder.setInsertionPointAfter(ifOperation);
2204 cir::ReturnOp::create(builder, loc);
2211 assert(priority <= 65535 &&
"Priority should always be <= 65535.");
2212 std::string prioritySuffix = llvm::utostr(priority);
2213 assert(prioritySuffix.size() < 6);
2214 prioritySuffix = std::string(6 - prioritySuffix.size(),
'0') + prioritySuffix;
2215 return prioritySuffix;
2218cir::FuncOp LoweringPreparePass::buildGlobalInitCallerFunc(
2219 llvm::StringRef fnName, cir::GlobalLinkageKind linkage,
2220 llvm::ArrayRef<cir::FuncOp> initializers,
uint32_t priority,
2221 cir::GlobalOp guard) {
2222 CIRBaseBuilderTy builder(getContext());
2223 builder.setInsertionPointToEnd(&mlirModule.getBodyRegion().back());
2224 auto fnType = cir::FuncType::get({}, builder.
getVoidTy());
2225 cir::FuncOp fn = buildRuntimeFunction(builder, fnName, mlirModule.getLoc(),
2227 builder.setInsertionPointToStart(fn.addEntryBlock());
2228 mlir::Location loc = fn.getLoc();
2229 auto emitCalls = [&] {
2230 for (cir::FuncOp init : initializers)
2233 init.getCallingConv());
2237 buildInitGuardCheck(builder, loc, guard,
false);
2238 builder.setInsertionPointToEnd(&guardIf.getThenRegion().front());
2240 cir::YieldOp::create(builder, loc);
2241 builder.setInsertionPointAfter(guardIf);
2245 cir::ReturnOp::create(builder, loc);
2246 globalCtorList.emplace_back(fnName, priority);
2250void LoweringPreparePass::buildCXXGlobalPriorityInitFuncs(
2251 llvm::SmallVectorImpl<cir::FuncOp> &importedInits) {
2255 for (
const auto &[priority, initializers] : prioritizedDynamicInitializers) {
2256 SmallString<256> fnName;
2257 fnName +=
"_GLOBAL__I_";
2260 llvm::SmallVector<cir::FuncOp> calls(importedInits.begin(),
2261 importedInits.end());
2262 calls.append(initializers.begin(), initializers.end());
2263 importedInits.clear();
2264 buildGlobalInitCallerFunc(fnName, cir::GlobalLinkageKind::InternalLinkage,
2269void LoweringPreparePass::buildCXXGlobalInitFunc() {
2270 CIRBaseBuilderTy builder(getContext());
2271 builder.setInsertionPointToEnd(&mlirModule.getBodyRegion().back());
2272 mlir::Location loc = mlirModule.getLoc();
2277 llvm::SmallVector<cir::FuncOp> importedInits;
2278 if (
auto inits = mlirModule->getAttrOfType<mlir::ArrayAttr>(
2279 cir::CIRDialect::getCXXModuleImportedInitsAttrName()))
2280 for (
auto init :
inits.getAsRange<cir::CXXModuleInitAttr>())
2281 importedInits.push_back(
2282 buildRuntimeFunction(builder, init.getName().getValue(),
2291 if (
auto moduleInitFnName = mlirModule->getAttrOfType<mlir::StringAttr>(
2292 cir::CIRDialect::getCXXModuleInitFnNameAttrName())) {
2300 llvm::SmallVector<cir::FuncOp> initializers(importedInits.begin(),
2301 importedInits.end());
2302 for (
const auto &[priority, inits] : prioritizedDynamicInitializers)
2303 initializers.append(
inits.begin(),
inits.end());
2304 initializers.append(dynamicInitializers.begin(), dynamicInitializers.end());
2306 llvm::StringRef fnName = moduleInitFnName.getValue();
2307 cir::GlobalOp guard;
2308 if (!initializers.empty()) {
2309 cir::IntType guardTy = builder.
getSIntNTy(8);
2311 createGuardGlobalOp(builder, loc, (fnName +
"__in_chrg").str(),
2312 guardTy, cir::GlobalLinkageKind::InternalLinkage);
2314 guard.setInitialValueAttr(cir::IntAttr::get(guardTy, 0));
2316 buildGlobalInitCallerFunc(fnName, cir::GlobalLinkageKind::ExternalLinkage,
2318 cir::GlobalCtorAttr::getDefaultPriority(), guard);
2326 buildCXXGlobalPriorityInitFuncs(importedInits);
2327 if (importedInits.empty() && dynamicInitializers.empty())
2330 llvm::SmallVector<cir::FuncOp> initializers(importedInits.begin(),
2331 importedInits.end());
2332 initializers.append(dynamicInitializers.begin(), dynamicInitializers.end());
2338 SmallString<256> fnName;
2339 fnName +=
"_GLOBAL__sub_I_";
2341 buildGlobalInitCallerFunc(fnName, cir::GlobalLinkageKind::InternalLinkage,
2343 cir::GlobalCtorAttr::getDefaultPriority());
2352 mlir::Operation *op, mlir::Type eltTy,
2354 mlir::Value numElements,
2355 uint64_t arrayLen,
bool isCtor) {
2356 mlir::Location loc = op->getLoc();
2357 bool isDynamic = numElements !=
nullptr;
2361 const unsigned sizeTypeSize =
2367 mlir::Value begin, end;
2370 end = cir::PtrStrideOp::create(builder, loc, eltTy, begin, numElements);
2372 mlir::Value endOffsetVal =
2374 begin = cir::CastOp::create(builder, loc, eltTy,
2375 cir::CastKind::array_to_ptrdecay, addr);
2376 end = cir::PtrStrideOp::create(builder, loc, eltTy, begin, endOffsetVal);
2379 mlir::Value start = isCtor ? begin : end;
2380 mlir::Value stop = isCtor ? end : begin;
2386 mlir::Value guardCond;
2389 guardCond = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne,
2395 cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, start, stop);
2397 ifOp = cir::IfOp::create(builder, loc, guardCond,
2399 [&](mlir::OpBuilder &, mlir::Location) {});
2400 builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
2403 mlir::Value tmpAddr =
2408 mlir::Block *bodyBlock = &op->getRegion(0).front();
2413 auto cloneRegionBodyInto = [&](mlir::Block *srcBlock,
2414 mlir::Value replacement) {
2415 mlir::IRMapping map;
2416 map.map(srcBlock->getArgument(0), replacement);
2417 for (mlir::Operation ®ionOp : *srcBlock) {
2418 if (!mlir::isa<cir::YieldOp>(®ionOp))
2419 builder.clone(regionOp, map);
2423 mlir::Block *partialDtorBlock =
nullptr;
2424 if (
auto arrayCtor = mlir::dyn_cast<cir::ArrayCtor>(op)) {
2425 mlir::Region &partialDtor = arrayCtor.getPartialDtor();
2426 if (!partialDtor.empty())
2427 partialDtorBlock = &partialDtor.front();
2428 }
else if (
auto arrayDtor = mlir::dyn_cast<cir::ArrayDtor>(op)) {
2437 if (arrayDtor.getDtorMayThrow())
2438 partialDtorBlock = bodyBlock;
2441 auto emitCtorDtorLoop = [&]() {
2445 [&](mlir::OpBuilder &b, mlir::Location loc) {
2446 auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
2447 auto cmp = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne,
2448 currentElement, stop);
2452 [&](mlir::OpBuilder &b, mlir::Location loc) {
2453 auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
2455 cloneRegionBodyInto(bodyBlock, currentElement);
2456 mlir::Value stride = builder.
getUnsignedInt(loc, 1, sizeTypeSize);
2457 auto nextElement = cir::PtrStrideOp::create(builder, loc, eltTy,
2458 currentElement, stride);
2461 mlir::Value stride = builder.
getSignedInt(loc, -1, sizeTypeSize);
2462 auto prevElement = cir::PtrStrideOp::create(builder, loc, eltTy,
2463 currentElement, stride);
2465 cloneRegionBodyInto(bodyBlock, prevElement);
2468 cir::YieldOp::create(b, loc);
2472 if (partialDtorBlock) {
2473 cir::CleanupScopeOp::create(
2474 builder, loc, cir::CleanupKind::EH,
2476 [&](mlir::OpBuilder &b, mlir::Location loc) {
2478 cir::YieldOp::create(b, loc);
2481 [&](mlir::OpBuilder &b, mlir::Location loc) {
2482 auto cur = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
2484 cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, cur, begin);
2486 builder, loc, cmp,
false,
2487 [&](mlir::OpBuilder &b, mlir::Location loc) {
2491 [&](mlir::OpBuilder &b, mlir::Location loc) {
2492 auto el = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
2493 auto neq = cir::CmpOp::create(
2494 builder, loc, cir::CmpOpKind::ne, el, begin);
2498 [&](mlir::OpBuilder &b, mlir::Location loc) {
2499 auto el = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
2500 mlir::Value negOne =
2502 auto prev = cir::PtrStrideOp::create(builder, loc, eltTy,
2505 cloneRegionBodyInto(partialDtorBlock, prev);
2508 cir::YieldOp::create(builder, loc);
2510 cir::YieldOp::create(b, loc);
2517 cir::YieldOp::create(builder, loc);
2522void LoweringPreparePass::lowerArrayDtor(cir::ArrayDtor op) {
2523 CIRBaseBuilderTy builder(getContext());
2524 builder.setInsertionPointAfter(op.getOperation());
2526 mlir::Type eltTy = op->getRegion(0).getArgument(0).getType();
2528 if (op.getNumElements()) {
2530 op.getAddr(), op.getNumElements(),
2537 mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize();
2543void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
2544 cir::CIRBaseBuilderTy builder(getContext());
2545 builder.setInsertionPointAfter(op.getOperation());
2547 mlir::Type eltTy = op->getRegion(0).getArgument(0).getType();
2549 if (op.getNumElements()) {
2551 op.getAddr(), op.getNumElements(),
2558 mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize();
2564cir::FuncOp LoweringPreparePass::getCalledFunction(cir::CallOp callOp) {
2565 mlir::SymbolRefAttr sym = llvm::dyn_cast_if_present<mlir::SymbolRefAttr>(
2566 callOp.getCallableForCallee());
2569 return symbolTables.lookupNearestSymbolFrom<cir::FuncOp>(callOp, sym);
2572void LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {
2573 cir::FuncOp funcOp = getCalledFunction(op);
2577 std::optional<cir::CtorKind> ctorKind = funcOp.getCxxConstructorKind();
2578 if (ctorKind && *ctorKind == cir::CtorKind::Copy &&
2579 funcOp.isCxxTrivialMemberFunction()) {
2581 CIRBaseBuilderTy builder(getContext());
2582 mlir::ValueRange operands = op.getOperands();
2583 mlir::Value dest = operands[0];
2584 mlir::Value src = operands[1];
2585 builder.setInsertionPoint(op);
2591cir::GlobalOp LoweringPreparePass::getOrCreateConstAggregateGlobal(
2592 CIRBaseBuilderTy &builder, mlir::Location loc, llvm::StringRef baseName,
2593 mlir::Type ty, mlir::TypedAttr constant, uint64_t alignment) {
2595 llvm::SmallVector<cir::GlobalOp, 1> &versions =
2596 constAggregateGlobals[baseName];
2599 for (cir::GlobalOp gv : versions) {
2600 if (gv.getSymType() == ty && gv.getInitialValue() == constant &&
2601 gv.getAlignment() == alignment)
2609 llvm::SmallString<128>
name(baseName);
2610 size_t baseLen =
name.size();
2611 unsigned version = versions.size();
2613 name.resize(baseLen);
2615 name.push_back(
'.');
2616 llvm::Twine(version).toVector(name);
2618 auto existingGv = symbolTables.lookupSymbolIn<cir::GlobalOp>(
2619 mlirModule, mlir::StringAttr::get(&getContext(), name));
2622 versions.push_back(existingGv);
2623 if (existingGv.getSymType() == ty &&
2624 existingGv.getInitialValue() == constant &&
2625 existingGv.getAlignment() == alignment)
2631 mlir::OpBuilder::InsertionGuard guard(builder);
2632 builder.setInsertionPointToStart(mlirModule.getBody());
2634 cir::GlobalOp::create(builder, loc, name, ty,
2636 cir::LangAddressSpaceAttr::get(
2637 &getContext(), cir::LangAddressSpace::Default),
2638 cir::GlobalLinkageKind::PrivateLinkage);
2639 mlir::SymbolTable::setSymbolVisibility(
2640 gv, mlir::SymbolTable::Visibility::Private);
2641 gv.setInitialValueAttr(constant);
2642 gv.setAlignment(alignment);
2646 symbolTables.getSymbolTable(mlirModule).insert(gv);
2648 versions.push_back(gv);
2652void LoweringPreparePass::lowerStoreOfConstAggregate(cir::StoreOp op) {
2654 auto constOp = op.getValue().getDefiningOp<cir::ConstantOp>();
2658 mlir::Type ty = constOp.getType();
2659 if (!mlir::isa<cir::ArrayType, cir::RecordType>(ty))
2665 auto alloca = op.getAddr().getDefiningOp<cir::AllocaOp>();
2669 mlir::TypedAttr constant = constOp.getValue();
2680 auto func = op->getParentOfType<cir::FuncOp>();
2683 llvm::StringRef funcName = func.getSymName();
2686 llvm::StringRef varName = alloca.getName();
2689 std::string baseName = (
"__const." + funcName +
"." + varName).str();
2690 CIRBaseBuilderTy builder(getContext());
2694 cir::GlobalOp gv = getOrCreateConstAggregateGlobal(
2695 builder, op.getLoc(), baseName, ty, constant, alloca.getAlignment());
2698 builder.setInsertionPoint(op);
2700 auto ptrTy = cir::PointerType::get(ty);
2701 mlir::Value globalPtr =
2702 cir::GetGlobalOp::create(builder, op.getLoc(), ptrTy, gv.getSymName());
2705 cir::CopyOp copyOp = builder.
createCopy(op.getAddr(), globalPtr);
2707 cir::CIRDataLayout dataLayout(mlirModule);
2708 uint64_t naturalAlign = dataLayout.getABITypeAlign(ty).value();
2709 if (alloca.getAlignment() != naturalAlign)
2710 copyOp.setDstAlignment(alloca.getAlignment());
2711 uint64_t srcAlign = gv.getAlignment().value_or(naturalAlign);
2712 if (srcAlign != naturalAlign)
2713 copyOp.setSrcAlignment(srcAlign);
2719 if (constOp.use_empty())
2726void LoweringPreparePass::lowerStdOp(cir::StdOpInterface typedOp) {
2727 mlir::Operation *op = typedOp.getOperation();
2728 cir::CIRBaseBuilderTy builder(getContext());
2729 builder.setInsertionPointAfter(op);
2730 mlir::Type resultType;
2731 if (op->getNumResults())
2732 resultType = op->getResult(0).getType();
2734 op->getLoc(), typedOp.getOriginalFnAttr(), resultType, op->getOperands());
2748 for (mlir::NamedAttribute attr : op->getDiscardableAttrs()) {
2749 if (call->getInherentAttr(
attr.getName()).has_value())
2750 call->setInherentAttr(
attr.getName(),
attr.getValue());
2752 call->setDiscardableAttr(
attr.getName(),
attr.getValue());
2755 op->replaceAllUsesWith(call);
2759void LoweringPreparePass::runOnOp(mlir::Operation *op) {
2760 if (
auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) {
2761 lowerArrayCtor(arrayCtor);
2762 }
else if (
auto arrayDtor = dyn_cast<cir::ArrayDtor>(op)) {
2763 lowerArrayDtor(arrayDtor);
2764 }
else if (
auto registerOp = dyn_cast<cir::RegisterExitDtorOp>(op)) {
2765 lowerRegisterExitDtorOp(registerOp);
2766 }
else if (
auto stdOp = mlir::dyn_cast<cir::StdOpInterface>(op)) {
2768 }
else if (
auto cast = mlir::dyn_cast<cir::CastOp>(op)) {
2770 }
else if (
auto complexConj = mlir::dyn_cast<cir::ComplexConjOp>(op)) {
2771 lowerComplexConjOp(complexConj);
2772 }
else if (
auto complexDiv = mlir::dyn_cast<cir::ComplexFDivOp>(op)) {
2773 lowerComplexFDivOp(complexDiv);
2774 }
else if (
auto complexMul = mlir::dyn_cast<cir::ComplexFMulOp>(op)) {
2775 lowerComplexFMulOp(complexMul);
2776 }
else if (
auto complexDiv = mlir::dyn_cast<cir::ComplexDivOp>(op)) {
2777 lowerComplexDivOp(complexDiv);
2778 }
else if (
auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op)) {
2779 lowerComplexMulOp(complexMul);
2780 }
else if (
auto glob = mlir::dyn_cast<cir::GlobalOp>(op)) {
2781 lowerGlobalOp(glob);
2782 if (
auto regAttr = glob->getAttrOfType<CUDAVarRegistrationInfoAttr>(
2783 CUDAVarRegistrationInfoAttr::getMnemonic()))
2784 cudaDeviceVars.emplace_back(glob, regAttr);
2785 }
else if (
auto getGlob = mlir::dyn_cast<cir::GetGlobalOp>(op)) {
2786 lowerGetGlobalOp(getGlob);
2787 }
else if (
auto callOp = dyn_cast<cir::CallOp>(op)) {
2788 lowerTrivialCopyCall(callOp);
2789 }
else if (
auto storeOp = dyn_cast<cir::StoreOp>(op)) {
2790 lowerStoreOfConstAggregate(storeOp);
2791 }
else if (
auto fnOp = dyn_cast<cir::FuncOp>(op)) {
2792 if (
auto globalCtor = fnOp.getGlobalCtorPriority())
2793 globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
2794 else if (
auto globalDtor = fnOp.getGlobalDtorPriority())
2795 globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
2797 if (mlir::Attribute attr =
2798 fnOp->getAttr(cir::CUDAKernelNameAttr::getMnemonic())) {
2799 auto kernelNameAttr = dyn_cast<CUDAKernelNameAttr>(attr);
2800 llvm::StringRef kernelName = kernelNameAttr.getKernelName();
2801 cudaKernelMap[kernelName] = fnOp;
2803 }
else if (
auto threeWayCmp = dyn_cast<cir::CmpThreeWayOp>(op)) {
2804 lowerThreeWayCmpOp(threeWayCmp);
2805 }
else if (
auto initOp = dyn_cast<cir::LocalInitOp>(op)) {
2806 lowerLocalInitOp(initOp);
2817 llvm::StringRef name) {
2818 return (
"__" + prefix + name).str();
2840void LoweringPreparePass::buildCUDAModuleCtor() {
2841 bool isHIP = getLangOpts().HIP;
2843 if (getLangOpts().GPURelocatableDeviceCode)
2844 llvm_unreachable(
"GPU RDC NYI");
2848 if (cudaKernelMap.empty() && cudaDeviceVars.empty())
2853 auto deviceBinaryAttr = mlirModule->getAttrOfType<mlir::StringAttr>(
2854 CIRDialect::getCUDADeviceBinaryAttrName());
2855 if (!deviceBinaryAttr) {
2863 mlir::Location loc = mlirModule->getLoc();
2864 CIRBaseBuilderTy builder(getContext());
2865 builder.setInsertionPointToStart(mlirModule.getBody());
2869 PointerType voidPtrPtrTy = builder.
getPointerTo(voidPtrTy);
2875 llvm::StringRef fatbinConstName =
2876 getLangOpts().HIP ?
".hip_fatbin" :
".nv_fatbin";
2878 llvm::StringRef fatbinSectionName =
2879 getLangOpts().HIP ?
".hipFatBinSegment" :
".nvFatBinSegment";
2883 auto fatbinType = mlir::cast<ArrayType>(deviceBinaryAttr.getType());
2885 GlobalOp fatbinStr = GlobalOp::create(builder, loc, fatbinStrName, fatbinType,
2887 GlobalLinkageKind::PrivateLinkage);
2889 const unsigned HIPCodeObjectAlign = 4096;
2890 fatbinStr.setAlignment(HIPCodeObjectAlign);
2892 fatbinStr.setAlignment(8);
2895 fatbinStr.setInitialValueAttr(
2896 cir::ConstArrayAttr::get(fatbinType, deviceBinaryAttr));
2897 fatbinStr.setSection(fatbinConstName);
2898 fatbinStr.setPrivate();
2902 mlir::Type fatbinWrapperMembers[] = {intTy, intTy, voidPtrTy, voidPtrTy};
2903 auto fatbinWrapperType = cir::StructType::get(
2904 &getContext(), fatbinWrapperMembers,
false,
false,
2906 std::string fatbinWrapperName =
2908 GlobalOp fatbinWrapper = GlobalOp::create(
2909 builder, loc, fatbinWrapperName, fatbinWrapperType,
2910 true, {}, GlobalLinkageKind::PrivateLinkage);
2911 fatbinWrapper.setSection(fatbinSectionName);
2913 constexpr unsigned cudaFatMagic = 0x466243b1;
2914 constexpr unsigned hipFatMagic = 0x48495046;
2915 unsigned fatMagic =
isHIP ? hipFatMagic : cudaFatMagic;
2917 auto magicInit = IntAttr::get(intTy, fatMagic);
2918 auto versionInit = IntAttr::get(intTy, 1);
2919 auto fatbinStrSymbol =
2920 mlir::FlatSymbolRefAttr::get(fatbinStr.getSymNameAttr());
2921 auto fatbinInit = GlobalViewAttr::get(voidPtrTy, fatbinStrSymbol);
2923 fatbinWrapper.setInitialValueAttr(cir::ConstRecordAttr::get(
2925 mlir::ArrayAttr::get(&getContext(),
2926 {magicInit, versionInit, fatbinInit, unusedInit})));
2929 std::string gpubinHandleName =
2932 GlobalOp gpuBinHandle = GlobalOp::create(
2933 builder, loc, gpubinHandleName, voidPtrPtrTy,
2934 false, {}, cir::GlobalLinkageKind::InternalLinkage);
2936 gpuBinHandle.setPrivate();
2941 std::string regFuncName =
2943 FuncType regFuncType = FuncType::get({voidPtrTy}, voidPtrPtrTy);
2944 cir::FuncOp regFunc =
2945 buildRuntimeFunction(builder, regFuncName, loc, regFuncType);
2948 cir::FuncOp moduleCtor = buildRuntimeFunction(
2949 builder, moduleCtorName, loc, FuncType::get({}, voidTy),
2950 GlobalLinkageKind::InternalLinkage);
2952 globalCtorList.emplace_back(moduleCtorName,
2953 cir::GlobalCtorAttr::getDefaultPriority());
2954 builder.setInsertionPointToStart(moduleCtor.addEntryBlock());
2962 mlir::Block *entryBlock = builder.getInsertionBlock();
2963 mlir::Region *parent = entryBlock->getParent();
2964 mlir::Block *ifBlock = builder.createBlock(parent);
2965 mlir::Block *exitBlock = builder.createBlock(parent);
2967 mlir::OpBuilder::InsertionGuard guard(builder);
2968 builder.setInsertionPointToEnd(entryBlock);
2969 mlir::Value handle =
2971 auto handlePtrTy = mlir::cast<cir::PointerType>(handle.getType());
2972 mlir::Value nullPtr = builder.
getNullPtr(handlePtrTy, loc);
2973 mlir::Value isNull =
2974 builder.
createCompare(loc, cir::CmpOpKind::eq, handle, nullPtr);
2975 cir::BrCondOp::create(builder, loc, isNull, ifBlock, exitBlock);
2979 mlir::OpBuilder::InsertionGuard guard(builder);
2980 builder.setInsertionPointToStart(ifBlock);
2982 mlir::Value fatbinVoidPtr = builder.
createBitcast(wrapper, voidPtrTy);
2983 cir::CallOp gpuBinaryHandleCall =
2985 mlir::Value gpuBinaryHandle = gpuBinaryHandleCall.getResult();
2987 mlir::Value gpuBinaryHandleGlobal = builder.
createGetGlobal(gpuBinHandle);
2988 builder.
createStore(loc, gpuBinaryHandle, gpuBinaryHandleGlobal);
2989 cir::BrOp::create(builder, loc, exitBlock);
2994 mlir::OpBuilder::InsertionGuard guard(builder);
2995 builder.setInsertionPointToStart(exitBlock);
2996 mlir::Value gHandle =
2999 if (std::optional<FuncOp> regGlobal = buildCUDARegisterGlobals())
3002 if (std::optional<FuncOp> dtor = buildHIPModuleDtor()) {
3003 cir::CIRBaseBuilderTy globalBuilder(getContext());
3004 globalBuilder.setInsertionPointToStart(mlirModule.getBody());
3005 FuncOp atexit = buildRuntimeFunction(
3006 globalBuilder,
"atexit", loc,
3007 FuncType::get(PointerType::get(dtor->getFunctionType()), intTy));
3008 mlir::Value dtorFunc = GetGlobalOp::create(
3009 builder, loc, PointerType::get(dtor->getFunctionType()),
3010 mlir::FlatSymbolRefAttr::get(dtor->getSymNameAttr()));
3013 cir::ReturnOp::create(builder, loc);
3017 if (!getLangOpts().GPURelocatableDeviceCode) {
3025 mlir::Value fatbinVoidPtr = builder.
createBitcast(wrapper, voidPtrTy);
3026 cir::CallOp gpuBinaryHandleCall =
3028 mlir::Value gpuBinaryHandle = gpuBinaryHandleCall.getResult();
3030 mlir::Value gpuBinaryHandleGlobal = builder.
createGetGlobal(gpuBinHandle);
3031 builder.
createStore(loc, gpuBinaryHandle, gpuBinaryHandleGlobal);
3034 if (std::optional<FuncOp> regGlobal = buildCUDARegisterGlobals()) {
3035 builder.
createCallOp(loc, *regGlobal, gpuBinaryHandle);
3041 std::optional<llvm::VersionTuple> sdkVersion = getSDKVersion();
3046 cir::CIRBaseBuilderTy globalBuilder(getContext());
3047 globalBuilder.setInsertionPointToStart(mlirModule.getBody());
3049 buildRuntimeFunction(globalBuilder,
"__cudaRegisterFatBinaryEnd", loc,
3050 FuncType::get({voidPtrPtrTy}, voidTy));
3054 llvm_unreachable(
"GPU RDC NYI");
3059 if (std::optional<FuncOp> dtor = buildCUDAModuleDtor()) {
3062 cir::CIRBaseBuilderTy globalBuilder(getContext());
3063 globalBuilder.setInsertionPointToStart(mlirModule.getBody());
3064 FuncOp atexit = buildRuntimeFunction(
3065 globalBuilder,
"atexit", loc,
3066 FuncType::get(PointerType::get(dtor->getFunctionType()), intTy));
3067 mlir::Value dtorFunc = GetGlobalOp::create(
3068 builder, loc, PointerType::get(dtor->getFunctionType()),
3069 mlir::FlatSymbolRefAttr::get(dtor->getSymNameAttr()));
3072 cir::ReturnOp::create(builder, loc);
3075std::optional<FuncOp> LoweringPreparePass::buildCUDAModuleDtor() {
3076 if (!mlirModule->getAttr(CIRDialect::getCUDADeviceBinaryAttrName()))
3081 VoidType voidTy = VoidType::get(&getContext());
3082 PointerType voidPtrPtrTy = PointerType::get(PointerType::get(voidTy));
3084 mlir::Location loc = mlirModule.getLoc();
3086 cir::CIRBaseBuilderTy builder(getContext());
3087 builder.setInsertionPointToStart(mlirModule.getBody());
3090 std::string unregisterFuncName =
3092 FuncOp unregisterFunc = buildRuntimeFunction(
3093 builder, unregisterFuncName, loc, FuncType::get({voidPtrPtrTy}, voidTy));
3102 buildRuntimeFunction(builder, dtorName, loc, FuncType::get({}, voidTy),
3103 GlobalLinkageKind::InternalLinkage);
3105 builder.setInsertionPointToStart(dtor.addEntryBlock());
3111 GlobalOp gpubinGlobal = cast<GlobalOp>(mlirModule.lookupSymbol(gpubinName));
3113 mlir::Value gpubin = builder.
createLoad(loc, gpubinAddress);
3115 ReturnOp::create(builder, loc);
3132std::optional<FuncOp> LoweringPreparePass::buildHIPModuleDtor() {
3133 if (!mlirModule->getAttr(CIRDialect::getCUDADeviceBinaryAttrName()))
3138 VoidType voidTy = VoidType::get(&getContext());
3139 PointerType voidPtrPtrTy = PointerType::get(PointerType::get(voidTy));
3141 mlir::Location loc = mlirModule.getLoc();
3143 cir::CIRBaseBuilderTy builder(getContext());
3144 builder.setInsertionPointToStart(mlirModule.getBody());
3147 std::string unregisterFuncName =
3149 FuncOp unregisterFunc = buildRuntimeFunction(
3150 builder, unregisterFuncName, loc, FuncType::get({voidPtrPtrTy}, voidTy));
3154 buildRuntimeFunction(builder, dtorName, loc, FuncType::get({}, voidTy),
3155 GlobalLinkageKind::InternalLinkage);
3158 GlobalOp gpuBinGlobal = cast<GlobalOp>(mlirModule.lookupSymbol(gpubinName));
3160 mlir::Block *entryBlock = dtor.addEntryBlock();
3161 mlir::Block *ifBlock = builder.createBlock(&dtor.getBody());
3162 mlir::Block *exitBlock = builder.createBlock(&dtor.getBody());
3164 mlir::OpBuilder::InsertionGuard guard(builder);
3165 builder.setInsertionPointToEnd(entryBlock);
3166 mlir::Value handle =
3168 auto handlePtrTy = mlir::cast<cir::PointerType>(handle.getType());
3169 mlir::Value nullPtr = builder.
getNullPtr(handlePtrTy, loc);
3170 mlir::Value isNotNull =
3171 builder.
createCompare(loc, cir::CmpOpKind::ne, handle, nullPtr);
3172 cir::BrCondOp::create(builder, loc, isNotNull, ifBlock, exitBlock);
3176 mlir::OpBuilder::InsertionGuard ifGuard(builder);
3177 builder.setInsertionPointToStart(ifBlock);
3180 cir::BrOp::create(builder, loc, exitBlock);
3183 mlir::OpBuilder::InsertionGuard exitGuard(builder);
3184 builder.setInsertionPointToStart(exitBlock);
3185 cir::ReturnOp::create(builder, loc);
3191std::optional<FuncOp> LoweringPreparePass::buildCUDARegisterGlobals() {
3192 if (cudaKernelMap.empty() && cudaDeviceVars.empty())
3195 cir::CIRBaseBuilderTy builder(getContext());
3196 builder.setInsertionPointToStart(mlirModule.getBody());
3198 mlir::Location loc = mlirModule.getLoc();
3201 auto voidTy = VoidType::get(&getContext());
3202 auto voidPtrTy = PointerType::get(voidTy);
3203 auto voidPtrPtrTy = PointerType::get(voidPtrTy);
3207 std::string regGlobalFuncName =
3209 auto regGlobalFuncTy = FuncType::get({voidPtrPtrTy}, voidTy);
3210 FuncOp regGlobalFunc =
3211 buildRuntimeFunction(builder, regGlobalFuncName, loc, regGlobalFuncTy,
3212 GlobalLinkageKind::InternalLinkage);
3213 builder.setInsertionPointToStart(regGlobalFunc.addEntryBlock());
3215 buildCUDARegisterGlobalFunctions(builder, regGlobalFunc);
3216 buildCUDARegisterVars(builder, regGlobalFunc);
3218 ReturnOp::create(builder, loc);
3219 return regGlobalFunc;
3222void LoweringPreparePass::buildCUDARegisterGlobalFunctions(
3223 cir::CIRBaseBuilderTy &builder, FuncOp regGlobalFunc) {
3224 mlir::Location loc = mlirModule.getLoc();
3226 cir::CIRDataLayout dataLayout(mlirModule);
3228 auto voidTy = VoidType::get(&getContext());
3229 auto voidPtrTy = PointerType::get(voidTy);
3230 auto voidPtrPtrTy = PointerType::get(voidPtrTy);
3233 cir::IntType::get(&getContext(), getTargetInfo().
getCharWidth(),
3237 mlir::Value fatbinHandle = *regGlobalFunc.args_begin();
3239 cir::CIRBaseBuilderTy globalBuilder(getContext());
3240 globalBuilder.setInsertionPointToStart(mlirModule.getBody());
3254 FuncOp cudaRegisterFunction = buildRuntimeFunction(
3256 FuncType::get({voidPtrPtrTy, voidPtrTy, voidPtrTy, voidPtrTy, intTy,
3257 voidPtrTy, voidPtrTy, voidPtrTy, voidPtrTy, voidPtrTy},
3260 auto makeConstantString = [&](llvm::StringRef str) -> GlobalOp {
3261 auto strType = ArrayType::get(&getContext(), charTy, 1 + str.size());
3262 auto tmpString = cir::GlobalOp::create(
3263 globalBuilder, loc, (
".str" + str).str(), strType,
3265 cir::GlobalLinkageKind::PrivateLinkage);
3268 tmpString.setInitialValueAttr(
3269 ConstArrayAttr::get(strType, StringAttr::get(str +
"\0", strType)));
3270 tmpString.setPrivate();
3274 cir::ConstantOp cirNullPtr = builder.
getNullPtr(voidPtrTy, loc);
3275 bool isHIP = getLangOpts().HIP;
3276 for (
auto kernelName : cudaKernelMap.keys()) {
3277 FuncOp deviceStub = cudaKernelMap[kernelName];
3278 GlobalOp deviceFuncStr = makeConstantString(kernelName);
3282 mlir::Value hostFunc;
3289 auto funcHandle = cast<GlobalOp>(mlirModule.lookupSymbol(kernelName));
3294 GetGlobalOp::create(
3295 builder, loc, PointerType::get(deviceStub.getFunctionType()),
3296 mlir::FlatSymbolRefAttr::get(deviceStub.getSymNameAttr())),
3300 loc, cudaRegisterFunction,
3301 {fatbinHandle, hostFunc, deviceFunc, deviceFunc,
3302 ConstantOp::create(builder, loc, IntAttr::get(intTy, -1)), cirNullPtr,
3303 cirNullPtr, cirNullPtr, cirNullPtr, cirNullPtr});
3310void LoweringPreparePass::buildCUDARegisterVars(cir::CIRBaseBuilderTy &builder,
3311 FuncOp regGlobalFunc) {
3312 mlir::Location loc = mlirModule.getLoc();
3314 cir::CIRDataLayout dataLayout(mlirModule);
3317 PointerType voidPtrPtrTy = builder.
getPointerTo(voidPtrTy);
3319 IntType sizeTy = builder.
getUIntNTy(getTargetInfo().getMaxPointerWidth());
3321 cir::IntType::get(&getContext(), getTargetInfo().
getCharWidth(),
3324 if (cudaDeviceVars.empty())
3327 cir::CIRBaseBuilderTy globalBuilder(getContext());
3328 globalBuilder.setInsertionPointToStart(mlirModule.getBody());
3330 cir::VoidType voidTy = builder.
getVoidTy();
3331 FuncOp cudaRegisterVar;
3332 FuncOp cudaRegisterManagedVar;
3334 auto makeConstantString = [&](llvm::StringRef str) -> GlobalOp {
3335 auto strType = ArrayType::get(&getContext(), charTy, 1 + str.size());
3336 auto tmpString = cir::GlobalOp::create(
3337 globalBuilder, loc, (
".str" + str).str(), strType,
3339 cir::GlobalLinkageKind::PrivateLinkage);
3340 tmpString.setInitialValueAttr(
3341 ConstArrayAttr::get(strType, StringAttr::get(str +
"\0", strType)));
3342 tmpString.setPrivate();
3346 mlir::Value fatbinHandle = *regGlobalFunc.args_begin();
3348 for (
auto &[global, regAttr] : cudaDeviceVars) {
3349 switch (regAttr.getKind()) {
3350 case cir::CUDADeviceVarKind::Variable:
3352 case cir::CUDADeviceVarKind::Surface:
3353 llvm_unreachable(
"Surface registration NYI");
3354 case cir::CUDADeviceVarKind::Texture:
3355 llvm_unreachable(
"Texture registration NYI");
3359 if (regAttr.getIsManaged() && global.isDeclaration())
3362 GlobalOp deviceNameStr = makeConstantString(regAttr.getDeviceSideName());
3365 mlir::Value hostVar =
3368 llvm::TypeSize size = dataLayout.getTypeAllocSize(global.getSymType());
3370 if (regAttr.getIsManaged()) {
3374 if (!cudaRegisterManagedVar)
3375 cudaRegisterManagedVar = buildRuntimeFunction(
3379 {voidPtrPtrTy, voidPtrTy, voidPtrTy, voidPtrTy, sizeTy, intTy},
3381 llvm::StringRef
name = global.getSymName();
3382 assert(
name.ends_with(
".managed") &&
3383 "HIP managed variables not transformed");
3384 auto managedVar = mlirModule.lookupSymbol<GlobalOp>(
3385 name.drop_back(llvm::StringRef(
".managed").size()));
3386 mlir::Value managedPtr =
3388 auto varSize = ConstantOp::create(
3389 builder, loc, IntAttr::get(sizeTy, size.getFixedValue()));
3390 auto align = ConstantOp::create(
3391 builder, loc, IntAttr::get(intTy, global.getAlignment().value_or(1)));
3393 loc, cudaRegisterManagedVar,
3394 {fatbinHandle, managedPtr, hostVar, deviceName, varSize,
align});
3402 if (!cudaRegisterVar)
3403 cudaRegisterVar = buildRuntimeFunction(
3405 FuncType::get({voidPtrPtrTy, voidPtrTy, voidPtrTy, voidPtrTy, intTy,
3406 sizeTy, intTy, intTy},
3408 auto isExtern = ConstantOp::create(
3409 builder, loc, IntAttr::get(intTy, regAttr.getIsExtern() ? 1 : 0));
3410 auto varSize = ConstantOp::create(
3411 builder, loc, IntAttr::get(sizeTy, size.getFixedValue()));
3412 auto isConstant = ConstantOp::create(
3413 builder, loc, IntAttr::get(intTy, regAttr.getIsConstant() ? 1 : 0));
3415 ConstantOp::create(builder, loc, IntAttr::get(intTy, 0));
3417 {fatbinHandle, hostVar, deviceName, deviceName,
3418 isExtern, varSize, isConstant, normalized});
3423void LoweringPreparePass::runOnOperation() {
3424 mlirModule = getOperation();
3429 <<
" requires a module with a triple";
3430 return signalPassFailure();
3433 llvm::SmallVector<mlir::Operation *> opsToTransform;
3435 mlirModule->walk([&](mlir::Operation *op) {
3436 if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
3437 cir::ComplexConjOp, cir::ComplexMulOp, cir::ComplexDivOp,
3438 cir::ComplexFMulOp, cir::ComplexFDivOp, cir::DynamicCastOp,
3439 cir::FuncOp, cir::CallOp, cir::GetGlobalOp, cir::GlobalOp,
3440 cir::StoreOp, cir::CmpThreeWayOp, cir::LocalInitOp,
3441 cir::RegisterExitDtorOp, cir::StdOpInterface>(op))
3442 opsToTransform.push_back(op);
3445 for (mlir::Operation *o : opsToTransform)
3448 buildCXXGlobalInitFunc();
3449 buildCXXGlobalTlsFunc();
3450 if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice) {
3451 buildCUDAModuleCtor();
3456 mlirModule->removeAttr(CIRDialect::getCUDADeviceBinaryAttrName());
3459 buildGlobalCtorDtorList();
3463 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)
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
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 hipModuleCtor()
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()