[CIR] Pointer and vptr width from a CIR-native data-layout entry (#204185)
PointerType and VPtrType have hard-coded sizes and alignments of 64/8
bits. On targets with 32-bit pointers (e.g., nvptx, spirv32), this trips
the record layout builder. Any record containing a pointer hit the
insertPadding assertion (offset >= size)
because the pointer was sized at 8 bytes while the following field was
placed at the AST-mandated 4-byte offset.
### Changes:
- CIRGenerator: attaches a CIR-native cir.ptr data-layout entry at
module setup, storing {size-in-bits, abi-align-in-bits} read
from the target DataLayout (only for the default address space).
- CIRTypes: PointerType reads its size/alignment from that entry
(falling back to 64/8 when absent); VPtrType routes through a cir.ptr so
it picks up the same width.
- LowerToLLVM: strips the cir.ptr entry during CIR→LLVM lowering, since
cir.ptr has no meaning in LLVM IR.
- Unit test: checking 4-byte pointer/vptr layout on nvptx, verified
across CIR, CIR→LLVM.
This commit is contained in:
parent
6d9de52545
commit
53e16d7708
13 changed files with 421 additions and 28 deletions
34
clang/include/clang/CIR/CIRDataLayoutSpec.h
Normal file
34
clang/include/clang/CIR/CIRDataLayoutSpec.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//===-- CIRDataLayoutSpec.h - DLTI data layout for CIR modules --*- 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 declares a helper that attaches the DLTI data-layout spec,
|
||||
// including the CIR-native pointer entry, to a CIR module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef CLANG_CIR_CIRDATALAYOUTSPEC_H
|
||||
#define CLANG_CIR_CIRDATALAYOUTSPEC_H
|
||||
|
||||
namespace llvm {
|
||||
class DataLayout;
|
||||
} // namespace llvm
|
||||
|
||||
namespace mlir {
|
||||
class ModuleOp;
|
||||
} // namespace mlir
|
||||
|
||||
namespace cir {
|
||||
|
||||
/// Translate \p dl into a DLTI data-layout spec and attach it to \p mod.
|
||||
/// On top of the plain mlir::translateDataLayout entries this adds a
|
||||
/// #cir.ptr_spec entry keyed on !cir.ptr, which CIR pointer types read for
|
||||
/// their size and alignment; without it pointer widths default to 64 bits.
|
||||
void setMLIRDataLayout(mlir::ModuleOp mod, const llvm::DataLayout &dl);
|
||||
|
||||
} // namespace cir
|
||||
|
||||
#endif // CLANG_CIR_CIRDATALAYOUTSPEC_H
|
||||
|
|
@ -1188,6 +1188,52 @@ def CIR_TargetAddressSpaceAttr : CIR_Attr< "TargetAddressSpace",
|
|||
let canHaveIllegalCXXABIType = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PtrSpecAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_PtrSpecAttr : CIR_Attr<"PtrSpec", "ptr_spec"> {
|
||||
let summary = "!cir.ptr data layout spec";
|
||||
let description = [{
|
||||
Pointer data layout for `!cir.ptr`: `size`, `abi` and `preferred` are
|
||||
required bitwidths; `index` is the optional bitwidth for index
|
||||
computations, defaulting to `size`. All present values must be divisible
|
||||
by 8, with `preferred` >= `abi`.
|
||||
|
||||
This is the CIR-native analogue of the ptr dialect's `#ptr.spec`; a
|
||||
native attribute keeps CIR's data-layout queries free of any ptr-dialect
|
||||
dependency.
|
||||
|
||||
Used as the value of the `!cir.ptr<!cir.void>`-keyed data-layout entry:
|
||||
|
||||
```mlir
|
||||
#dlti.dl_spec<!cir.ptr<!cir.void> =
|
||||
#cir.ptr_spec<size = 64, abi = 64, preferred = 64>>
|
||||
```
|
||||
}];
|
||||
let parameters = (ins
|
||||
"uint32_t":$size,
|
||||
"uint32_t":$abi,
|
||||
"uint32_t":$preferred,
|
||||
DefaultValuedParameter<"uint32_t", "kOptionalSpecValue">:$index
|
||||
);
|
||||
let skipDefaultBuilders = 1;
|
||||
let builders = [
|
||||
AttrBuilder<(ins "uint32_t":$size, "uint32_t":$abi, "uint32_t":$preferred,
|
||||
CArg<"uint32_t", "kOptionalSpecValue">:$index), [{
|
||||
return $_get($_ctxt, size, abi, preferred, index);
|
||||
}]>
|
||||
];
|
||||
let assemblyFormat = "`<` struct(params) `>`";
|
||||
let extraClassDeclaration = [{
|
||||
/// Sentinel value marking the optional `index` parameter as unset.
|
||||
static constexpr uint32_t kOptionalSpecValue =
|
||||
std::numeric_limits<uint32_t>::max();
|
||||
}];
|
||||
let genVerifyDecl = 1;
|
||||
let canHaveIllegalCXXABIType = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ConstComplexAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -239,7 +239,9 @@ def CIR_ComplexType : CIR_Type<"Complex", "complex", [
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
|
||||
DeclareTypeInterfaceMethods<DataLayoutTypeInterface>,
|
||||
DeclareTypeInterfaceMethods<DataLayoutTypeInterface,
|
||||
["getPreferredAlignment", "getIndexBitwidth", "areCompatible",
|
||||
"verifyEntries"]>,
|
||||
DeclareTypeInterfaceMethods<CIR_SizedTypeInterface>
|
||||
]> {
|
||||
let summary = "CIR pointer type";
|
||||
|
|
|
|||
49
clang/lib/CIR/CodeGen/CIRDataLayoutSpec.cpp
Normal file
49
clang/lib/CIR/CodeGen/CIRDataLayoutSpec.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
//===--- CIRDataLayoutSpec.cpp - DLTI data layout for CIR modules ---------===//
|
||||
//
|
||||
// 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 attaches the DLTI data-layout spec, including the CIR-native
|
||||
// pointer entry, to a CIR module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/CIR/CIRDataLayoutSpec.h"
|
||||
|
||||
#include "mlir/Dialect/DLTI/DLTI.h"
|
||||
#include "mlir/IR/BuiltinOps.h"
|
||||
#include "mlir/Target/LLVMIR/Import.h"
|
||||
|
||||
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRTypes.h"
|
||||
#include "clang/CIR/MissingFeatures.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
|
||||
void cir::setMLIRDataLayout(mlir::ModuleOp mod, const llvm::DataLayout &dl) {
|
||||
mlir::MLIRContext *mlirContext = mod.getContext();
|
||||
mlir::DataLayoutSpecInterface dlSpec =
|
||||
mlir::translateDataLayout(dl, mlirContext);
|
||||
|
||||
// Append the !cir.ptr-keyed #cir.ptr_spec entry.
|
||||
// TODO(cir): only the default address space is recorded.
|
||||
assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS());
|
||||
constexpr unsigned kBitsInByte = 8;
|
||||
unsigned ptrSizeBits = dl.getPointerSizeInBits(/*AS=*/0);
|
||||
unsigned ptrAbiBits =
|
||||
dl.getPointerABIAlignment(/*AS=*/0).value() * kBitsInByte;
|
||||
unsigned ptrPrefBits =
|
||||
dl.getPointerPrefAlignment(/*AS=*/0).value() * kBitsInByte;
|
||||
unsigned ptrIndexBits = dl.getIndexSizeInBits(/*AS=*/0);
|
||||
auto ptrKey = cir::PointerType::get(cir::VoidType::get(mlirContext));
|
||||
auto ptrSpec = cir::PtrSpecAttr::get(mlirContext, ptrSizeBits, ptrAbiBits,
|
||||
ptrPrefBits, ptrIndexBits);
|
||||
llvm::SmallVector<mlir::DataLayoutEntryInterface> entries(
|
||||
dlSpec.getEntries().begin(), dlSpec.getEntries().end());
|
||||
entries.push_back(mlir::DataLayoutEntryAttr::get(ptrKey, ptrSpec));
|
||||
|
||||
mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName,
|
||||
mlir::DataLayoutSpecAttr::get(mlirContext, entries));
|
||||
}
|
||||
|
|
@ -16,11 +16,12 @@
|
|||
#include "mlir/Dialect/OpenACC/OpenACC.h"
|
||||
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#include "mlir/Target/LLVMIR/Import.h"
|
||||
|
||||
#include "clang/AST/DeclGroup.h"
|
||||
#include "clang/CIR/CIRDataLayoutSpec.h"
|
||||
#include "clang/CIR/CIRGenerator.h"
|
||||
#include "clang/CIR/InitAllDialects.h"
|
||||
#include "clang/CIR/MissingFeatures.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
|
||||
using namespace cir;
|
||||
|
|
@ -38,13 +39,6 @@ CIRGenerator::~CIRGenerator() {
|
|||
assert(deferredInlineMemberFuncDefs.empty() || diags.hasErrorOccurred());
|
||||
}
|
||||
|
||||
static void setMLIRDataLayout(mlir::ModuleOp &mod, const llvm::DataLayout &dl) {
|
||||
mlir::MLIRContext *mlirContext = mod.getContext();
|
||||
mlir::DataLayoutSpecInterface dlSpec =
|
||||
mlir::translateDataLayout(dl, mlirContext);
|
||||
mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
|
||||
}
|
||||
|
||||
void CIRGenerator::Initialize(ASTContext &astContext) {
|
||||
using namespace llvm;
|
||||
|
||||
|
|
@ -61,7 +55,7 @@ void CIRGenerator::Initialize(ASTContext &astContext) {
|
|||
mlir::ModuleOp mod = cgm->getModule();
|
||||
llvm::DataLayout layout =
|
||||
llvm::DataLayout(astContext.getTargetInfo().getDataLayoutString());
|
||||
setMLIRDataLayout(mod, layout);
|
||||
cir::setMLIRDataLayout(mod, layout);
|
||||
}
|
||||
|
||||
bool CIRGenerator::verifyModule() const { return cgm->verifyModule(); }
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ set(
|
|||
get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
|
||||
|
||||
add_clang_library(clangCIR
|
||||
CIRDataLayoutSpec.cpp
|
||||
CIRGenerator.cpp
|
||||
CIRGenAsm.cpp
|
||||
CIRGenAtomic.cpp
|
||||
|
|
|
|||
|
|
@ -172,6 +172,28 @@ bool TargetAddressSpaceAttr::isValidPtrIntCast(
|
|||
llvm_unreachable("isValidPtrIntCast for TargetAddressSpaceAttr NYI");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PtrSpecAttr definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
LogicalResult PtrSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
|
||||
uint32_t size, uint32_t abi,
|
||||
uint32_t preferred, uint32_t index) {
|
||||
constexpr unsigned kBitsInByte = 8;
|
||||
if (size % kBitsInByte != 0)
|
||||
return emitError() << "size entry must be divisible by 8";
|
||||
if (abi % kBitsInByte != 0)
|
||||
return emitError() << "abi entry must be divisible by 8";
|
||||
if (preferred % kBitsInByte != 0)
|
||||
return emitError() << "preferred entry must be divisible by 8";
|
||||
if (index != kOptionalSpecValue && index % kBitsInByte != 0)
|
||||
return emitError() << "index entry must be divisible by 8";
|
||||
if (abi > preferred)
|
||||
return emitError() << "preferred alignment is expected to be at least "
|
||||
"as large as ABI alignment";
|
||||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// General CIR parsing / printing
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -607,20 +607,105 @@ void RecordType::removeABIConversionNamePrefix() {
|
|||
// Data Layout information for types
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// The cir.ptr data-layout entry holds a #cir.ptr_spec attribute (see
|
||||
// cir::setMLIRDataLayout).
|
||||
namespace {
|
||||
constexpr static uint64_t kBitsInByte = 8;
|
||||
|
||||
// Defaults used when the module carries no cir.ptr data-layout entry.
|
||||
constexpr static uint64_t kDefaultPointerSizeBits = 64;
|
||||
constexpr static uint64_t kDefaultPointerAlignment = 8;
|
||||
|
||||
/// Returns the default-address-space #cir.ptr_spec entry, or a synthesized
|
||||
/// 64-bit default when there is none. Per-AS entries are not modeled yet.
|
||||
cir::PtrSpecAttr getPointerSpec(mlir::DataLayoutEntryListRef params,
|
||||
cir::PointerType type) {
|
||||
// FIXME: improve this in face of address spaces
|
||||
assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS());
|
||||
for (mlir::DataLayoutEntryInterface entry : params) {
|
||||
if (!entry.isTypeEntry())
|
||||
continue;
|
||||
auto key =
|
||||
mlir::cast<cir::PointerType>(mlir::cast<mlir::Type>(entry.getKey()));
|
||||
if (key.getAddrSpace())
|
||||
continue;
|
||||
if (auto spec = mlir::dyn_cast<cir::PtrSpecAttr>(entry.getValue()))
|
||||
return spec;
|
||||
}
|
||||
return cir::PtrSpecAttr::get(type.getContext(), kDefaultPointerSizeBits,
|
||||
kDefaultPointerAlignment * kBitsInByte,
|
||||
kDefaultPointerAlignment * kBitsInByte,
|
||||
kDefaultPointerSizeBits);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
llvm::TypeSize
|
||||
PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
|
||||
::mlir::DataLayoutEntryListRef params) const {
|
||||
// FIXME: improve this in face of address spaces
|
||||
assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS());
|
||||
return llvm::TypeSize::getFixed(64);
|
||||
return llvm::TypeSize::getFixed(getPointerSpec(params, *this).getSize());
|
||||
}
|
||||
|
||||
uint64_t
|
||||
PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
|
||||
::mlir::DataLayoutEntryListRef params) const {
|
||||
// FIXME: improve this in face of address spaces
|
||||
assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS());
|
||||
return 8;
|
||||
return getPointerSpec(params, *this).getAbi() / kBitsInByte;
|
||||
}
|
||||
|
||||
uint64_t PointerType::getPreferredAlignment(
|
||||
const ::mlir::DataLayout &dataLayout,
|
||||
::mlir::DataLayoutEntryListRef params) const {
|
||||
return getPointerSpec(params, *this).getPreferred() / kBitsInByte;
|
||||
}
|
||||
|
||||
std::optional<uint64_t>
|
||||
PointerType::getIndexBitwidth(const ::mlir::DataLayout &dataLayout,
|
||||
::mlir::DataLayoutEntryListRef params) const {
|
||||
cir::PtrSpecAttr spec = getPointerSpec(params, *this);
|
||||
if (spec.getIndex() == cir::PtrSpecAttr::kOptionalSpecValue)
|
||||
return spec.getSize();
|
||||
return spec.getIndex();
|
||||
}
|
||||
|
||||
llvm::LogicalResult
|
||||
PointerType::verifyEntries(mlir::DataLayoutEntryListRef entries,
|
||||
mlir::Location loc) const {
|
||||
for (mlir::DataLayoutEntryInterface entry : entries) {
|
||||
if (!entry.isTypeEntry())
|
||||
continue;
|
||||
auto key = mlir::cast<PointerType>(mlir::cast<mlir::Type>(entry.getKey()));
|
||||
if (!mlir::isa<cir::PtrSpecAttr>(entry.getValue()))
|
||||
return mlir::emitError(loc) << "expected layout attribute for " << key
|
||||
<< " to be a #cir.ptr_spec attribute";
|
||||
if (!mlir::isa<cir::VoidType>(key.getPointee()))
|
||||
return mlir::emitError(loc) << "expected !cir.ptr data layout entry for "
|
||||
<< key << " to use !cir.void as pointee";
|
||||
// Per-address-space pointer layouts are not supported yet.
|
||||
if (key.getAddrSpace())
|
||||
return mlir::emitError(loc)
|
||||
<< "!cir.ptr data layout entries are currently limited to the "
|
||||
"default address space";
|
||||
}
|
||||
return mlir::success();
|
||||
}
|
||||
|
||||
bool PointerType::areCompatible(
|
||||
mlir::DataLayoutEntryListRef oldLayout,
|
||||
mlir::DataLayoutEntryListRef newLayout, mlir::DataLayoutSpecInterface,
|
||||
const mlir::DataLayoutIdentifiedEntryMap &) const {
|
||||
// A nested spec may only override with the same size and a compatible ABI
|
||||
// alignment. TODO(cir): match by address space once per-AS specs exist.
|
||||
cir::PtrSpecAttr oldSpec = getPointerSpec(oldLayout, *this);
|
||||
uint64_t size = oldSpec.getSize();
|
||||
uint64_t abi = oldSpec.getAbi();
|
||||
for (mlir::DataLayoutEntryInterface newEntry : newLayout) {
|
||||
if (!newEntry.isTypeEntry())
|
||||
continue;
|
||||
auto newSpec = mlir::cast<cir::PtrSpecAttr>(newEntry.getValue());
|
||||
if (size != newSpec.getSize() || abi < newSpec.getAbi() ||
|
||||
abi % newSpec.getAbi() != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
llvm::TypeSize
|
||||
|
|
@ -1122,20 +1207,31 @@ BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
|
|||
// DataMemberType Definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static mlir::Type getDataMemberLayoutType(const mlir::DataLayout &dataLayout,
|
||||
mlir::MLIRContext *ctx) {
|
||||
// Itanium ABI: a data member pointer is a ptrdiff_t, an integer of the
|
||||
// pointer index width.
|
||||
// TODO: consider data member pointer layout in other ABIs
|
||||
auto voidPtrTy = cir::PointerType::get(cir::VoidType::get(ctx));
|
||||
uint64_t width = dataLayout.getTypeIndexBitwidth(voidPtrTy).value_or(
|
||||
dataLayout.getTypeSizeInBits(voidPtrTy).getFixedValue());
|
||||
return cir::IntType::get(ctx, width, /*is_signed=*/true);
|
||||
}
|
||||
|
||||
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);
|
||||
return dataLayout.getTypeSizeInBits(
|
||||
getDataMemberLayoutType(dataLayout, getContext()));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
DataMemberType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
|
||||
::mlir::DataLayoutEntryListRef params) const {
|
||||
// FIXME: consider alignment differences under different ABIs
|
||||
assert(!MissingFeatures::cxxABI());
|
||||
return 8;
|
||||
return dataLayout.getTypeABIAlignment(
|
||||
getDataMemberLayoutType(dataLayout, getContext()));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -1145,14 +1241,15 @@ DataMemberType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
|
|||
llvm::TypeSize
|
||||
VPtrType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
|
||||
mlir::DataLayoutEntryListRef params) const {
|
||||
// FIXME: consider size differences under different ABIs
|
||||
return llvm::TypeSize::getFixed(64);
|
||||
// A vtable pointer is an ordinary data pointer; size it as a cir.ptr.
|
||||
return dataLayout.getTypeSizeInBits(
|
||||
cir::PointerType::get(cir::VoidType::get(getContext())));
|
||||
}
|
||||
|
||||
uint64_t VPtrType::getABIAlignment(const mlir::DataLayout &dataLayout,
|
||||
mlir::DataLayoutEntryListRef params) const {
|
||||
// FIXME: consider alignment differences under different ABIs
|
||||
return 8;
|
||||
return dataLayout.getTypeABIAlignment(
|
||||
cir::PointerType::get(cir::VoidType::get(getContext())));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -4039,6 +4039,21 @@ void ConvertCIRToLLVMPass::runOnOperation() {
|
|||
if (failed(applyPartialConversion(ops, target, std::move(patterns))))
|
||||
signalPassFailure();
|
||||
|
||||
// Drop the cir.ptr-keyed data-layout entries: they drove pointer-width
|
||||
// queries up to this point, but the LLVM IR exporter rejects CIR types.
|
||||
if (auto dlSpec = mlir::dyn_cast_or_null<mlir::DataLayoutSpecAttr>(
|
||||
module->getAttr(mlir::DLTIDialect::kDataLayoutAttrName))) {
|
||||
llvm::SmallVector<mlir::DataLayoutEntryInterface> kept;
|
||||
for (mlir::DataLayoutEntryInterface entry : dlSpec.getEntries()) {
|
||||
if (entry.isTypeEntry() &&
|
||||
mlir::isa<cir::PointerType>(mlir::cast<mlir::Type>(entry.getKey())))
|
||||
continue;
|
||||
kept.push_back(entry);
|
||||
}
|
||||
module->setAttr(mlir::DLTIDialect::kDataLayoutAttrName,
|
||||
mlir::DataLayoutSpecAttr::get(module.getContext(), kept));
|
||||
}
|
||||
|
||||
// Emit the llvm.global_ctors array.
|
||||
buildCtorDtorList(module, cir::CIRDialect::getGlobalCtorsAttrName(),
|
||||
"llvm.global_ctors", [](mlir::Attribute attr) {
|
||||
|
|
|
|||
54
clang/test/CIR/CodeGen/pointer-width-32bit.cpp
Normal file
54
clang/test/CIR/CodeGen/pointer-width-32bit.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// RUN: %clang_cc1 -std=c++20 -triple nvptx-nvidia-cuda -fclangir -emit-cir %s -o %t.cir
|
||||
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
|
||||
// RUN: %clang_cc1 -std=c++20 -triple nvptx-nvidia-cuda -fclangir -emit-llvm %s -o %t-cir.ll
|
||||
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
|
||||
// RUN: %clang_cc1 -std=c++20 -triple nvptx-nvidia-cuda -emit-llvm %s -o %t.ll
|
||||
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
|
||||
|
||||
// On a 32-bit-pointer target such as nvptx, !cir.ptr and !cir.vptr are 4 bytes
|
||||
// wide, driven by the #cir.ptr_spec data-layout entry. Hardcoded 64-bit widths
|
||||
// used to trip the record layout builder (insertPadding: offset >= size) on
|
||||
// every record containing a pointer.
|
||||
|
||||
struct S {
|
||||
int *p;
|
||||
int x;
|
||||
};
|
||||
|
||||
S s;
|
||||
|
||||
class A {
|
||||
public:
|
||||
virtual void f();
|
||||
int x;
|
||||
};
|
||||
|
||||
void A::f() {}
|
||||
|
||||
// A data member pointer is ptrdiff_t-sized, so 'x' again lands at offset 4.
|
||||
struct M {
|
||||
int S::*pm;
|
||||
int x;
|
||||
};
|
||||
|
||||
M m;
|
||||
|
||||
// Each 4-byte pointer is followed by 'x' at offset 4 with no padding; records
|
||||
// are 4-byte aligned.
|
||||
// CIR-DAG: !rec_S = !cir.struct<"S" {!cir.ptr<!s32i>, !s32i}>
|
||||
// CIR-DAG: !rec_A = !cir.struct<class "A" {!cir.vptr, !s32i}>
|
||||
// -emit-cir prints after cir-cxxabi-lowering, so M's member pointer is
|
||||
// already a 32-bit integer here.
|
||||
// CIR-DAG: !rec_M = !cir.struct<"M" {!s32i, !s32i}>
|
||||
// CIR-DAG: !cir.ptr<!cir.void> = #cir.ptr_spec<size = 32, abi = 32, preferred = 32, index = 32>
|
||||
// CIR: cir.global external @s = #cir.zero : !rec_S {alignment = 4 : i64}
|
||||
// CIR: cir.global external @m = #cir.const_record<{#cir.int<-1> : !s32i, #cir.int<0> : !s32i}> : !rec_M {alignment = 4 : i64}
|
||||
// CIR: cir.global{{.*}}@_ZTV1A = #cir.vtable<{{.*}}{alignment = 4 : i64}
|
||||
|
||||
// LLVM: @s = global %struct.S zeroinitializer, align 4
|
||||
// LLVM: @m = global %struct.M { i32 -1, i32 0 }, align 4
|
||||
// LLVM: @_ZTV1A = global { [3 x ptr] } {{.*}}, align 4
|
||||
|
||||
// OGCG: @s = global %struct.S zeroinitializer, align 4
|
||||
// OGCG: @m = global %struct.M { i32 -1, i32 0 }, align 4
|
||||
// OGCG: @_ZTV1A = {{.*}}constant { [3 x ptr] } {{.*}}, align 4
|
||||
58
clang/test/CIR/IR/pointer-data-layout.cir
Normal file
58
clang/test/CIR/IR/pointer-data-layout.cir
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// RUN: cir-opt %s -verify-diagnostics -split-input-file
|
||||
|
||||
// A well-formed #cir.ptr_spec entry round-trips without diagnostics.
|
||||
module attributes {dlti.dl_spec = #dlti.dl_spec<
|
||||
!cir.ptr<!cir.void> = #cir.ptr_spec<size = 32, abi = 32, preferred = 32>>} {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// The entry value must be a #cir.ptr_spec attribute.
|
||||
// expected-error @below {{expected layout attribute for '!cir.ptr<!cir.void>' to be a #cir.ptr_spec attribute}}
|
||||
module attributes {dlti.dl_spec = #dlti.dl_spec<
|
||||
!cir.ptr<!cir.void> = dense<32> : vector<2xi64>>} {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// The entry key must use !cir.void as pointee.
|
||||
// expected-error @below {{expected !cir.ptr data layout entry for '!cir.ptr<!cir.int<s, 32>>' to use !cir.void as pointee}}
|
||||
module attributes {dlti.dl_spec = #dlti.dl_spec<
|
||||
!cir.ptr<!cir.int<s, 32>> = #cir.ptr_spec<size = 32, abi = 32, preferred = 32>>} {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// Per-address-space pointer layouts are not supported yet.
|
||||
// expected-error @below {{!cir.ptr data layout entries are currently limited to the default address space}}
|
||||
module attributes {dlti.dl_spec = #dlti.dl_spec<
|
||||
!cir.ptr<!cir.void, target_address_space(5)> = #cir.ptr_spec<size = 32, abi = 32, preferred = 32>>} {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error @+2 {{size entry must be divisible by 8}}
|
||||
module attributes {dlti.dl_spec = #dlti.dl_spec<
|
||||
!cir.ptr<!cir.void> = #cir.ptr_spec<size = 33, abi = 32, preferred = 32>>} {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error @+2 {{abi entry must be divisible by 8}}
|
||||
module attributes {dlti.dl_spec = #dlti.dl_spec<
|
||||
!cir.ptr<!cir.void> = #cir.ptr_spec<size = 32, abi = 33, preferred = 64>>} {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error @+2 {{index entry must be divisible by 8}}
|
||||
module attributes {dlti.dl_spec = #dlti.dl_spec<
|
||||
!cir.ptr<!cir.void> = #cir.ptr_spec<size = 32, abi = 32, preferred = 32, index = 33>>} {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error @+2 {{preferred alignment is expected to be at least as large as ABI alignment}}
|
||||
module attributes {dlti.dl_spec = #dlti.dl_spec<
|
||||
!cir.ptr<!cir.void> = #cir.ptr_spec<size = 64, abi = 64, preferred = 32>>} {
|
||||
}
|
||||
22
clang/test/CIR/Tools/pointer-width-from-triple.cir
Normal file
22
clang/test/CIR/Tools/pointer-width-from-triple.cir
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: cir-translate --cir-to-llvmir --target nvptx-nvidia-cuda --disable-cc-lowering %s -o %t.nvptx.ll
|
||||
// RUN: FileCheck %s -input-file %t.nvptx.ll -check-prefix=NVPTX
|
||||
// RUN: cir-translate --cir-to-llvmir --target x86_64-unknown-linux-gnu --disable-cc-lowering %s -o %t.x86.ll
|
||||
// RUN: FileCheck %s -input-file %t.x86.ll -check-prefix=X86
|
||||
|
||||
// A data layout derived from the target triple must carry the #cir.ptr_spec
|
||||
// entry, just as CIRGen emits it. cir.ptr_diff bakes the pointee size into
|
||||
// the emitted division: 4 bytes on nvptx, not the 64-bit fallback of 8.
|
||||
|
||||
!s64i = !cir.int<s, 64>
|
||||
module {
|
||||
cir.func @f(%arg0: !cir.ptr<!cir.ptr<!s64i>>, %arg1: !cir.ptr<!cir.ptr<!s64i>>) -> !s64i {
|
||||
%0 = cir.ptr_diff %arg0, %arg1 : !cir.ptr<!cir.ptr<!s64i>> -> !s64i
|
||||
cir.return %0 : !s64i
|
||||
}
|
||||
}
|
||||
|
||||
// NVPTX-LABEL: define i64 @f
|
||||
// NVPTX: sdiv exact i64 %{{.*}}, 4
|
||||
|
||||
// X86-LABEL: define i64 @f
|
||||
// X86: sdiv exact i64 %{{.*}}, 8
|
||||
|
|
@ -20,10 +20,10 @@
|
|||
#include "mlir/InitAllTranslations.h"
|
||||
#include "mlir/Support/LogicalResult.h"
|
||||
#include "mlir/Target/LLVMIR/Dialect/All.h"
|
||||
#include "mlir/Target/LLVMIR/Import.h"
|
||||
#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
|
||||
#include "mlir/Tools/mlir-translate/Translation.h"
|
||||
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/TargetParser/Host.h"
|
||||
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
#include "clang/Basic/DiagnosticIDs.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/CIR/CIRDataLayoutSpec.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRDialect.h"
|
||||
#include "clang/CIR/Dialect/Passes.h"
|
||||
#include "clang/CIR/InitAllDialects.h"
|
||||
|
|
@ -111,9 +112,7 @@ llvm::LogicalResult prepareCIRModuleDataLayout(mlir::ModuleOp mod,
|
|||
context->loadDialect<mlir::DLTIDialect, mlir::LLVM::LLVMDialect,
|
||||
mlir::omp::OpenMPDialect>();
|
||||
|
||||
mlir::DataLayoutSpecInterface dlSpec =
|
||||
mlir::translateDataLayout(llvm::DataLayout(layoutString), context);
|
||||
mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
|
||||
cir::setMLIRDataLayout(mod, llvm::DataLayout(layoutString));
|
||||
|
||||
return llvm::success();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue