Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
cir::ConstantOp getTrue(mlir::Location loc) { return getBool(true, loc); }

cir::BoolType getBoolTy() { return cir::BoolType::get(getContext()); }
cir::VoidType getVoidTy() { return cir::VoidType::get(getContext()); }

cir::PointerType getPointerTo(mlir::Type ty) {
return cir::PointerType::get(ty);
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ struct MissingFeatures {
static bool opGlobalDLLImportExport() { return false; }
static bool opGlobalPartition() { return false; }
static bool opGlobalUsedOrCompilerUsed() { return false; }
static bool opGlobalAnnotations() { return false; }
static bool opGlobalDtorLowering() { return false; }
static bool opGlobalCtorAttr() { return false; }
static bool opGlobalCtorPriority() { return false; }
static bool opGlobalCtorList() { return false; }
static bool setDSOLocal() { return false; }
static bool setComdat() { return false; }

Expand Down
144 changes: 143 additions & 1 deletion clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,39 @@

#include "PassDetail.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Dialect/Passes.h"
#include "clang/CIR/MissingFeatures.h"
#include "llvm/Support/Path.h"

#include <memory>

using namespace mlir;
using namespace cir;

static SmallString<128> getTransformedFileName(mlir::ModuleOp mlirModule) {
SmallString<128> fileName;

if (mlirModule.getSymName())
fileName = llvm::sys::path::filename(mlirModule.getSymName()->str());

if (fileName.empty())
fileName = "<null>";

for (size_t i = 0; i < fileName.size(); ++i) {
// Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
// to be the set of C preprocessing numbers.
if (!clang::isPreprocessingNumberBody(fileName[i]))
fileName[i] = '_';
}

return fileName;
}

namespace {
struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
LoweringPreparePass() = default;
Expand All @@ -30,9 +51,16 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
void lowerComplexDivOp(cir::ComplexDivOp op);
void lowerComplexMulOp(cir::ComplexMulOp op);
void lowerUnaryOp(cir::UnaryOp op);
void lowerGlobalOp(cir::GlobalOp op);
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);

/// Build the function that initializes the specified global
cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);

/// Build a module init function that calls all the dynamic initializers.
void buildCXXGlobalInitFunc();

cir::FuncOp buildRuntimeFunction(
mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
cir::FuncType type,
Expand All @@ -47,6 +75,10 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
/// Tracks current module.
mlir::ModuleOp mlirModule;

/// Tracks existing dynamic initializers.
llvm::StringMap<uint32_t> dynamicInitializerNames;
llvm::SmallVector<cir::FuncOp> dynamicInitializers;

void setASTContext(clang::ASTContext *c) { astCtx = c; }
};

Expand Down Expand Up @@ -589,6 +621,111 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
op.erase();
}

cir::FuncOp
LoweringPreparePass::buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op) {
// TODO(cir): Store this in the GlobalOp.
// This should come from the MangleContext, but for now I'm hardcoding it.
SmallString<256> fnName("__cxx_global_var_init");
// Get a unique name
uint32_t cnt = dynamicInitializerNames[fnName]++;
if (cnt)
fnName += "." + llvm::Twine(cnt).str();

// Create a variable initialization function.
CIRBaseBuilderTy builder(getContext());
builder.setInsertionPointAfter(op);
auto fnType = cir::FuncType::get({}, builder.getVoidTy());
FuncOp f = buildRuntimeFunction(builder, fnName, op.getLoc(), fnType,
cir::GlobalLinkageKind::InternalLinkage);

// Move over the initialzation code of the ctor region.
mlir::Block *entryBB = f.addEntryBlock();
if (!op.getCtorRegion().empty()) {
mlir::Block &block = op.getCtorRegion().front();
entryBB->getOperations().splice(entryBB->begin(), block.getOperations(),
block.begin(), std::prev(block.end()));
}

// Register the destructor call with __cxa_atexit
mlir::Region &dtorRegion = op.getDtorRegion();
if (!dtorRegion.empty()) {
assert(!cir::MissingFeatures::opGlobalDtorLowering());
llvm_unreachable("dtor region lowering is NYI");
}

// Replace cir.yield with cir.return
builder.setInsertionPointToEnd(entryBB);
mlir::Operation *yieldOp = nullptr;
if (!op.getCtorRegion().empty()) {
mlir::Block &block = op.getCtorRegion().front();
yieldOp = &block.getOperations().back();
} else {
assert(!cir::MissingFeatures::opGlobalDtorLowering());
llvm_unreachable("dtor region lowering is NYI");
}

assert(isa<YieldOp>(*yieldOp));
cir::ReturnOp::create(builder, yieldOp->getLoc());
return f;
}

void LoweringPreparePass::lowerGlobalOp(GlobalOp op) {
mlir::Region &ctorRegion = op.getCtorRegion();
mlir::Region &dtorRegion = op.getDtorRegion();

if (!ctorRegion.empty() || !dtorRegion.empty()) {
// Build a variable initialization function and move the initialzation code
// in the ctor region over.
cir::FuncOp f = buildCXXGlobalVarDeclInitFunc(op);

// Clear the ctor and dtor region
ctorRegion.getBlocks().clear();
dtorRegion.getBlocks().clear();

assert(!cir::MissingFeatures::astVarDeclInterface());
dynamicInitializers.push_back(f);
}

assert(!cir::MissingFeatures::opGlobalAnnotations());
}

