Skip to content

Commit

Permalink
[CIR][Lowering] Emit llvm.global_ctors list
Browse files Browse the repository at this point in the history
  • Loading branch information
htyu committed Aug 17, 2023
1 parent f318211 commit e6eaacf
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 2 deletions.
14 changes: 14 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -452,4 +452,18 @@ def OptNoneAttr : CIRUnitAttr<"OptNone", "optnone"> {
let storageType = [{ OptNoneAttr }];
}

def GlobalCtorAttr : CIR_Attr<"GlobalCtor", "globalCtor"> {
let summary = "Indicates a function is a global constructor.";
let description = [{
Describing a global constructor with a priority.
}];
let parameters = (ins "int":$value);
let assemblyFormat = [{
`<` $value `>`
}];

let extraClassDeclaration = [{
int getPriority() const { return getValue(); }
}];
}
#endif // MLIR_CIR_DIALECT_CIR_ATTRS
4 changes: 4 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() {
mlir::SymbolTable::setSymbolVisibility(
f, mlir::SymbolTable::Visibility::Private);
mlir::NamedAttrList attrs;
// 65535 is the default priority, i.e, the lowest priority.
// TODO: handle globals with a user-specified initialzation priority.
auto ctorAttr = mlir::cir::GlobalCtorAttr::get(builder.getContext(), 65535);
attrs.set(ctorAttr.getMnemonic(), ctorAttr);
f.setExtraAttrsAttr(mlir::cir::ExtraFuncAttributesAttr::get(
builder.getContext(), attrs.getDictionary(builder.getContext())));

Expand Down
75 changes: 75 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1792,6 +1792,78 @@ mlir::LLVMTypeConverter prepareTypeConverter(mlir::MLIRContext *ctx) {
}
} // namespace

static void buildCtorList(mlir::ModuleOp module) {
llvm::SmallVector<std::pair<mlir::LLVM::LLVMFuncOp, int>, 2> globalCtors;
for (auto fn : module.getBodyRegion().getOps<mlir::LLVM::LLVMFuncOp>()) {
for (auto fnAttr : fn->getAttrs()) {
if (auto extraAttr =
fnAttr.getValue()
.dyn_cast<mlir::cir::ExtraFuncAttributesAttr>()) {
for (auto attr : extraAttr.getElements()) {
if (auto ctorAttr = attr.getValue().dyn_cast<mlir::cir::GlobalCtorAttr>()) {
globalCtors.emplace_back(fn, ctorAttr.getPriority());
break;
}
}
break;
}
}
}

if (globalCtors.empty())
return;

mlir::OpBuilder builder(module.getContext());
builder.setInsertionPointToEnd(&module.getBodyRegion().back());

// Create a global array llvm.global_ctors with element type of
// struct { i32, ptr, ptr }
auto CtorPFTy = mlir::LLVM::LLVMPointerType::get(builder.getContext());
llvm::SmallVector<mlir::Type> CtorStructFields;
CtorStructFields.push_back(builder.getI32Type());
CtorStructFields.push_back(CtorPFTy);
CtorStructFields.push_back(CtorPFTy);

auto CtorStructTy = mlir::LLVM::LLVMStructType::getLiteral(
builder.getContext(), CtorStructFields);
auto CtorStructArrayTy =
mlir::LLVM::LLVMArrayType::get(CtorStructTy, globalCtors.size());

auto loc = module.getLoc();
auto newGlobalOp = builder.create<mlir::LLVM::GlobalOp>(
loc, CtorStructArrayTy, true, mlir::LLVM::Linkage::Appending,
"llvm.global_ctors", mlir::Attribute());

newGlobalOp.getRegion().push_back(new mlir::Block());
builder.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());

mlir::Value result = builder.create<mlir::LLVM::UndefOp>(
loc, CtorStructArrayTy);

for (uint64_t I = 0; I < globalCtors.size(); I++) {
auto fn = globalCtors[I];
mlir::Value structInit =
builder.create<mlir::LLVM::UndefOp>(loc, CtorStructTy);
mlir::Value initPriority =
builder.create<mlir::LLVM::ConstantOp>(loc, CtorStructFields[0], fn.second);
mlir::Value initFuncAddr = builder.create<mlir::LLVM::AddressOfOp>(
loc, CtorStructFields[1], fn.first.getName());
mlir::Value initAssociate =
builder.create<mlir::LLVM::NullOp>(loc, CtorStructFields[2]);
structInit = builder.create<mlir::LLVM::InsertValueOp>(loc, structInit,
initPriority, 0);
structInit = builder.create<mlir::LLVM::InsertValueOp>(loc, structInit,
initFuncAddr, 1);
// TODO: hanlde associated data for initializers.
structInit = builder.create<mlir::LLVM::InsertValueOp>(loc, structInit,
initAssociate, 2);
result =
builder.create<mlir::LLVM::InsertValueOp>(loc, result, structInit, I);
}

builder.create<mlir::LLVM::ReturnOp>(loc, result);
}

void ConvertCIRToLLVMPass::runOnOperation() {
auto module = getOperation();

Expand Down Expand Up @@ -1830,6 +1902,9 @@ void ConvertCIRToLLVMPass::runOnOperation() {

if (failed(applyPartialConversion(module, target, std::move(patterns))))
signalPassFailure();

// Emit the llvm.global_ctors array.
buildCtorList(module);
}

std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CIR/CodeGen/static.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ static Init __ioinit2(false);
// AFTER-NEXT: %1 = cir.const(#false) : !cir.bool
// AFTER-NEXT: cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
// AFTER-NEXT: cir.return
// AFTER: cir.func private @_GLOBAL__sub_I_static.cpp()
// AFTER: cir.func private @_GLOBAL__sub_I_static.cpp() extra( {globalCtor = #cir.globalCtor<65535>} )
// AFTER-NEXT: cir.call @__cxx_global_var_init() : () -> ()
// AFTER-NEXT: cir.call @__cxx_global_var_init.1() : () -> ()
// AFTER-NEXT: cir.return


// LLVM: @_ZL8__ioinit = internal global %class.Init zeroinitializer
// LLVM: @_ZL9__ioinit2 = internal global %class.Init zeroinitializer
// LLVM: @llvm.global_ctors = appending constant [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_static.cpp, ptr null }]
// LLVM: define internal void @__cxx_global_var_init()
// LLVM-NEXT: call void @_ZN4InitC1Eb(ptr @_ZL8__ioinit, i8 1)
// LLVM-NEXT: ret void
Expand Down
26 changes: 26 additions & 0 deletions clang/test/CIR/Lowering/globals.cir
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// RUN: cir-translate %s -cir-to-llvmir -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM

#false = #cir.bool<false> : !cir.bool
!s16i = !cir.int<s, 16>
!s32i = !cir.int<s, 32>
!s64i = !cir.int<s, 64>
Expand All @@ -11,6 +12,8 @@
!u64i = !cir.int<u, 64>
!u8i = !cir.int<u, 8>
!ty_22struct2EA22 = !cir.struct<"struct.A", !s32i, !cir.array<!cir.array<!s32i x 2> x 2>, #cir.recdecl.ast>
!ty_22class2EInit22 = !cir.struct<"class.Init", !u8i>


module {
cir.global external @a = #cir.int<3> : !s32i
Expand Down Expand Up @@ -134,4 +137,27 @@ module {
// MLIR: llvm.mlir.global external @zeroInitFlt(dense<0.000000e+00> : tensor<2xf32>) {addr_space = 0 : i32} : !llvm.array<2 x f32>
cir.global "private" internal @staticVar = #cir.int<0> : !s32i
// MLIR: llvm.mlir.global internal @staticVar(0 : i32) {addr_space = 0 : i32} : i32
cir.func private @_ZN4InitC1Eb(!cir.ptr<!ty_22class2EInit22>, !cir.bool) extra( {inline = #cir.inline<no>} )
cir.global "private" internal @_ZL9__ioinit2 = #cir.zero : !ty_22class2EInit22
cir.func internal private @__cxx_global_var_init() {
%0 = cir.get_global @_ZL9__ioinit2 : cir.ptr <!ty_22class2EInit22>
%1 = cir.const(#false) : !cir.bool
cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
cir.return
}
cir.func private @_GLOBAL__sub_I_static.cpp() extra( {globalCtor = #cir.globalCtor<65535>} ){
cir.call @__cxx_global_var_init() : () -> ()
cir.return
}
// MLIR: llvm.mlir.global appending constant @llvm.global_ctors() {addr_space = 0 : i32} : !llvm.array<1 x struct<(i32, ptr, ptr)>>
// MLIR-NEXT: %0 = llvm.mlir.undef : !llvm.array<1 x struct<(i32, ptr, ptr)>>
// MLIR-NEXT: %1 = llvm.mlir.undef : !llvm.struct<(i32, ptr, ptr)>
// MLIR-NEXT: %2 = llvm.mlir.constant(65535 : i32) : i32
// MLIR-NEXT: %3 = llvm.mlir.addressof @_GLOBAL__sub_I_static.cpp : !llvm.ptr
// MLIR-NEXT: %4 = llvm.mlir.null : !llvm.ptr
// MLIR-NEXT: %5 = llvm.insertvalue %2, %1[0] : !llvm.struct<(i32, ptr, ptr)>
// MLIR-NEXT: %6 = llvm.insertvalue %3, %5[1] : !llvm.struct<(i32, ptr, ptr)>
// MLIR-NEXT: %7 = llvm.insertvalue %4, %6[2] : !llvm.struct<(i32, ptr, ptr)>
// MLIR-NEXT: %8 = llvm.insertvalue %7, %0[0] : !llvm.array<1 x struct<(i32, ptr, ptr)>>
// MLIR-NEXT: llvm.return %8 : !llvm.array<1 x struct<(i32, ptr, ptr)>>
}

0 comments on commit e6eaacf

Please sign in to comment.