mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 02:38:07 +08:00
[CIR] Add basic support for data member pointers (#170939)
This adds the minimum support for C++ data member pointer variables.
This commit is contained in:
@@ -35,6 +35,7 @@ namespace cir {
|
||||
class ArrayType;
|
||||
class BoolType;
|
||||
class ComplexType;
|
||||
class DataMemberType;
|
||||
class IntType;
|
||||
class MethodType;
|
||||
class PointerType;
|
||||
|
||||
@@ -447,6 +447,57 @@ def CIR_ConstPtrAttr : CIR_Attr<"ConstPtr", "ptr", [TypedAttrInterface]> {
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DataMemberAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_DataMemberAttr : CIR_Attr<"DataMember", "data_member", [
|
||||
TypedAttrInterface
|
||||
]> {
|
||||
let summary = "Holds a constant data member pointer value";
|
||||
let parameters = (ins AttributeSelfTypeParameter<
|
||||
"", "cir::DataMemberType">:$type,
|
||||
OptionalParameter<
|
||||
"std::optional<unsigned>">:$member_index);
|
||||
let description = [{
|
||||
A data member attribute is a literal attribute that represents a constant
|
||||
pointer-to-data-member value.
|
||||
|
||||
The `member_index` parameter represents the index of the pointed-to member
|
||||
within its containing record. It is an optional parameter; lack of this
|
||||
parameter indicates a null pointer-to-data-member value.
|
||||
|
||||
Example:
|
||||
```
|
||||
#ptr = #cir.data_member<1> : !cir.data_member<!s32i in !rec_22Point22>
|
||||
|
||||
#null = #cir.data_member<null> : !cir.data_member<!s32i in !rec_22Point22>
|
||||
```
|
||||
}];
|
||||
|
||||
let builders = [
|
||||
AttrBuilderWithInferredContext<(ins "cir::DataMemberType":$type), [{
|
||||
return $_get(type.getContext(), type, std::nullopt);
|
||||
}]>,
|
||||
AttrBuilderWithInferredContext<(ins "cir::DataMemberType":$type,
|
||||
"unsigned":$member_index), [{
|
||||
return $_get(type.getContext(), type, member_index);
|
||||
}]>,
|
||||
];
|
||||
|
||||
let genVerifyDecl = 1;
|
||||
|
||||
let assemblyFormat = [{
|
||||
`<` ($member_index^):(`null`)? `>`
|
||||
}];
|
||||
|
||||
let extraClassDeclaration = [{
|
||||
bool isNullPtr() const {
|
||||
return !getMemberIndex().has_value();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GlobalViewAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -309,6 +309,13 @@ def CIR_AnyFloatOrVecOfFloatType
|
||||
let cppFunctionName = "isFPOrVectorOfFPType";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Data member type predicates
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_AnyDataMemberType : CIR_TypeBase<"::cir::DataMemberType",
|
||||
"data member type">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// VPtr type predicates
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -322,7 +329,8 @@ def CIR_PtrToVPtr : CIR_PtrToType<CIR_AnyVPtrType>;
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
defvar CIR_ScalarTypes = [
|
||||
CIR_AnyBoolType, CIR_AnyIntType, CIR_AnyFloatType, CIR_AnyPtrType
|
||||
CIR_AnyBoolType, CIR_AnyIntType, CIR_AnyFloatType, CIR_AnyPtrType,
|
||||
CIR_AnyDataMemberType, CIR_AnyVPtrType
|
||||
];
|
||||
|
||||
def CIR_AnyScalarType : AnyTypeOf<CIR_ScalarTypes, "cir scalar type"> {
|
||||
|
||||
@@ -305,6 +305,36 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CIR_DataMemberType
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_DataMemberType : CIR_Type<"DataMember", "data_member",
|
||||
[DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]
|
||||
> {
|
||||
let summary = "CIR type that represents a pointer-to-data-member in C++";
|
||||
let description = [{
|
||||
`cir.data_member` models a pointer-to-data-member in C++. Values of this
|
||||
type are essentially offsets of the pointed-to member within one of its
|
||||
containing record.
|
||||
}];
|
||||
|
||||
let parameters = (ins "mlir::Type":$member_ty,
|
||||
"cir::RecordType":$class_ty);
|
||||
|
||||
let builders = [
|
||||
TypeBuilderWithInferredContext<(ins
|
||||
"mlir::Type":$member_ty, "cir::RecordType":$class_ty
|
||||
), [{
|
||||
return $_get(member_ty.getContext(), member_ty, class_ty);
|
||||
}]>,
|
||||
];
|
||||
|
||||
let assemblyFormat = [{
|
||||
`<` $member_ty `in` $class_ty `>`
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CIR_VPtrType
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -693,7 +723,7 @@ def CIRRecordType : Type<
|
||||
def CIR_AnyType : AnyTypeOf<[
|
||||
CIR_VoidType, CIR_BoolType, CIR_ArrayType, CIR_VectorType, CIR_IntType,
|
||||
CIR_AnyFloatType, CIR_PointerType, CIR_FuncType, CIR_RecordType,
|
||||
CIR_ComplexType, CIR_VPtrType
|
||||
CIR_ComplexType, CIR_VPtrType, CIR_DataMemberType
|
||||
]>;
|
||||
|
||||
#endif // CLANG_CIR_DIALECT_IR_CIRTYPES_TD
|
||||
|
||||
@@ -189,6 +189,10 @@ struct MissingFeatures {
|
||||
static bool globalCtorLexOrder() { return false; }
|
||||
static bool globalCtorAssociatedData() { return false; }
|
||||
|
||||
// LowerModule handling
|
||||
static bool lowerModuleCodeGenOpts() { return false; }
|
||||
static bool lowerModuleLangOpts() { return false; }
|
||||
|
||||
// Misc
|
||||
static bool aarch64SIMDIntrinsics() { return false; }
|
||||
static bool aarch64SMEIntrinsics() { return false; }
|
||||
@@ -292,6 +296,7 @@ struct MissingFeatures {
|
||||
static bool lowerModeOptLevel() { return false; }
|
||||
static bool loweringPrepareX86CXXABI() { return false; }
|
||||
static bool loweringPrepareAArch64XXABI() { return false; }
|
||||
static bool makeTripleAlwaysPresent() { return false; }
|
||||
static bool maybeHandleStaticInExternC() { return false; }
|
||||
static bool mergeAllConstants() { return false; }
|
||||
static bool metaDataNode() { return false; }
|
||||
|
||||
@@ -189,6 +189,11 @@ public:
|
||||
return getType<cir::RecordType>(nameAttr, kind);
|
||||
}
|
||||
|
||||
cir::DataMemberAttr getDataMemberAttr(cir::DataMemberType ty,
|
||||
unsigned memberIndex) {
|
||||
return cir::DataMemberAttr::get(ty, memberIndex);
|
||||
}
|
||||
|
||||
// Return true if the value is a null constant such as null pointer, (+0.0)
|
||||
// for floating-point or zero initializer
|
||||
bool isNullValue(mlir::Attribute attr) const {
|
||||
|
||||
@@ -731,11 +731,8 @@ public:
|
||||
}
|
||||
|
||||
mlir::Value VisitUnaryAddrOf(const UnaryOperator *e) {
|
||||
if (llvm::isa<MemberPointerType>(e->getType())) {
|
||||
cgf.cgm.errorNYI(e->getSourceRange(), "Address of member pointer");
|
||||
return builder.getNullPtr(cgf.convertType(e->getType()),
|
||||
cgf.getLoc(e->getExprLoc()));
|
||||
}
|
||||
if (llvm::isa<MemberPointerType>(e->getType()))
|
||||
return cgf.cgm.emitMemberPointerConstant(e);
|
||||
|
||||
return cgf.emitLValue(e->getSubExpr()).getPointer();
|
||||
}
|
||||
|
||||
@@ -1464,6 +1464,26 @@ void CIRGenModule::emitExplicitCastExprType(const ExplicitCastExpr *e,
|
||||
"emitExplicitCastExprType");
|
||||
}
|
||||
|
||||
mlir::Value CIRGenModule::emitMemberPointerConstant(const UnaryOperator *e) {
|
||||
assert(!cir::MissingFeatures::cxxABI());
|
||||
|
||||
mlir::Location loc = getLoc(e->getSourceRange());
|
||||
|
||||
const auto *decl = cast<DeclRefExpr>(e->getSubExpr())->getDecl();
|
||||
|
||||
// A member function pointer.
|
||||
if (isa<CXXMethodDecl>(decl)) {
|
||||
errorNYI(e->getSourceRange(), "emitMemberPointerConstant: method pointer");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Otherwise, a member data pointer.
|
||||
auto ty = mlir::cast<cir::DataMemberType>(convertType(e->getType()));
|
||||
const auto *fieldDecl = cast<FieldDecl>(decl);
|
||||
return cir::ConstantOp::create(
|
||||
builder, loc, builder.getDataMemberAttr(ty, fieldDecl->getFieldIndex()));
|
||||
}
|
||||
|
||||
void CIRGenModule::emitDeclContext(const DeclContext *dc) {
|
||||
for (Decl *decl : dc->decls()) {
|
||||
// Unlike other DeclContexts, the contents of an ObjCImplDecl at TU scope
|
||||
|
||||
@@ -497,6 +497,8 @@ public:
|
||||
/// the given type. This is usually, but not always, an LLVM null constant.
|
||||
mlir::TypedAttr emitNullConstantForBase(const CXXRecordDecl *record);
|
||||
|
||||
mlir::Value emitMemberPointerConstant(const UnaryOperator *e);
|
||||
|
||||
llvm::StringRef getMangledName(clang::GlobalDecl gd);
|
||||
|
||||
void emitTentativeDefinition(const VarDecl *d);
|
||||
|
||||
@@ -482,6 +482,21 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MemberPointer: {
|
||||
const auto *mpt = cast<MemberPointerType>(ty);
|
||||
|
||||
mlir::Type memberTy = convertType(mpt->getPointeeType());
|
||||
auto clsTy = mlir::cast<cir::RecordType>(
|
||||
convertType(QualType(mpt->getQualifier().getAsType(), 0)));
|
||||
if (mpt->isMemberDataPointer()) {
|
||||
resultType = cir::DataMemberType::get(memberTy, clsTy);
|
||||
} else {
|
||||
assert(!cir::MissingFeatures::methodType());
|
||||
cgm.errorNYI(SourceLocation(), "MethodType");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::FunctionNoProto:
|
||||
case Type::FunctionProto:
|
||||
resultType = convertFunctionTypeInternal(type);
|
||||
|
||||
@@ -269,6 +269,38 @@ ConstComplexAttr::verify(function_ref<InFlightDiagnostic()> emitError,
|
||||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DataMemberAttr definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
LogicalResult
|
||||
DataMemberAttr::verify(function_ref<InFlightDiagnostic()> emitError,
|
||||
cir::DataMemberType ty,
|
||||
std::optional<unsigned> memberIndex) {
|
||||
// DataMemberAttr without a given index represents a null value.
|
||||
if (!memberIndex.has_value())
|
||||
return success();
|
||||
|
||||
cir::RecordType recTy = ty.getClassTy();
|
||||
if (recTy.isIncomplete())
|
||||
return emitError()
|
||||
<< "incomplete 'cir.record' cannot be used to build a non-null "
|
||||
"data member pointer";
|
||||
|
||||
unsigned memberIndexValue = memberIndex.value();
|
||||
if (memberIndexValue >= recTy.getNumElements())
|
||||
return emitError()
|
||||
<< "member index of a #cir.data_member attribute is out of range";
|
||||
|
||||
mlir::Type memberTy = recTy.getMembers()[memberIndexValue];
|
||||
if (memberTy != ty.getMemberTy())
|
||||
return emitError()
|
||||
<< "member type of a #cir.data_member attribute must match the "
|
||||
"attribute type";
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CIR ConstArrayAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -357,6 +357,12 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
|
||||
return success();
|
||||
}
|
||||
|
||||
if (isa<cir::DataMemberAttr>(attrType)) {
|
||||
// More detailed type verifications are already done in
|
||||
// DataMemberAttr::verify. Don't need to repeat here.
|
||||
return success();
|
||||
}
|
||||
|
||||
if (isa<cir::ZeroAttr>(attrType)) {
|
||||
if (isa<cir::RecordType, cir::ArrayType, cir::VectorType, cir::ComplexType>(
|
||||
opType))
|
||||
|
||||
@@ -750,6 +750,26 @@ BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
|
||||
return 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DataMemberType Definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
llvm::TypeSize
|
||||
DataMemberType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
|
||||
::mlir::DataLayoutEntryListRef params) const {
|
||||
// FIXME: consider size differences under different ABIs
|
||||
assert(!MissingFeatures::cxxABI());
|
||||
return llvm::TypeSize::getFixed(64);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
DataMemberType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
|
||||
::mlir::DataLayoutEntryListRef params) const {
|
||||
// FIXME: consider alignment differences under different ABIs
|
||||
assert(!MissingFeatures::cxxABI());
|
||||
return 8;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// VPtrType Definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
add_subdirectory(TargetLowering)
|
||||
|
||||
add_clang_library(MLIRCIRTransforms
|
||||
CIRCanonicalize.cpp
|
||||
CIRSimplify.cpp
|
||||
@@ -21,4 +23,5 @@ add_clang_library(MLIRCIRTransforms
|
||||
|
||||
MLIRCIR
|
||||
MLIRCIRInterfaces
|
||||
MLIRCIRTargetLowering
|
||||
)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//===- CIRCXXABI.cpp ------------------------------------------------------===//
|
||||
//
|
||||
// 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 partially mimics clang/lib/CodeGen/CGCXXABI.cpp. The queries are
|
||||
// adapted to operate on the CIR dialect, however.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CIRCXXABI.h"
|
||||
|
||||
namespace cir {
|
||||
|
||||
CIRCXXABI::~CIRCXXABI() {}
|
||||
|
||||
} // namespace cir
|
||||
55
clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
Normal file
55
clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
Normal file
@@ -0,0 +1,55 @@
|
||||
//===----- CIRCXXABI.h - Interface to C++ ABIs for CIR Dialect --*- C++ -*-===//
|
||||
//
|
||||
// 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 partially mimics the CodeGen/CGCXXABI.h class. The main difference
|
||||
// is that this is adapted to operate on the CIR dialect.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRCXXABI_H
|
||||
#define CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRCXXABI_H
|
||||
|
||||
#include "mlir/Transforms/DialectConversion.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRTypes.h"
|
||||
|
||||
namespace cir {
|
||||
|
||||
// Forward declarations.
|
||||
class LowerModule;
|
||||
|
||||
class CIRCXXABI {
|
||||
friend class LowerModule;
|
||||
|
||||
protected:
|
||||
LowerModule &lm;
|
||||
|
||||
CIRCXXABI(LowerModule &lm) : lm(lm) {}
|
||||
|
||||
public:
|
||||
virtual ~CIRCXXABI();
|
||||
|
||||
/// Lower the given data member pointer type to its ABI type. The returned
|
||||
/// type is also a CIR type.
|
||||
virtual mlir::Type
|
||||
lowerDataMemberType(cir::DataMemberType type,
|
||||
const mlir::TypeConverter &typeConverter) const = 0;
|
||||
|
||||
/// Lower the given data member pointer constant to a constant of the ABI
|
||||
/// type. The returned constant is represented as an attribute as well.
|
||||
virtual mlir::TypedAttr
|
||||
lowerDataMemberConstant(cir::DataMemberAttr attr,
|
||||
const mlir::DataLayout &layout,
|
||||
const mlir::TypeConverter &typeConverter) const = 0;
|
||||
};
|
||||
|
||||
/// Creates an Itanium-family ABI.
|
||||
std::unique_ptr<CIRCXXABI> createItaniumCXXABI(LowerModule &lm);
|
||||
|
||||
} // namespace cir
|
||||
|
||||
#endif // CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRCXXABI_H
|
||||
@@ -0,0 +1,20 @@
|
||||
add_clang_library(MLIRCIRTargetLowering
|
||||
CIRCXXABI.cpp
|
||||
LowerModule.cpp
|
||||
LowerItaniumCXXABI.cpp
|
||||
|
||||
DEPENDS
|
||||
clangBasic
|
||||
|
||||
LINK_COMPONENTS
|
||||
TargetParser
|
||||
|
||||
LINK_LIBS PUBLIC
|
||||
|
||||
clangBasic
|
||||
MLIRIR
|
||||
MLIRPass
|
||||
MLIRDLTIDialect
|
||||
MLIRCIR
|
||||
MLIRCIRInterfaces
|
||||
)
|
||||
@@ -0,0 +1,90 @@
|
||||
//===---- LowerItaniumCXXABI.cpp - Emit CIR code Itanium-specific code ---===//
|
||||
//
|
||||
// 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 provides CIR lowering logic targeting the Itanium C++ ABI. The class in
|
||||
// this file generates records that follow the Itanium C++ ABI, which is
|
||||
// documented at:
|
||||
// https://itanium-cxx-abi.github.io/cxx-abi/abi.html
|
||||
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
|
||||
//
|
||||
// It also supports the closely-related ARM ABI, documented at:
|
||||
// https://developer.arm.com/documentation/ihi0041/g/
|
||||
//
|
||||
// This file partially mimics clang/lib/CodeGen/ItaniumCXXABI.cpp. The queries
|
||||
// are adapted to operate on the CIR dialect, however.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CIRCXXABI.h"
|
||||
#include "LowerModule.h"
|
||||
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
namespace cir {
|
||||
|
||||
namespace {
|
||||
|
||||
class LowerItaniumCXXABI : public CIRCXXABI {
|
||||
public:
|
||||
LowerItaniumCXXABI(LowerModule &lm) : CIRCXXABI(lm) {}
|
||||
|
||||
/// Lower the given data member pointer type to its ABI type. The returned
|
||||
/// type is also a CIR type.
|
||||
virtual mlir::Type
|
||||
lowerDataMemberType(cir::DataMemberType type,
|
||||
const mlir::TypeConverter &typeConverter) const override;
|
||||
|
||||
mlir::TypedAttr lowerDataMemberConstant(
|
||||
cir::DataMemberAttr attr, const mlir::DataLayout &layout,
|
||||
const mlir::TypeConverter &typeConverter) const override;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<CIRCXXABI> createItaniumCXXABI(LowerModule &lm) {
|
||||
return std::make_unique<LowerItaniumCXXABI>(lm);
|
||||
}
|
||||
|
||||
static cir::IntType getPtrDiffCIRTy(LowerModule &lm) {
|
||||
const clang::TargetInfo &target = lm.getTarget();
|
||||
clang::TargetInfo::IntType ptrdiffTy =
|
||||
target.getPtrDiffType(clang::LangAS::Default);
|
||||
return cir::IntType::get(lm.getMLIRContext(), target.getTypeWidth(ptrdiffTy),
|
||||
target.isTypeSigned(ptrdiffTy));
|
||||
}
|
||||
|
||||
mlir::Type LowerItaniumCXXABI::lowerDataMemberType(
|
||||
cir::DataMemberType type, const mlir::TypeConverter &typeConverter) const {
|
||||
// Itanium C++ ABI 2.3.1:
|
||||
// A data member pointer is represented as the data member's offset in bytes
|
||||
// from the address point of an object of the base type, as a ptrdiff_t.
|
||||
return getPtrDiffCIRTy(lm);
|
||||
}
|
||||
|
||||
mlir::TypedAttr LowerItaniumCXXABI::lowerDataMemberConstant(
|
||||
cir::DataMemberAttr attr, const mlir::DataLayout &layout,
|
||||
const mlir::TypeConverter &typeConverter) const {
|
||||
uint64_t memberOffset;
|
||||
if (attr.isNullPtr()) {
|
||||
// Itanium C++ ABI 2.3:
|
||||
// A NULL pointer is represented as -1.
|
||||
memberOffset = -1ull;
|
||||
} else {
|
||||
// Itanium C++ ABI 2.3:
|
||||
// A pointer to data member is an offset from the base address of
|
||||
// the class object containing it, represented as a ptrdiff_t
|
||||
unsigned memberIndex = attr.getMemberIndex().value();
|
||||
memberOffset =
|
||||
attr.getType().getClassTy().getElementOffset(layout, memberIndex);
|
||||
}
|
||||
|
||||
mlir::Type abiTy = lowerDataMemberType(attr.getType(), typeConverter);
|
||||
return cir::IntAttr::get(abiTy, memberOffset);
|
||||
}
|
||||
|
||||
} // namespace cir
|
||||
@@ -0,0 +1,87 @@
|
||||
//===--- LowerModule.cpp - Lower CIR Module to a Target -------------------===//
|
||||
//
|
||||
// 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 partially mimics clang/lib/CodeGen/CodeGenModule.cpp. The queries
|
||||
// are adapted to operate on the CIR dialect, however.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "LowerModule.h"
|
||||
#include "CIRCXXABI.h"
|
||||
#include "mlir/IR/BuiltinAttributes.h"
|
||||
#include "mlir/IR/PatternMatch.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/TargetOptions.h"
|
||||
#include "clang/CIR/MissingFeatures.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
namespace cir {
|
||||
|
||||
static std::unique_ptr<CIRCXXABI> createCXXABI(LowerModule &lm) {
|
||||
switch (lm.getCXXABIKind()) {
|
||||
case clang::TargetCXXABI::AppleARM64:
|
||||
case clang::TargetCXXABI::Fuchsia:
|
||||
case clang::TargetCXXABI::GenericAArch64:
|
||||
case clang::TargetCXXABI::GenericARM:
|
||||
case clang::TargetCXXABI::iOS:
|
||||
case clang::TargetCXXABI::WatchOS:
|
||||
case clang::TargetCXXABI::GenericMIPS:
|
||||
case clang::TargetCXXABI::GenericItanium:
|
||||
case clang::TargetCXXABI::WebAssembly:
|
||||
case clang::TargetCXXABI::XL:
|
||||
return createItaniumCXXABI(lm);
|
||||
case clang::TargetCXXABI::Microsoft:
|
||||
llvm_unreachable("Windows ABI NYI");
|
||||
}
|
||||
|
||||
llvm_unreachable("invalid C++ ABI kind");
|
||||
}
|
||||
|
||||
LowerModule::LowerModule(clang::LangOptions langOpts,
|
||||
clang::CodeGenOptions codeGenOpts,
|
||||
mlir::ModuleOp &module,
|
||||
std::unique_ptr<clang::TargetInfo> target,
|
||||
mlir::PatternRewriter &rewriter)
|
||||
: module(module), target(std::move(target)), abi(createCXXABI(*this)),
|
||||
rewriter(rewriter) {}
|
||||
|
||||
// TODO: not to create it every time
|
||||
std::unique_ptr<LowerModule>
|
||||
createLowerModule(mlir::ModuleOp module, mlir::PatternRewriter &rewriter) {
|
||||
// Fetch target information.
|
||||
llvm::Triple triple(mlir::cast<mlir::StringAttr>(
|
||||
module->getAttr(cir::CIRDialect::getTripleAttrName()))
|
||||
.getValue());
|
||||
clang::TargetOptions targetOptions;
|
||||
targetOptions.Triple = triple.str();
|
||||
auto targetInfo = clang::targets::AllocateTarget(triple, targetOptions);
|
||||
|
||||
// FIXME(cir): This just uses the default language options. We need to account
|
||||
// for custom options.
|
||||
// Create context.
|
||||
assert(!cir::MissingFeatures::lowerModuleLangOpts());
|
||||
clang::LangOptions langOpts;
|
||||
|
||||
// FIXME(cir): This just uses the default code generation options. We need to
|
||||
// account for custom options.
|
||||
assert(!cir::MissingFeatures::lowerModuleCodeGenOpts());
|
||||
clang::CodeGenOptions codeGenOpts;
|
||||
|
||||
if (auto optInfo = mlir::cast_if_present<cir::OptInfoAttr>(
|
||||
module->getAttr(cir::CIRDialect::getOptInfoAttrName()))) {
|
||||
codeGenOpts.OptimizationLevel = optInfo.getLevel();
|
||||
codeGenOpts.OptimizeSize = optInfo.getSize();
|
||||
}
|
||||
|
||||
return std::make_unique<LowerModule>(std::move(langOpts),
|
||||
std::move(codeGenOpts), module,
|
||||
std::move(targetInfo), rewriter);
|
||||
}
|
||||
|
||||
} // namespace cir
|
||||
@@ -0,0 +1,55 @@
|
||||
//===--- LowerModule.h - Abstracts CIR's module lowering --------*- C++ -*-===//
|
||||
//
|
||||
// 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 partially mimics clang/lib/CodeGen/CodeGenModule.h. The queries are
|
||||
// adapted to operate on the CIR dialect, however.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_LOWERMODULE_H
|
||||
#define CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_LOWERMODULE_H
|
||||
|
||||
#include "CIRCXXABI.h"
|
||||
#include "mlir/IR/BuiltinOps.h"
|
||||
#include "clang/Basic/CodeGenOptions.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRDialect.h"
|
||||
#include "clang/CIR/MissingFeatures.h"
|
||||
#include <memory>
|
||||
|
||||
namespace cir {
|
||||
|
||||
class LowerModule {
|
||||
mlir::ModuleOp module;
|
||||
const std::unique_ptr<clang::TargetInfo> target;
|
||||
std::unique_ptr<CIRCXXABI> abi;
|
||||
[[maybe_unused]] mlir::PatternRewriter &rewriter;
|
||||
|
||||
public:
|
||||
LowerModule(clang::LangOptions langOpts, clang::CodeGenOptions codeGenOpts,
|
||||
mlir::ModuleOp &module, std::unique_ptr<clang::TargetInfo> target,
|
||||
mlir::PatternRewriter &rewriter);
|
||||
~LowerModule() = default;
|
||||
|
||||
clang::TargetCXXABI::Kind getCXXABIKind() const {
|
||||
assert(!cir::MissingFeatures::lowerModuleLangOpts());
|
||||
return target->getCXXABI().getKind();
|
||||
}
|
||||
|
||||
CIRCXXABI &getCXXABI() const { return *abi; }
|
||||
const clang::TargetInfo &getTarget() const { return *target; }
|
||||
mlir::MLIRContext *getMLIRContext() { return module.getContext(); }
|
||||
};
|
||||
|
||||
std::unique_ptr<LowerModule> createLowerModule(mlir::ModuleOp module,
|
||||
mlir::PatternRewriter &rewriter);
|
||||
|
||||
} // namespace cir
|
||||
|
||||
#endif // CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_LOWERMODULE_H
|
||||
@@ -18,7 +18,12 @@ add_clang_library(clangCIRLoweringDirectToLLVM
|
||||
clangCIRLoweringCommon
|
||||
${dialect_libs}
|
||||
MLIRCIR
|
||||
MLIRCIRTargetLowering
|
||||
MLIRBuiltinToLLVMIRTranslation
|
||||
MLIRLLVMToLLVMIRTranslation
|
||||
MLIRIR
|
||||
)
|
||||
|
||||
target_include_directories(clangCIRLoweringDirectToLLVM PRIVATE
|
||||
${CLANG_SOURCE_DIR}/lib/CIR/Dialect/Transforms/TargetLowering
|
||||
)
|
||||
|
||||
@@ -1755,6 +1755,14 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite(
|
||||
return mlir::success();
|
||||
}
|
||||
attr = op.getValue();
|
||||
} else if (mlir::isa<cir::DataMemberType>(op.getType())) {
|
||||
assert(lowerMod && "lower module is not available");
|
||||
auto dataMember = mlir::cast<cir::DataMemberAttr>(op.getValue());
|
||||
mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());
|
||||
mlir::TypedAttr abiValue = lowerMod->getCXXABI().lowerDataMemberConstant(
|
||||
dataMember, layout, *typeConverter);
|
||||
rewriter.replaceOpWithNewOp<ConstantOp>(op, abiValue);
|
||||
return mlir::success();
|
||||
} else if (const auto arrTy = mlir::dyn_cast<cir::ArrayType>(op.getType())) {
|
||||
const auto constArr = mlir::dyn_cast<cir::ConstArrayAttr>(op.getValue());
|
||||
if (!constArr && !isa<cir::ZeroAttr, cir::UndefAttr>(op.getValue()))
|
||||
@@ -2839,8 +2847,20 @@ mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite(
|
||||
return mlir::success();
|
||||
}
|
||||
|
||||
std::unique_ptr<cir::LowerModule> prepareLowerModule(mlir::ModuleOp module) {
|
||||
mlir::PatternRewriter rewriter{module->getContext()};
|
||||
// If the triple is not present, e.g. CIR modules parsed from text, we
|
||||
// cannot init LowerModule properly. This happens in some lowering tests,
|
||||
// but it should not happen in real compilation.
|
||||
assert(!cir::MissingFeatures::makeTripleAlwaysPresent());
|
||||
if (!module->hasAttr(cir::CIRDialect::getTripleAttrName()))
|
||||
return {};
|
||||
return cir::createLowerModule(module, rewriter);
|
||||
}
|
||||
|
||||
static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
|
||||
mlir::DataLayout &dataLayout) {
|
||||
mlir::DataLayout &dataLayout,
|
||||
cir::LowerModule *lowerModule) {
|
||||
converter.addConversion([&](cir::PointerType type) -> mlir::Type {
|
||||
unsigned addrSpace =
|
||||
type.getAddrSpace() ? type.getAddrSpace().getValue().getUInt() : 0;
|
||||
@@ -2850,6 +2870,13 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
|
||||
assert(!cir::MissingFeatures::addressSpace());
|
||||
return mlir::LLVM::LLVMPointerType::get(type.getContext());
|
||||
});
|
||||
converter.addConversion(
|
||||
[&, lowerModule](cir::DataMemberType type) -> mlir::Type {
|
||||
assert(lowerModule && "CXXABI is not available");
|
||||
mlir::Type abiType =
|
||||
lowerModule->getCXXABI().lowerDataMemberType(type, converter);
|
||||
return converter.convertType(abiType);
|
||||
});
|
||||
converter.addConversion([&](cir::ArrayType type) -> mlir::Type {
|
||||
mlir::Type ty =
|
||||
convertTypeForMemory(converter, dataLayout, type.getElementType());
|
||||
@@ -3118,7 +3145,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
|
||||
mlir::ModuleOp module = getOperation();
|
||||
mlir::DataLayout dl(module);
|
||||
mlir::LLVMTypeConverter converter(&getContext());
|
||||
prepareTypeConverter(converter, dl);
|
||||
std::unique_ptr<cir::LowerModule> lowerModule = prepareLowerModule(module);
|
||||
prepareTypeConverter(converter, dl, lowerModule.get());
|
||||
|
||||
mlir::RewritePatternSet patterns(&getContext());
|
||||
|
||||
@@ -3126,7 +3154,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
|
||||
#define GET_LLVM_LOWERING_PATTERNS_LIST
|
||||
#include "clang/CIR/Dialect/IR/CIRLowering.inc"
|
||||
#undef GET_LLVM_LOWERING_PATTERNS_LIST
|
||||
>(converter, patterns.getContext(), dl);
|
||||
>(converter, patterns.getContext(), lowerModule.get(), dl);
|
||||
|
||||
processCIRAttrs(module);
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#ifndef CLANG_CIR_LOWERTOLLVM_H
|
||||
#define CLANG_CIR_LOWERTOLLVM_H
|
||||
|
||||
#include "LowerModule.h"
|
||||
|
||||
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
|
||||
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
|
||||
#include "mlir/Transforms/DialectConversion.h"
|
||||
|
||||
32
clang/test/CIR/CodeGen/pointer-to-data-member.cpp
Normal file
32
clang/test/CIR/CodeGen/pointer-to-data-member.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -Wno-unused-value -emit-cir %s -o %t.cir
|
||||
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -Wno-unused-value -emit-llvm %s -o %t-cir.ll
|
||||
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -Wno-unused-value -emit-llvm %s -o %t.ll
|
||||
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
|
||||
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
};
|
||||
|
||||
auto test1() -> int Point::* {
|
||||
return &Point::y;
|
||||
}
|
||||
|
||||
// CIR: cir.func {{.*}} @_Z5test1v() -> !cir.data_member<!s32i in !rec_Point> {
|
||||
// CIR: %[[RETVAL:.*]] = cir.alloca !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, ["__retval"]
|
||||
// CIR: %[[MEMBER:.*]] = cir.const #cir.data_member<1> : !cir.data_member<!s32i in !rec_Point>
|
||||
// CIR: cir.store %[[MEMBER]], %[[RETVAL]] : !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>
|
||||
// CIR: %[[RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, !cir.data_member<!s32i in !rec_Point>
|
||||
// CIR: cir.return %[[RET]] : !cir.data_member<!s32i in !rec_Point>
|
||||
|
||||
// LLVM: define {{.*}} i64 @_Z5test1v()
|
||||
// LLVM: %[[RETVAL:.*]] = alloca i64
|
||||
// LLVM: store i64 4, ptr %[[RETVAL]]
|
||||
// LLVM: %[[RET:.*]] = load i64, ptr %[[RETVAL]]
|
||||
// LLVM: ret i64 %[[RET]]
|
||||
|
||||
// OGCG: define {{.*}} i64 @_Z5test1v()
|
||||
// OGCG: ret i64 4
|
||||
27
clang/test/CIR/IR/invalid-data-member.cir
Normal file
27
clang/test/CIR/IR/invalid-data-member.cir
Normal file
@@ -0,0 +1,27 @@
|
||||
// RUN: cir-opt %s -verify-diagnostics -split-input-file
|
||||
|
||||
// -----
|
||||
|
||||
!u16i = !cir.int<u, 16>
|
||||
!u32i = !cir.int<u, 32>
|
||||
!struct1 = !cir.record<struct "Struct1" {!u16i, !u32i}>
|
||||
|
||||
// expected-error@+1 {{member type of a #cir.data_member attribute must match the attribute type}}
|
||||
#invalid_member_ty = #cir.data_member<0> : !cir.data_member<!u32i in !struct1>
|
||||
|
||||
// -----
|
||||
|
||||
!u16i = !cir.int<u, 16>
|
||||
!incomplete_struct = !cir.record<struct "Incomplete" incomplete>
|
||||
|
||||
// expected-error@+1 {{incomplete 'cir.record' cannot be used to build a non-null data member pointer}}
|
||||
#incomplete_cls_member = #cir.data_member<0> : !cir.data_member<!u16i in !incomplete_struct>
|
||||
|
||||
// -----
|
||||
|
||||
!u16i = !cir.int<u, 16>
|
||||
!u32i = !cir.int<u, 32>
|
||||
!struct1 = !cir.record<struct "Struct1" {!u16i, !u32i}>
|
||||
|
||||
// expected-error@+1 {{member index of a #cir.data_member attribute is out of range}}
|
||||
#invalid_member_ty = #cir.data_member<2> : !cir.data_member<!u32i in !struct1>
|
||||
@@ -60,6 +60,7 @@ void GenerateLLVMLoweringPattern(llvm::StringRef OpName,
|
||||
|
||||
Code << "class " << PatternName
|
||||
<< " : public mlir::OpConversionPattern<cir::" << OpName << "> {\n";
|
||||
Code << " [[maybe_unused]] cir::LowerModule *lowerMod;\n";
|
||||
Code << " [[maybe_unused]] mlir::DataLayout const &dataLayout;\n";
|
||||
Code << "\n";
|
||||
|
||||
@@ -69,10 +70,12 @@ void GenerateLLVMLoweringPattern(llvm::StringRef OpName,
|
||||
|
||||
Code << " " << PatternName
|
||||
<< "(mlir::TypeConverter const "
|
||||
"&typeConverter, mlir::MLIRContext *context, mlir::DataLayout const "
|
||||
"&typeConverter, mlir::MLIRContext *context, "
|
||||
"cir::LowerModule *lowerMod, mlir::DataLayout const "
|
||||
"&dataLayout)\n";
|
||||
Code << " : OpConversionPattern<cir::" << OpName
|
||||
<< ">(typeConverter, context), dataLayout(dataLayout)";
|
||||
<< ">(typeConverter, context), lowerMod(lowerMod), "
|
||||
"dataLayout(dataLayout)";
|
||||
if (IsRecursive) {
|
||||
Code << " {\n";
|
||||
Code << " setHasBoundedRewriteRecursion();\n";
|
||||
|
||||
Reference in New Issue
Block a user