Author: Akshay K Date: 2026-07-30T16:50:13-07:00 New Revision: 53e16d7708c39ecc03f97d32d1db9afdd355deca
URL: https://github.com/llvm/llvm-project/commit/53e16d7708c39ecc03f97d32d1db9afdd355deca DIFF: https://github.com/llvm/llvm-project/commit/53e16d7708c39ecc03f97d32d1db9afdd355deca.diff LOG: [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. Added: clang/include/clang/CIR/CIRDataLayoutSpec.h clang/lib/CIR/CodeGen/CIRDataLayoutSpec.cpp clang/test/CIR/CodeGen/pointer-width-32bit.cpp clang/test/CIR/IR/pointer-data-layout.cir clang/test/CIR/Tools/pointer-width-from-triple.cir Modified: clang/include/clang/CIR/Dialect/IR/CIRAttrs.td clang/include/clang/CIR/Dialect/IR/CIRTypes.td clang/lib/CIR/CodeGen/CIRGenerator.cpp clang/lib/CIR/CodeGen/CMakeLists.txt clang/lib/CIR/Dialect/IR/CIRAttrs.cpp clang/lib/CIR/Dialect/IR/CIRTypes.cpp clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp clang/tools/cir-translate/cir-translate.cpp Removed: ################################################################################ diff --git a/clang/include/clang/CIR/CIRDataLayoutSpec.h b/clang/include/clang/CIR/CIRDataLayoutSpec.h new file mode 100644 index 0000000000000..c270f6283afe4 --- /dev/null +++ b/clang/include/clang/CIR/CIRDataLayoutSpec.h @@ -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 diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index f0c8464b8f105..a0fe997156a69 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -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 //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 09c26af212f38..29afaa6d41f4b 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -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"; diff --git a/clang/lib/CIR/CodeGen/CIRDataLayoutSpec.cpp b/clang/lib/CIR/CodeGen/CIRDataLayoutSpec.cpp new file mode 100644 index 0000000000000..a25fb46da5e8e --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRDataLayoutSpec.cpp @@ -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)); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index d4fcbb6e42f3e..941322cfdc2b4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -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(); } diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 8e4fd906b6eca..78569b11651e0 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -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 diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp index 0678bcd882260..264e836718c81 100644 --- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.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 //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index e070f758032be..c1f3d3dc6cca5 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -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 ptr diff _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 diff erences under diff erent 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 diff erences under diff erent 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 diff erences under diff erent 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 diff erences under diff erent ABIs - return 8; + return dataLayout.getTypeABIAlignment( + cir::PointerType::get(cir::VoidType::get(getContext()))); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index c7e8f97f3a68f..f392b9eb63d5e 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -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) { diff --git a/clang/test/CIR/CodeGen/pointer-width-32bit.cpp b/clang/test/CIR/CodeGen/pointer-width-32bit.cpp new file mode 100644 index 0000000000000..0e2a7a1bc1390 --- /dev/null +++ b/clang/test/CIR/CodeGen/pointer-width-32bit.cpp @@ -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 ptr diff _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 diff --git a/clang/test/CIR/IR/pointer-data-layout.cir b/clang/test/CIR/IR/pointer-data-layout.cir new file mode 100644 index 0000000000000..938216cae2be3 --- /dev/null +++ b/clang/test/CIR/IR/pointer-data-layout.cir @@ -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>>} { +} diff --git a/clang/test/CIR/Tools/pointer-width-from-triple.cir b/clang/test/CIR/Tools/pointer-width-from-triple.cir new file mode 100644 index 0000000000000..f534c641c1746 --- /dev/null +++ b/clang/test/CIR/Tools/pointer-width-from-triple.cir @@ -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 diff --git a/clang/tools/cir-translate/cir-translate.cpp b/clang/tools/cir-translate/cir-translate.cpp index cc3b7dec291d1..f99d89d9b0be4 100644 --- a/clang/tools/cir-translate/cir-translate.cpp +++ b/clang/tools/cir-translate/cir-translate.cpp @@ -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(); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
