@@ -2413,6 +2413,73 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
24132413 });
24142414}
24152415
2416+ static void buildCtorDtorList (
2417+ mlir::ModuleOp module , StringRef globalXtorName, StringRef llvmXtorName,
2418+ llvm::function_ref<std::pair<StringRef, int >(mlir::Attribute)> createXtor) {
2419+ llvm::SmallVector<std::pair<StringRef, int >> globalXtors;
2420+ for (const mlir::NamedAttribute namedAttr : module ->getAttrs ()) {
2421+ if (namedAttr.getName () == globalXtorName) {
2422+ for (auto attr : mlir::cast<mlir::ArrayAttr>(namedAttr.getValue ()))
2423+ globalXtors.emplace_back (createXtor (attr));
2424+ break ;
2425+ }
2426+ }
2427+
2428+ if (globalXtors.empty ())
2429+ return ;
2430+
2431+ mlir::OpBuilder builder (module .getContext ());
2432+ builder.setInsertionPointToEnd (&module .getBodyRegion ().back ());
2433+
2434+ // Create a global array llvm.global_ctors with element type of
2435+ // struct { i32, ptr, ptr }
2436+ auto ctorPFTy = mlir::LLVM::LLVMPointerType::get (builder.getContext ());
2437+ llvm::SmallVector<mlir::Type> ctorStructFields;
2438+ ctorStructFields.push_back (builder.getI32Type ());
2439+ ctorStructFields.push_back (ctorPFTy);
2440+ ctorStructFields.push_back (ctorPFTy);
2441+
2442+ auto ctorStructTy = mlir::LLVM::LLVMStructType::getLiteral (
2443+ builder.getContext (), ctorStructFields);
2444+ auto ctorStructArrayTy =
2445+ mlir::LLVM::LLVMArrayType::get (ctorStructTy, globalXtors.size ());
2446+
2447+ mlir::Location loc = module .getLoc ();
2448+ auto newGlobalOp = mlir::LLVM::GlobalOp::create (
2449+ builder, loc, ctorStructArrayTy, /* constant=*/ false ,
2450+ mlir::LLVM::Linkage::Appending, llvmXtorName, mlir::Attribute ());
2451+
2452+ builder.createBlock (&newGlobalOp.getRegion ());
2453+ builder.setInsertionPointToEnd (newGlobalOp.getInitializerBlock ());
2454+
2455+ mlir::Value result =
2456+ mlir::LLVM::UndefOp::create (builder, loc, ctorStructArrayTy);
2457+
2458+ for (auto [index, fn] : llvm::enumerate (globalXtors)) {
2459+ mlir::Value structInit =
2460+ mlir::LLVM::UndefOp::create (builder, loc, ctorStructTy);
2461+ mlir::Value initPriority = mlir::LLVM::ConstantOp::create (
2462+ builder, loc, ctorStructFields[0 ], fn.second );
2463+ mlir::Value initFuncAddr = mlir::LLVM::AddressOfOp::create (
2464+ builder, loc, ctorStructFields[1 ], fn.first );
2465+ mlir::Value initAssociate =
2466+ mlir::LLVM::ZeroOp::create (builder, loc, ctorStructFields[2 ]);
2467+ // Literal zero makes the InsertValueOp::create ambiguous.
2468+ llvm::SmallVector<int64_t > zero{0 };
2469+ structInit = mlir::LLVM::InsertValueOp::create (builder, loc, structInit,
2470+ initPriority, zero);
2471+ structInit = mlir::LLVM::InsertValueOp::create (builder, loc, structInit,
2472+ initFuncAddr, 1 );
2473+ // TODO: handle associated data for initializers.
2474+ structInit = mlir::LLVM::InsertValueOp::create (builder, loc, structInit,
2475+ initAssociate, 2 );
2476+ result = mlir::LLVM::InsertValueOp::create (builder, loc, result, structInit,
2477+ index);
2478+ }
2479+
2480+ builder.create <mlir::LLVM::ReturnOp>(loc, result);
2481+ }
2482+
24162483// The applyPartialConversion function traverses blocks in the dominance order,
24172484// so it does not lower and operations that are not reachachable from the
24182485// operations passed in as arguments. Since we do need to lower such code in
@@ -2519,6 +2586,14 @@ void ConvertCIRToLLVMPass::runOnOperation() {
25192586
25202587 if (failed (applyPartialConversion (ops, target, std::move (patterns))))
25212588 signalPassFailure ();
2589+
2590+ // Emit the llvm.global_ctors array.
2591+ buildCtorDtorList (module , cir::CIRDialect::getGlobalCtorsAttrName (),
2592+ " llvm.global_ctors" , [](mlir::Attribute attr) {
2593+ auto ctorAttr = mlir::cast<cir::GlobalCtorAttr>(attr);
2594+ return std::make_pair (ctorAttr.getName (),
2595+ ctorAttr.getPriority ());
2596+ });
25222597}
25232598
25242599mlir::LogicalResult CIRToLLVMBrOpLowering::matchAndRewrite (
0 commit comments