void LoweringPreparePass::buildCXXGlobalInitFunc() {
if (dynamicInitializers.empty())
return;

assert(!cir::MissingFeatures::opGlobalCtorList());

SmallString<256> fnName;
// Include the filename in the symbol name. Including "sub_" matches gcc
// and makes sure these symbols appear lexicographically behind the symbols
// with priority (TBD). Module implementation units behave the same
// way as a non-modular TU with imports.
// TODO: check CXX20ModuleInits
if (astCtx->getCurrentNamedModule() &&
!astCtx->getCurrentNamedModule()->isModuleImplementation()) {
llvm::raw_svector_ostream out(fnName);
std::unique_ptr<clang::MangleContext> mangleCtx(
astCtx->createMangleContext());
cast<clang::ItaniumMangleContext>(*mangleCtx)
.mangleModuleInitializer(astCtx->getCurrentNamedModule(), out);
} else {
fnName += "_GLOBAL__sub_I_";
fnName += getTransformedFileName(mlirModule);
}

CIRBaseBuilderTy builder(getContext());
builder.setInsertionPointToEnd(&mlirModule.getBodyRegion().back());
auto fnType = cir::FuncType::get({}, builder.getVoidTy());
cir::FuncOp f =
buildRuntimeFunction(builder, fnName, mlirModule.getLoc(), fnType,
cir::GlobalLinkageKind::ExternalLinkage);
builder.setInsertionPointToStart(f.addEntryBlock());
for (cir::FuncOp &f : dynamicInitializers)
builder.createCallOp(f.getLoc(), f, {});

cir::ReturnOp::create(builder, f.getLoc());
}

static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder,
clang::ASTContext *astCtx,
mlir::Operation *op, mlir::Type eltTy,
Expand Down Expand Up @@ -691,6 +828,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
lowerComplexDivOp(complexDiv);
else if (auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op))
lowerComplexMulOp(complexMul);
else if (auto glob = mlir::dyn_cast<cir::GlobalOp>(op))
lowerGlobalOp(glob);
else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op))
lowerUnaryOp(unary);
}
Expand All @@ -704,12 +843,15 @@ void LoweringPreparePass::runOnOperation() {

op->walk([&](mlir::Operation *op) {
if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
cir::ComplexMulOp, cir::ComplexDivOp, cir::UnaryOp>(op))
cir::ComplexMulOp, cir::ComplexDivOp, cir::GlobalOp,
cir::UnaryOp>(op))
opsToTransform.push_back(op);
});

for (mlir::Operation *o : opsToTransform)
runOnOp(o);

buildCXXGlobalInitFunc();
}

std::unique_ptr<Pass> mlir::createLoweringPreparePass() {
Expand Down
23 changes: 16 additions & 7 deletions clang/test/CIR/CodeGen/global-init.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir
// RUN: FileCheck --input-file=%t-before.cir %s --check-prefix=CIR-BEFORE-LPP
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR

// Note: The CIR generated from this test isn't ready for lowering to LLVM yet.
// That will require changes to LoweringPrepare.
// Note: The LoweringPrepare work isn't yet complete. We still need to create
// the global ctor list attribute.

struct NeedsCtor {
NeedsCtor();
};

NeedsCtor needsCtor;

// CIR: cir.func private @_ZN9NeedsCtorC1Ev(!cir.ptr<!rec_NeedsCtor>)
// CIR: cir.global external @needsCtor = ctor : !rec_NeedsCtor {
// CIR: %[[THIS:.*]] = cir.get_global @needsCtor : !cir.ptr<!rec_NeedsCtor>
// CIR: cir.call @_ZN9NeedsCtorC1Ev(%[[THIS]]) : (!cir.ptr<!rec_NeedsCtor>) -> ()
// CIR-BEFORE-LPP: cir.global external @needsCtor = ctor : !rec_NeedsCtor {
// CIR-BEFORE-LPP: %[[THIS:.*]] = cir.get_global @needsCtor : !cir.ptr<!rec_NeedsCtor>
// CIR-BEFORE-LPP: cir.call @_ZN9NeedsCtorC1Ev(%[[THIS]]) : (!cir.ptr<!rec_NeedsCtor>) -> ()

// CIR: cir.global external @needsCtor = #cir.zero : !rec_NeedsCtor
// CIR: cir.func internal private @__cxx_global_var_init() {
// CIR: %0 = cir.get_global @needsCtor : !cir.ptr<!rec_NeedsCtor>
// CIR: cir.call @_ZN9NeedsCtorC1Ev(%0) : (!cir.ptr<!rec_NeedsCtor>) -> ()

// CIR: cir.func private @_GLOBAL__sub_I_[[FILENAME:.*]]() {
// CIR: cir.call @__cxx_global_var_init() : () -> ()
// CIR: cir.return
// CIR: }
Loading