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
11 changes: 11 additions & 0 deletions clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return createBitcast(src, getPointerTo(newPointeeTy));
}

mlir::Value createPtrIsNull(mlir::Value ptr) {
mlir::Value nullPtr = getNullPtr(ptr.getType(), ptr.getLoc());
return createCompare(ptr.getLoc(), cir::CmpOpKind::eq, ptr, nullPtr);
}

//===--------------------------------------------------------------------===//
// Binary Operators
//===--------------------------------------------------------------------===//
Expand Down Expand Up @@ -644,6 +649,12 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return getI64IntegerAttr(size.getQuantity());
}

// Creates constant nullptr for pointer type ty.
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) {
assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer());
return cir::ConstantOp::create(*this, loc, getConstPtrAttr(ty, 0));
}

/// Create a loop condition.
cir::ConditionOp createCondition(mlir::Value condition) {
return cir::ConditionOp::create(*this, condition.getLoc(), condition);
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ struct MissingFeatures {
static bool opFuncReadOnly() { return false; }
static bool opFuncSection() { return false; }
static bool opFuncWillReturn() { return false; }
static bool opFuncNoReturn() { return false; }
static bool setLLVMFunctionFEnvAttributes() { return false; }
static bool setFunctionAttributes() { return false; }

Expand Down Expand Up @@ -256,6 +257,8 @@ struct MissingFeatures {
static bool loopInfoStack() { return false; }
static bool lowerAggregateLoadStore() { return false; }
static bool lowerModeOptLevel() { return false; }
static bool loweringPrepareX86CXXABI() { return false; }
static bool loweringPrepareAArch64XXABI() { return false; }
static bool maybeHandleStaticInExternC() { return false; }
static bool mergeAllConstants() { return false; }
static bool metaDataNode() { return false; }
Expand Down
6 changes: 0 additions & 6 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return cir::ConstantOp::create(*this, loc, cir::IntAttr::get(sInt64Ty, c));
}

// Creates constant nullptr for pointer type ty.
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) {
assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer());
return cir::ConstantOp::create(*this, loc, getConstPtrAttr(ty, 0));
}

mlir::Value createNeg(mlir::Value value) {

if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ add_clang_library(MLIRCIRTransforms
FlattenCFG.cpp
HoistAllocas.cpp
LoweringPrepare.cpp
LoweringPrepareItaniumCXXABI.cpp
GotoSolver.cpp

DEPENDS
Expand Down
41 changes: 38 additions & 3 deletions clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//

#include "LoweringPrepareCXXABI.h"
#include "PassDetail.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/Module.h"
Expand Down Expand Up @@ -62,6 +63,7 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
void lowerComplexMulOp(cir::ComplexMulOp op);
void lowerUnaryOp(cir::UnaryOp op);
void lowerGlobalOp(cir::GlobalOp op);
void lowerDynamicCastOp(cir::DynamicCastOp op);
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);

Expand Down Expand Up @@ -91,6 +93,9 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {

clang::ASTContext *astCtx;

// Helper for lowering C++ ABI specific operations.
std::shared_ptr<cir::LoweringPrepareCXXABI> cxxABI;

/// Tracks current module.
mlir::ModuleOp mlirModule;

Expand All @@ -101,7 +106,24 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
/// List of ctors and their priorities to be called before main()
llvm::SmallVector<std::pair<std::string, uint32_t>, 4> globalCtorList;

void setASTContext(clang::ASTContext *c) { astCtx = c; }
void setASTContext(clang::ASTContext *c) {
astCtx = c;
switch (c->getCXXABIKind()) {
case clang::TargetCXXABI::GenericItanium:
// We'll need X86-specific support for handling vaargs lowering, but for
// now the Itanium ABI will work.
assert(!cir::MissingFeatures::loweringPrepareX86CXXABI());
cxxABI.reset(cir::LoweringPrepareCXXABI::createItaniumABI());
break;
case clang::TargetCXXABI::GenericAArch64:
case clang::TargetCXXABI::AppleARM64:
assert(!cir::MissingFeatures::loweringPrepareAArch64XXABI());
cxxABI.reset(cir::LoweringPrepareCXXABI::createItaniumABI());
break;
default:
llvm_unreachable("NYI");
}
}
};

} // namespace
Expand Down Expand Up @@ -850,6 +872,17 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() {
cir::ReturnOp::create(builder, f.getLoc());
}

void LoweringPreparePass::lowerDynamicCastOp(DynamicCastOp op) {
CIRBaseBuilderTy builder(getContext());
builder.setInsertionPointAfter(op);

assert(astCtx && "AST context is not available during lowering prepare");
auto loweredValue = cxxABI->lowerDynamicCast(builder, *astCtx, op);

op.replaceAllUsesWith(loweredValue);
op.erase();
}

static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder,
clang::ASTContext *astCtx,
mlir::Operation *op, mlir::Type eltTy,
Expand Down Expand Up @@ -954,6 +987,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
lowerComplexMulOp(complexMul);
else if (auto glob = mlir::dyn_cast<cir::GlobalOp>(op))
lowerGlobalOp(glob);
else if (auto dynamicCast = mlir::dyn_cast<cir::DynamicCastOp>(op))
lowerDynamicCastOp(dynamicCast);
else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op))
lowerUnaryOp(unary);
}
Expand All @@ -967,8 +1002,8 @@ void LoweringPreparePass::runOnOperation() {

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

Expand Down
38 changes: 38 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/LoweringPrepareCXXABI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides the LoweringPrepareCXXABI class, which is the base class
// for ABI specific functionalities that are required during LLVM lowering
// prepare.
//
//===----------------------------------------------------------------------===//

#ifndef CIR_DIALECT_TRANSFORMS__LOWERINGPREPARECXXABI_H
#define CIR_DIALECT_TRANSFORMS__LOWERINGPREPARECXXABI_H

#include "mlir/IR/Value.h"
#include "clang/AST/ASTContext.h"
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"

namespace cir {

class LoweringPrepareCXXABI {
public:
static LoweringPrepareCXXABI *createItaniumABI();

virtual ~LoweringPrepareCXXABI() {}

virtual mlir::Value lowerDynamicCast(CIRBaseBuilderTy &builder,
clang::ASTContext &astCtx,
cir::DynamicCastOp op) = 0;
};

} // namespace cir

#endif // CIR_DIALECT_TRANSFORMS__LOWERINGPREPARECXXABI_H
126 changes: 126 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//===--------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with
// LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===--------------------------------------------------------------------===//
//
// This file provides Itanium C++ ABI specific code
// that is used during LLVMIR lowering prepare.
//
//===--------------------------------------------------------------------===//

#include "LoweringPrepareCXXABI.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/Value.h"
#include "mlir/IR/ValueRange.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/MissingFeatures.h"

class LoweringPrepareItaniumCXXABI : public cir::LoweringPrepareCXXABI {
public:
mlir::Value lowerDynamicCast(cir::CIRBaseBuilderTy &builder,
clang::ASTContext &astCtx,
cir::DynamicCastOp op) override;
};

cir::LoweringPrepareCXXABI *cir::LoweringPrepareCXXABI::createItaniumABI() {
return new LoweringPrepareItaniumCXXABI();
}

static void buildBadCastCall(cir::CIRBaseBuilderTy &builder, mlir::Location loc,
mlir::FlatSymbolRefAttr badCastFuncRef) {
builder.createCallOp(loc, badCastFuncRef, cir::VoidType(),
mlir::ValueRange{});
// TODO(cir): Set the 'noreturn' attribute on the function.
assert(!cir::MissingFeatures::opFuncNoReturn());
cir::UnreachableOp::create(builder, loc);
builder.clearInsertionPoint();
}

static mlir::Value
buildDynamicCastAfterNullCheck(cir::CIRBaseBuilderTy &builder,
cir::DynamicCastOp op) {
mlir::Location loc = op->getLoc();
mlir::Value srcValue = op.getSrc();
cir::DynamicCastInfoAttr castInfo = op.getInfo().value();

// TODO(cir): consider address space
assert(!cir::MissingFeatures::addressSpace());

mlir::Value srcPtr = builder.createBitcast(srcValue, builder.getVoidPtrTy());
cir::ConstantOp srcRtti = builder.getConstant(loc, castInfo.getSrcRtti());
cir::ConstantOp destRtti = builder.getConstant(loc, castInfo.getDestRtti());
cir::ConstantOp offsetHint =
builder.getConstant(loc, castInfo.getOffsetHint());

mlir::FlatSymbolRefAttr dynCastFuncRef = castInfo.getRuntimeFunc();
mlir::Value dynCastFuncArgs[4] = {srcPtr, srcRtti, destRtti, offsetHint};

mlir::Value castedPtr =
builder
.createCallOp(loc, dynCastFuncRef, builder.getVoidPtrTy(),
dynCastFuncArgs)
.getResult();

assert(mlir::isa<cir::PointerType>(castedPtr.getType()) &&
"the return value of __dynamic_cast should be a ptr");

/// C++ [expr.dynamic.cast]p9:
/// A failed cast to reference type throws std::bad_cast
if (op.isRefCast()) {
// Emit a cir.if that checks the casted value.
mlir::Value castedValueIsNull = builder.createPtrIsNull(castedPtr);
builder.create<cir::IfOp>(
loc, castedValueIsNull, false, [&](mlir::OpBuilder &, mlir::Location) {
buildBadCastCall(builder, loc, castInfo.getBadCastFunc());
});
}

// Note that castedPtr is a void*. Cast it to a pointer to the destination
// type before return.
return builder.createBitcast(castedPtr, op.getType());
}

static mlir::Value
buildDynamicCastToVoidAfterNullCheck(cir::CIRBaseBuilderTy &builder,
clang::ASTContext &astCtx,
cir::DynamicCastOp op) {
llvm_unreachable("dynamic cast to void is NYI");
}

mlir::Value
LoweringPrepareItaniumCXXABI::lowerDynamicCast(cir::CIRBaseBuilderTy &builder,
clang::ASTContext &astCtx,
cir::DynamicCastOp op) {
mlir::Location loc = op->getLoc();
mlir::Value srcValue = op.getSrc();

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

if (op.isRefCast())
return buildDynamicCastAfterNullCheck(builder, op);

mlir::Value srcValueIsNotNull = builder.createPtrToBoolCast(srcValue);
return builder
.create<cir::TernaryOp>(
loc, srcValueIsNotNull,
[&](mlir::OpBuilder &, mlir::Location) {
mlir::Value castedValue =
op.isCastToVoid()
? buildDynamicCastToVoidAfterNullCheck(builder, astCtx, op)
: buildDynamicCastAfterNullCheck(builder, op);
builder.createYield(loc, castedValue);
},
[&](mlir::OpBuilder &, mlir::Location) {
builder.createYield(
loc, builder.getNullPtr(op.getType(), loc).getResult());
})
.getResult();
}
2 changes: 1 addition & 1 deletion clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1739,7 +1739,6 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());
const StringRef symbol = op.getSymName();
SmallVector<mlir::NamedAttribute> attributes;
mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);

if (init.has_value()) {
if (mlir::isa<cir::FPAttr, cir::IntAttr, cir::BoolAttr>(init.value())) {
Expand Down Expand Up @@ -1771,6 +1770,7 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
}

// Rewrite op.
mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);
auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(
op, llvmType, isConst, linkage, symbol, init.value_or(mlir::Attribute()),
alignment, addrSpace, isDsoLocal, isThreadLocal, comdatAttr, attributes);
Expand Down
Loading