https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/219487
>From d4a522af9b1910055fc051265a634051e5b5bb5d Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Wed, 26 Aug 2026 13:10:05 -0700 Subject: [PATCH] [CIR] Layout _BitInt types in record/array in CIR as it is in LLVM-IR I've worked through this quite a bit, and spent some time working on seeing if I could do this during LowerToLLVM, however this causes a ton of complication, as this level of change affects basically every member-access invariant that we have. Additionally, we have prior art (bool -> 8 bits, FP80 -> 128 bits), that I think it makes sense at least to 'put it with the rest'. The problem is that the 'i' types for bitint(which they are lowered to) don't match alignment-wise to the BitInt types. As a result, unless we do a bunch of transformations to change the struct/array/etc types (plus the get-member/initialization, etc stuff this entails), we're going to be reprensenting these types incorrectly. We have prior art for this as well, particularly around zero-length bitfields (which we represent as a field in the LLVM-IR to prevent the above conflicts). This patch does this layout at the CIR level, which gives us layout parity to LLVM-IR, as well as making sure we represent things correctly in LLVM-IR. Note: This patch was heavily authored by Claude, though I've done my best to review and confirm every line of it. --- .../include/clang/CIR/Dialect/IR/CIRTypes.td | 11 + clang/include/clang/CIR/LoweringHelpers.h | 4 + .../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 24 +- clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 21 +- .../TargetLowering/CIRABIRewriteContext.cpp | 21 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 65 +---- clang/lib/CIR/Lowering/LoweringHelpers.cpp | 58 ++++- clang/test/CIR/CodeGen/attr-noundef.cpp | 4 +- clang/test/CIR/CodeGen/bitint-record-layout.c | 224 ++++++++++++++++++ .../CIR/CodeGen/bitint-split-storage-nyi.c | 22 ++ .../call-conv-lowering-x86_64-variadic.c | 8 +- 11 files changed, 380 insertions(+), 82 deletions(-) create mode 100644 clang/test/CIR/CodeGen/bitint-record-layout.c diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index acbd6ad071d63..26c0f7689d97b 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -93,6 +93,17 @@ def CIR_IntType : CIR_Type<"Int", "int", [ /// Returns a maximum bitwidth of cir::IntType. /// Matches llvm::IntegerType::MAX_INT_BITS (1 << 23). static unsigned maxBitwidth() { return (1 << 23); } + + /// The bit-width of this integer type when stored via LLVM-IR. This + /// is just sizeof(ty)*CHAR_BIT for all but _BitInt, which is represented as + /// widened for layout. + unsigned getStorageTypeWidth(const mlir::DataLayout &dataLayout) const; + + /// Like getStorageTypeWidth, this gets the alignment of the type when + /// lowered to LLVM-IR for the purposes of ensuring we get layout correct + /// for record types (particularly around _BitInt, which has a different + /// alignment in LLVM-IR vs the FE). + uint64_t getStorageTypeAlignment(const mlir::DataLayout &dataLayout) const; }]; let genVerifyDecl = 1; } diff --git a/clang/include/clang/CIR/LoweringHelpers.h b/clang/include/clang/CIR/LoweringHelpers.h index f0f65bb317521..fe61db3fc5d25 100644 --- a/clang/include/clang/CIR/LoweringHelpers.h +++ b/clang/include/clang/CIR/LoweringHelpers.h @@ -76,4 +76,8 @@ mlir::Value createAnd(mlir::OpBuilder &bld, mlir::Value lhs, const llvm::APInt &rhs); mlir::Value createLShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs); + +mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter, + mlir::DataLayout const &dataLayout, + mlir::Type type); #endif diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp index a103b68331a8d..7451bf6fbd4aa 100644 --- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp @@ -152,7 +152,17 @@ struct CIRRecordLowering final { CharUnits getSizeInBits(mlir::Type ty) { return CharUnits::fromQuantity(dataLayout.layout.getTypeSizeInBits(ty)); } - CharUnits getAlignment(mlir::Type Ty) { + + CharUnits getMemberAlignment(mlir::Type Ty) { + // Recurse on Arrays, they have the member alignment of their element type. + if (auto arrayTy = mlir::dyn_cast<cir::ArrayType>(Ty)) + return getMemberAlignment(arrayTy.getElementType()); + // Int types (_BitInt in particular) share the alignment of their storage + // type. + if (auto intTy = mlir::dyn_cast<cir::IntType>(Ty)) + return CharUnits::fromQuantity( + intTy.getStorageTypeAlignment(dataLayout.layout)); + return CharUnits::fromQuantity(dataLayout.layout.getTypeABIAlignment(Ty)); } @@ -744,11 +754,11 @@ void CIRRecordLowering::determinePacked(bool nvBaseType) { continue; // If any member falls at an offset that it not a multiple of its alignment, // then the entire record must be packed. - if (!member.offset.isMultipleOf(getAlignment(member.data))) + if (!member.offset.isMultipleOf(getMemberAlignment(member.data))) packed = true; if (member.offset < nvSize) - nvAlignment = std::max(nvAlignment, getAlignment(member.data)); - alignment = std::max(alignment, getAlignment(member.data)); + nvAlignment = std::max(nvAlignment, getMemberAlignment(member.data)); + alignment = std::max(alignment, getMemberAlignment(member.data)); } // If the size of the record (the capstone's offset) is not a multiple of the // record's alignment, it must be packed. @@ -786,8 +796,8 @@ void CIRRecordLowering::insertPadding() { CharUnits offset = member.offset; assert(offset >= size); // Insert padding if we need to. - if (offset != - size.alignTo(packed ? CharUnits::One() : getAlignment(member.data))) + if (offset != size.alignTo(packed ? CharUnits::One() + : getMemberAlignment(member.data))) padding.push_back(std::make_pair(size, offset - size)); size = offset + getSize(member.data); } @@ -1055,7 +1065,7 @@ void CIRRecordLowering::lowerUnion(bool nonVirtualBaseType) { // Else we just add padding normally. appendPaddingBytes(layoutSize - getSize(storageType)); } - packed = !layoutSize.isMultipleOf(getAlignment(storageType)); + packed = !layoutSize.isMultipleOf(getMemberAlignment(storageType)); } bool CIRRecordLowering::hasOwnStorage(const CXXRecordDecl *decl, diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index 1bed5de96474a..897063171e76a 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -846,6 +846,8 @@ UnionType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, uint64_t UnionType::getABIAlignment(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params) const { + if (getPacked()) + return 1; mlir::Type storage = getUnionStorageType(dataLayout); if (!storage) return 1; @@ -1029,7 +1031,24 @@ void IntType::print(mlir::AsmPrinter &printer) const { llvm::TypeSize IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, mlir::DataLayoutEntryListRef params) const { - return llvm::TypeSize::getFixed(getWidth()); + return llvm::TypeSize::getFixed(getStorageTypeWidth(dataLayout)); +} + +unsigned +IntType::getStorageTypeWidth(const mlir::DataLayout &dataLayout) const { + if (!isBitInt()) + return getWidth(); + uint64_t alignBits = getABIAlignment(dataLayout, {}) * 8; + return static_cast<unsigned>(llvm::alignTo(getWidth(), alignBits)); +} + +uint64_t +IntType::getStorageTypeAlignment(const mlir::DataLayout &dataLayout) const { + if (!isBitInt()) + return getABIAlignment(dataLayout, {}); + auto storageTy = + mlir::IntegerType::get(getContext(), getStorageTypeWidth(dataLayout)); + return dataLayout.getTypeABIAlignment(storageTy); } uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout, diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp index 8d4c3b19c213d..8cf332bbbefa3 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp @@ -274,6 +274,22 @@ mlir::ArrayAttr updateResAttrs(mlir::MLIRContext *ctx, return mlir::ArrayAttr::get(ctx, {mlir::DictionaryAttr::get(ctx, attrs)}); } +/// The number of bytes a coercion memory slot needs to hold a value of type +/// \p ty without truncating it. For most types this is the ordinary storage +/// size. For a _BitInt it is deliberately the value's own literal byte +/// footprint (ceil(width/8)) rather than the wider, ABI-alignment-padded +/// footprint a _BitInt gets as a record member (see +/// cir::IntType::getStorageTypeWidth): this coercion is about how many bytes +/// the *value* needs to round-trip, not how a record would lay it out, and +/// those are genuinely different questions for a _BitInt (e.g. _BitInt(33) +/// only needs 5 bytes here, even though it occupies 8 padded bytes as a +/// record member). +static uint64_t coercionByteSize(mlir::Type ty, const mlir::DataLayout &dl) { + if (auto intTy = mlir::dyn_cast<cir::IntType>(ty)) + return llvm::divideCeil(intTy.getWidth(), 8); + return dl.getTypeSize(ty); +} + /// Coerce \p src into a temporary memory slot typed for \p dstTy at the /// current builder insertion point, and return the destination-typed pointer /// to that slot without loading the value back out. This is the shared @@ -310,8 +326,9 @@ emitCoercionToMemory(mlir::OpBuilder &builder, mlir::Location loc, uint64_t srcAlign = dl.getTypeABIAlignment(srcTy); uint64_t dstAlign = dl.getTypeABIAlignment(dstTy); uint64_t allocaAlign = std::max(srcAlign, dstAlign); - mlir::Type slotTy = - dl.getTypeSize(srcTy) >= dl.getTypeSize(dstTy) ? srcTy : dstTy; + mlir::Type slotTy = coercionByteSize(srcTy, dl) >= coercionByteSize(dstTy, dl) + ? srcTy + : dstTy; auto slotPtrTy = cir::PointerType::get(slotTy); auto srcPtrTy = cir::PointerType::get(srcTy); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 9ee597b81df24..66de2388c2345 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -76,69 +76,6 @@ mlir::Type elementTypeIfVector(mlir::Type type) { } } // namespace -/// In-memory storage width in bits for a _BitInt(N): N rounded up to the type's -/// ABI alignment. This equals sizeof(_BitInt(N)) * 8 on the default target -/// (e.g. _BitInt(6) -> 8, _BitInt(17) -> 32, _BitInt(128) -> 128). -static unsigned getBitIntMemoryStorageBits(cir::IntType ty, - const mlir::DataLayout &dataLayout) { - uint64_t alignBits = ty.getABIAlignment(dataLayout, {}) * 8; - return llvm::alignTo(ty.getWidth(), alignBits); -} - -/// A _BitInt(N) whose padded storage integer iM has a larger alloc size than -/// its M/8 store size is laid out by clang as a byte array, not a plain integer -/// (e.g. _BitInt(129) -> i192 with alloc size 32 != store size 24). That -/// "split" storage form is not yet implemented; lowerings must detect it and -/// report errorNYI rather than emit the wrong-sized integer. -static bool isSplitStorageBitInt(cir::IntType ty, - const mlir::DataLayout &dataLayout) { - if (!ty.isBitInt()) - return false; - unsigned storageBits = getBitIntMemoryStorageBits(ty, dataLayout); - auto storageTy = mlir::IntegerType::get(ty.getContext(), storageBits); - uint64_t storeSize = storageBits / 8; - uint64_t allocSize = - llvm::alignTo(storeSize, dataLayout.getTypeABIAlignment(storageTy)); - return allocSize != storeSize; -} - -/// Given a type convertor and a data layout, convert the given type to a type -/// that is suitable for memory operations. For example, this can be used to -/// lower cir.bool accesses to i8. -static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter, - mlir::DataLayout const &dataLayout, - mlir::Type type) { - // TODO(cir): Handle other types similarly to clang's codegen - // convertTypeForMemory - if (isa<cir::BoolType>(type)) { - return mlir::IntegerType::get(type.getContext(), - dataLayout.getTypeSizeInBits(type)); - } - - if (auto vecTy = mlir::dyn_cast<cir::VectorType>(type)) { - if (mlir::isa<cir::BoolType>(vecTy.getElementType())) { - assert(!cir::MissingFeatures::hlsl()); - // Pad to at least one byte. - uint64_t bytePadded = std::max<uint64_t>(vecTy.getSize(), 8); - return mlir::IntegerType::get(type.getContext(), bytePadded); - } - } - - // _BitInt(N) keeps its literal width as a value but is stored in a padded - // integer iM in memory, the same way bool is i1 as a value and i8 in memory. - // The byte-array storage form for wide split widths is not implemented; a - // null return signals that, and op lowerings turn it into errorNYI. - if (auto intTy = mlir::dyn_cast<cir::IntType>(type); - intTy && intTy.isBitInt()) { - if (isSplitStorageBitInt(intTy, dataLayout)) - return {}; - return mlir::IntegerType::get( - type.getContext(), getBitIntMemoryStorageBits(intTy, dataLayout)); - } - - return converter.convertType(type); -} - /// Alignment to use for a memory access whose op carries no explicit alignment. /// For _BitInt the storage integer iM's ABI alignment (e.g. i128's 16) /// over-aligns the value, so use the CIR _BitInt ABI alignment (e.g. 8). @@ -179,7 +116,7 @@ static mlir::Value castBitIntMemoryStorage(mlir::ConversionPatternRewriter &rewriter, const mlir::DataLayout &dataLayout, cir::IntType intTy, mlir::Value value, bool toMemory) { - unsigned storageBits = getBitIntMemoryStorageBits(intTy, dataLayout); + unsigned storageBits = intTy.getStorageTypeWidth(dataLayout); if (storageBits == intTy.getWidth()) return value; unsigned dstBits = toMemory ? storageBits : intTy.getWidth(); diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp b/clang/lib/CIR/Lowering/LoweringHelpers.cpp index 9ffb62a9cd026..1dad8beaa4bce 100644 --- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp +++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp @@ -16,6 +16,60 @@ #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/SymbolTable.h" #include "mlir/Interfaces/DataLayoutInterfaces.h" +#include "clang/CIR/MissingFeatures.h" + +namespace { +/// A _BitInt(N) whose padded storage integer iM has a larger alloc size than +/// its M/8 store size is laid out by clang as a byte array, not a plain +/// integer (e.g. _BitInt(129) -> i192 with alloc size 32 != store size 24). +/// That "split" storage form is not yet implemented; lowerings must detect +/// it and report errorNYI rather than emit the wrong-sized integer. +bool isSplitStorageBitInt(cir::IntType ty, const mlir::DataLayout &dataLayout) { + if (!ty.isBitInt()) + return false; + unsigned storageBits = ty.getStorageTypeWidth(dataLayout); + auto storageTy = mlir::IntegerType::get(ty.getContext(), storageBits); + uint64_t storeSize = storageBits / 8; + uint64_t allocSize = + llvm::alignTo(storeSize, dataLayout.getTypeABIAlignment(storageTy)); + return allocSize != storeSize; +} +} // namespace + +mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter, + mlir::DataLayout const &dataLayout, + mlir::Type type) { + // TODO(cir): Handle other types similarly to clang's codegen + // convertTypeForMemory + if (mlir::isa<cir::BoolType>(type)) { + return mlir::IntegerType::get(type.getContext(), + dataLayout.getTypeSizeInBits(type)); + } + + if (auto vecTy = mlir::dyn_cast<cir::VectorType>(type)) { + if (mlir::isa<cir::BoolType>(vecTy.getElementType())) { + assert(!cir::MissingFeatures::hlsl()); + // Pad to at least one byte. + uint64_t bytePadded = std::max<uint64_t>(vecTy.getSize(), 8); + return mlir::IntegerType::get(type.getContext(), bytePadded); + } + } + + // _BitInt(N) keeps its literal width as a value but is stored in a padded + // integer iM in memory, the same way bool is i1 as a value and i8 in + // memory. The byte-array storage form for wide split widths is not + // implemented; a null return signals that, and op lowerings turn it into + // errorNYI. + if (auto intTy = mlir::dyn_cast<cir::IntType>(type); + intTy && intTy.isBitInt()) { + if (isSplitStorageBitInt(intTy, dataLayout)) + return {}; + return mlir::IntegerType::get(type.getContext(), + intTy.getStorageTypeWidth(dataLayout)); + } + + return converter.convertType(type); +} static unsigned getIntOrBoolBitWidth(mlir::Type ty) { if (auto intTy = mlir::dyn_cast<cir::IntType>(ty)) @@ -539,8 +593,8 @@ static mlir::Type adjustGlobalUnionTypeForInit( // Unions can only initialize one field, so this has to be sizeof-one. assert(constRecord.getMembers().size() == 1); mlir::Attribute member = constRecord.getMembers()[0]; - mlir::Type memberTy = - converter.convertType(mlir::cast<mlir::TypedAttr>(member).getType()); + mlir::Type memberTy = convertTypeForMemory( + converter, dataLayout, mlir::cast<mlir::TypedAttr>(member).getType()); // The active member may itself need adjusting (e.g. it is a nested union, or // a struct containing one), so recurse before using its type below. diff --git a/clang/test/CIR/CodeGen/attr-noundef.cpp b/clang/test/CIR/CodeGen/attr-noundef.cpp index 856448be00247..f73d984d4e536 100644 --- a/clang/test/CIR/CodeGen/attr-noundef.cpp +++ b/clang/test/CIR/CodeGen/attr-noundef.cpp @@ -228,8 +228,8 @@ void pass_large_BitInt(_BitInt(127) e) { // CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic17pass_large_BitIntEDB127_ // LLVM: define {{.*}} i3 @_ZN12check_exotic10ret_BitIntEv( -// LLVM: define {{.*}} void @_ZN12check_exotic11pass_BitIntEDB3_(i3 % -// LLVM: define {{.*}} void @_ZN12check_exotic17pass_large_BitIntEDB127_(i127 % +// LLVM: define {{.*}} void @_ZN12check_exotic11pass_BitIntEDB3_(i3 noundef % +// LLVM: define {{.*}} void @_ZN12check_exotic17pass_large_BitIntEDB127_(i127 noundef % // OGCG: define {{.*}} noundef signext i3 @_ZN12check_exotic10ret_BitIntEv( // OGCG: define {{.*}} void @_ZN12check_exotic11pass_BitIntEDB3_(i3 noundef signext % diff --git a/clang/test/CIR/CodeGen/bitint-record-layout.c b/clang/test/CIR/CodeGen/bitint-record-layout.c new file mode 100644 index 0000000000000..3a4bf8cfaf105 --- /dev/null +++ b/clang/test/CIR/CodeGen/bitint-record-layout.c @@ -0,0 +1,224 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -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 -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM,LLVMCIR --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM,OGCG --input-file=%t.ll %s + +union JustBIUnion { + _BitInt(65) bi; +}; +// CIR-DAG: !rec_JustBIUnion = !cir.union<"JustBIUnion" {data !cir.int<s, 65, bitint>}> +// LLVM-DAG: %union.JustBIUnion = type { i128 } + +struct SmallerUnionMem { long long a; int b; }; +// CIR-DAG: !rec_SmallerUnionMem = !cir.struct<"SmallerUnionMem" {data !s64i, data !s32i}> +// LLVM-DAG: %struct.SmallerUnionMem = type { i64, i32 } + +union BIUnion { + _BitInt(65) bi; + struct SmallerUnionMem m; +}; +// CIR-DAG: !rec_BIUnion = !cir.union<"BIUnion" {data !cir.int<s, 65, bitint>, data !rec_SmallerUnionMem}> +// LLVM-DAG: %union.BIUnion = type { i128 } + +union BIUnionArr { + _BitInt(65) bi; + char arr[20]; +}; +// CIR-DAG: !rec_BIUnionArr = !cir.union<"BIUnionArr" packed {data !cir.int<s, 65, bitint>, data !cir.array<!s8i x 20>}, padding = {!cir.array<!u8i x 8>}> +// LLVM-DAG: %union.BIUnionArr = type <{ i128, [8 x i8] }> + +struct First65 { + _BitInt(65) bi; + int i; +}; +// CIR-DAG: !rec_First65 = !cir.struct<"First65" packed {data !cir.int<s, 65, bitint>, data !s32i, pad !cir.array<!u8i x 4>}> +// LLVM-DAG: %struct.First65 = type <{ i128, i32, [4 x i8] }> + +struct Middle65 { + char c; + _BitInt(65) bi; + int i; +}; +// CIR-DAG: !rec_Middle65 = !cir.struct<"Middle65" packed {data !s8i, pad !cir.array<!u8i x 7>, data !cir.int<s, 65, bitint>, data !s32i, pad !cir.array<!u8i x 4>}> +// LLVM-DAG: %struct.Middle65 = type <{ i8, [7 x i8], i128, i32, [4 x i8] }> + +struct Last65 { + int i; + _BitInt(65) bi; +}; +// CIR-DAG: !rec_Last65 = !cir.struct<"Last65" packed {data !s32i, pad !cir.array<!u8i x 4>, data !cir.int<s, 65, bitint>}> +// LLVM-DAG: %struct.Last65 = type <{ i32, [4 x i8], i128 }> + +struct First127 { + _BitInt(127) bi; + int i; +}; +// CIR-DAG: !rec_First127 = !cir.struct<"First127" packed {data !cir.int<s, 127, bitint>, data !s32i, pad !cir.array<!u8i x 4>}> +// LLVM-DAG: %struct.First127 = type <{ i128, i32, [4 x i8] }> + +struct Middle127 { + char c; + _BitInt(127) bi; + int i; +}; +// CIR-DAG: !rec_Middle127 = !cir.struct<"Middle127" packed {data !s8i, pad !cir.array<!u8i x 7>, data !cir.int<s, 127, bitint>, data !s32i, pad !cir.array<!u8i x 4>}> +// LLVM-DAG: %struct.Middle127 = type <{ i8, [7 x i8], i128, i32, [4 x i8] }> + +struct Last127 { + int i; + _BitInt(127) bi; +}; +// CIR-DAG: !rec_Last127 = !cir.struct<"Last127" packed {data !s32i, pad !cir.array<!u8i x 4>, data !cir.int<s, 127, bitint>}> +// LLVM-DAG: %struct.Last127 = type <{ i32, [4 x i8], i128 }> + +struct First128 { + _BitInt(128) bi; + int i; +}; +// CIR-DAG: !rec_First128 = !cir.struct<"First128" packed {data !s128i_bitint, data !s32i, pad !cir.array<!u8i x 4>}> +// LLVM-DAG: %struct.First128 = type <{ i128, i32, [4 x i8] }> + +struct Middle128 { + char c; + _BitInt(128) bi; + int i; +}; +// CIR-DAG: !rec_Middle128 = !cir.struct<"Middle128" packed {data !s8i, pad !cir.array<!u8i x 7>, data !s128i_bitint, data !s32i, pad !cir.array<!u8i x 4>}> +// LLVM-DAG: %struct.Middle128 = type <{ i8, [7 x i8], i128, i32, [4 x i8] }> + +struct Last128 { + int i; + _BitInt(128) bi; +}; +// CIR-DAG: !rec_Last128 = !cir.struct<"Last128" packed {data !s32i, pad !cir.array<!u8i x 4>, data !s128i_bitint}> +// LLVM-DAG: %struct.Last128 = type <{ i32, [4 x i8], i128 }> + +struct ArrMem { + int i; + _BitInt(128) bi[2]; +}; +// CIR-DAG: !rec_ArrMem = !cir.struct<"ArrMem" packed {data !s32i, pad !cir.array<!u8i x 4>, data !cir.array<!s128i_bitint x 2>}> +// LLVM-DAG: %struct.ArrMem = type <{ i32, [4 x i8], [2 x i128] }> + +struct Inner { + int i; + _BitInt(128) bi; +}; +// CIR-DAG: !rec_Inner = !cir.struct<"Inner" packed {data !s32i, pad !cir.array<!u8i x 4>, data !s128i_bitint}> +// LLVM-DAG: %struct.Inner = type <{ i32, [4 x i8], i128 }> +struct Outer { + char c; + struct Inner inner; +}; +// CIR-DAG: !rec_Outer = !cir.struct<"Outer" {data !s8i, pad !cir.array<!u8i x 7>, data !rec_Inner}> +// LLVM-DAG: %struct.Outer = type { i8, [7 x i8], %struct.Inner } + +struct Inner2 { + int i; + _BitInt(128) bi; +}; +// CIR-DAG: !rec_Inner2 = !cir.struct<"Inner2" packed {data !s32i, pad !cir.array<!u8i x 4>, data !s128i_bitint}> +// LLVM-DAG: %struct.Inner2 = type <{ i32, [4 x i8], i128 }> + +struct Outer2 { + char c; + struct Inner2 inner; + short s; +}; +// CIR-DAG: !rec_Outer2 = !cir.struct<"Outer2" {data !s8i, pad !cir.array<!u8i x 7>, data !rec_Inner2, data !s16i, pad !cir.array<!u8i x 6>}> +// LLVM-DAG: %struct.Outer2 = type { i8, [7 x i8], %struct.Inner2, i16, [6 x i8] } + + +union JustBIUnion jbiu = { .bi = 54321 }; +// CIR-DAG: cir.global external @jbiu = #cir.const_record<{#cir.int<54321> : !cir.int<s, 65, bitint>}> : !rec_JustBIUnion {alignment = 8 : i64} +// LLVM-DAG: @jbiu = global %union.JustBIUnion { i128 54321 }, align 8 +union BIUnion biunion = { .bi = 12345 }; +// CIR-DAG: cir.global external @biunion = #cir.const_record<{#cir.int<12345> : !cir.int<s, 65, bitint>}> : !rec_BIUnion {alignment = 8 : i64} +// LLVM-DAG: @biunion = global %union.BIUnion { i128 12345 }, align 8 + +union BIUnionArr biuarr = { .arr = { 'a', 'b', 'c' } }; +// CIR-DAG: cir.global external @biuarr = #cir.const_record<{#cir.const_array<[#cir.int<97> : !s8i, #cir.int<98> : !s8i, #cir.int<99> : !s8i], trailing_zeros> : !cir.array<!s8i x 20>}> : !rec_BIUnionArr {alignment = 8 : i64} +// Classic-codegen represents the constant by splitting the init part of +// the string and the zeros separately, plus not as a string. Else this is effectively the same. +// LLVMCIR-DAG: @biuarr = global <{ [20 x i8], [4 x i8] }> <{ [20 x i8] c"abc\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", [4 x i8] zeroinitializer }>, align 8 +// OGCG-DAG: @biuarr = global { <{ i8, i8, i8, [17 x i8] }>, [4 x i8] } { <{ i8, i8, i8, [17 x i8] }> <{ i8 97, i8 98, i8 99, [17 x i8] zeroinitializer }>, [4 x i8] zeroinitializer }, align 8 + +struct First65 f65[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @f65 = #cir.const_array<[#cir.const_record<{#cir.int<1> : !cir.int<s, 65, bitint>, #cir.int<222> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First65, #cir.const_record<{#cir.int<3> : !cir.int<s, 65, bitint>, #cir.int<444> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First65]> : !cir.array<!rec_First65 x 2> {alignment = 16 : i64} +// LLVM-DAG: @f65 = global [2 x %struct.First65] [%struct.First65 <{ i128 1, i32 222, [4 x i8] zeroinitializer }>, %struct.First65 <{ i128 3, i32 444, [4 x i8] zeroinitializer }>], align 16 +struct Middle65 m65[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @m65 = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s8i, #cir.zero : !cir.array<!u8i x 7>, #cir.int<222> : !cir.int<s, 65, bitint>, #cir.int<0> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_Middle65, #cir.const_record<{#cir.int<3> : !s8i, #cir.zero : !cir.array<!u8i x 7>, #cir.int<444> : !cir.int<s, 65, bitint>, #cir.int<0> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_Middle65]> : !cir.array<!rec_Middle65 x 2> {alignment = 16 : i64} +// LLVM-DAG: @m65 = global [2 x %struct.Middle65] [%struct.Middle65 <{ i8 1, [7 x i8] zeroinitializer, i128 222, i32 0, [4 x i8] zeroinitializer }>, %struct.Middle65 <{ i8 3, [7 x i8] zeroinitializer, i128 444, i32 0, [4 x i8] zeroinitializer }>], align 16 +struct Last65 l65[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @l65 = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<222> : !cir.int<s, 65, bitint>}> : !rec_Last65, #cir.const_record<{#cir.int<3> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<444> : !cir.int<s, 65, bitint>}> : !rec_Last65]> : !cir.array<!rec_Last65 x 2> {alignment = 16 : i64} +// LLVM-DAG: @l65 = global [2 x %struct.Last65] [%struct.Last65 <{ i32 1, [4 x i8] zeroinitializer, i128 222 }>, %struct.Last65 <{ i32 3, [4 x i8] zeroinitializer, i128 444 }>], align 16 + +struct First127 f127[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @f127 = #cir.const_array<[#cir.const_record<{#cir.int<1> : !cir.int<s, 127, bitint>, #cir.int<222> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First127, #cir.const_record<{#cir.int<3> : !cir.int<s, 127, bitint>, #cir.int<444> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First127]> : !cir.array<!rec_First127 x 2> {alignment = 16 : i64} +// LLVM-DAG: @f127 = global [2 x %struct.First127] [%struct.First127 <{ i128 1, i32 222, [4 x i8] zeroinitializer }>, %struct.First127 <{ i128 3, i32 444, [4 x i8] zeroinitializer }>], align 16 +struct Middle127 m127[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @m127 = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s8i, #cir.zero : !cir.array<!u8i x 7>, #cir.int<222> : !cir.int<s, 127, bitint>, #cir.int<0> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_Middle127, #cir.const_record<{#cir.int<3> : !s8i, #cir.zero : !cir.array<!u8i x 7>, #cir.int<444> : !cir.int<s, 127, bitint>, #cir.int<0> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_Middle127]> : !cir.array<!rec_Middle127 x 2> {alignment = 16 : i64} +// LLVM-DAG: @m127 = global [2 x %struct.Middle127] [%struct.Middle127 <{ i8 1, [7 x i8] zeroinitializer, i128 222, i32 0, [4 x i8] zeroinitializer }>, %struct.Middle127 <{ i8 3, [7 x i8] zeroinitializer, i128 444, i32 0, [4 x i8] zeroinitializer }>], align 16 +struct Last127 l127[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @l127 = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<222> : !cir.int<s, 127, bitint>}> : !rec_Last127, #cir.const_record<{#cir.int<3> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<444> : !cir.int<s, 127, bitint>}> : !rec_Last127]> : !cir.array<!rec_Last127 x 2> {alignment = 16 : i64} +// LLVM-DAG: @l127 = global [2 x %struct.Last127] [%struct.Last127 <{ i32 1, [4 x i8] zeroinitializer, i128 222 }>, %struct.Last127 <{ i32 3, [4 x i8] zeroinitializer, i128 444 }>], align 16 + +struct First128 f128[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @f128 = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s128i_bitint, #cir.int<222> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First128, #cir.const_record<{#cir.int<3> : !s128i_bitint, #cir.int<444> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First128]> : !cir.array<!rec_First128 x 2> {alignment = 16 : i64} +// LLVM-DAG: @f128 = global [2 x %struct.First128] [%struct.First128 <{ i128 1, i32 222, [4 x i8] zeroinitializer }>, %struct.First128 <{ i128 3, i32 444, [4 x i8] zeroinitializer }>], align 16 +struct Middle128 m128[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @m128 = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s8i, #cir.zero : !cir.array<!u8i x 7>, #cir.int<222> : !s128i_bitint, #cir.int<0> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_Middle128, #cir.const_record<{#cir.int<3> : !s8i, #cir.zero : !cir.array<!u8i x 7>, #cir.int<444> : !s128i_bitint, #cir.int<0> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_Middle128]> : !cir.array<!rec_Middle128 x 2> {alignment = 16 : i64} +// LLVM-DAG: @m128 = global [2 x %struct.Middle128] [%struct.Middle128 <{ i8 1, [7 x i8] zeroinitializer, i128 222, i32 0, [4 x i8] zeroinitializer }>, %struct.Middle128 <{ i8 3, [7 x i8] zeroinitializer, i128 444, i32 0, [4 x i8] zeroinitializer }>], align 16 +struct Last128 l128[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @l128 = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<222> : !s128i_bitint}> : !rec_Last128, #cir.const_record<{#cir.int<3> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<444> : !s128i_bitint}> : !rec_Last128]> : !cir.array<!rec_Last128 x 2> {alignment = 16 : i64} +// LLVM-DAG: @l128 = global [2 x %struct.Last128] [%struct.Last128 <{ i32 1, [4 x i8] zeroinitializer, i128 222 }>, %struct.Last128 <{ i32 3, [4 x i8] zeroinitializer, i128 444 }>], align 16 + +struct ArrMem arrMem[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @arrMem = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.const_array<[#cir.int<222> : !s128i_bitint], trailing_zeros> : !cir.array<!s128i_bitint x 2>}> : !rec_ArrMem, #cir.const_record<{#cir.int<3> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.const_array<[#cir.int<444> : !s128i_bitint], trailing_zeros> : !cir.array<!s128i_bitint x 2>}> : !rec_ArrMem]> : !cir.array<!rec_ArrMem x 2> {alignment = 16 : i64} +// LLVM-DAG: @arrMem = global [2 x %struct.ArrMem] [%struct.ArrMem <{ i32 1, [4 x i8] zeroinitializer, [2 x i128] [i128 222, i128 0] }>, %struct.ArrMem <{ i32 3, [4 x i8] zeroinitializer, [2 x i128] [i128 444, i128 0] }>], align 16 + +struct Outer nestedArr[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @nestedArr = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s8i, #cir.zero : !cir.array<!u8i x 7>, #cir.const_record<{#cir.int<222> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<0> : !s128i_bitint}> : !rec_Inner}> : !rec_Outer, #cir.const_record<{#cir.int<3> : !s8i, #cir.zero : !cir.array<!u8i x 7>, #cir.const_record<{#cir.int<444> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<0> : !s128i_bitint}> : !rec_Inner}> : !rec_Outer]> : !cir.array<!rec_Outer x 2> {alignment = 16 : i64} +// LLVM-DAG: @nestedArr = global [2 x %struct.Outer] [%struct.Outer { i8 1, [7 x i8] zeroinitializer, %struct.Inner <{ i32 222, [4 x i8] zeroinitializer, i128 0 }> }, %struct.Outer { i8 3, [7 x i8] zeroinitializer, %struct.Inner <{ i32 444, [4 x i8] zeroinitializer, i128 0 }> }], align 16 +struct Outer2 nestedArr2[2] = {{1, 222}, {3, 444}}; +// CIR-DAG: cir.global external @nestedArr2 = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s8i, #cir.zero : !cir.array<!u8i x 7>, #cir.const_record<{#cir.int<222> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<0> : !s128i_bitint}> : !rec_Inner2, #cir.int<0> : !s16i, #cir.zero : !cir.array<!u8i x 6>}> : !rec_Outer2, #cir.const_record<{#cir.int<3> : !s8i, #cir.zero : !cir.array<!u8i x 7>, #cir.const_record<{#cir.int<444> : !s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<0> : !s128i_bitint}> : !rec_Inner2, #cir.int<0> : !s16i, #cir.zero : !cir.array<!u8i x 6>}> : !rec_Outer2]> : !cir.array<!rec_Outer2 x 2> {alignment = 16 : i64} +// LLVM-DAG: @nestedArr2 = global [2 x %struct.Outer2] [%struct.Outer2 { i8 1, [7 x i8] zeroinitializer, %struct.Inner2 <{ i32 222, [4 x i8] zeroinitializer, i128 0 }>, i16 0, [6 x i8] zeroinitializer }, %struct.Outer2 { i8 3, [7 x i8] zeroinitializer, %struct.Inner2 <{ i32 444, [4 x i8] zeroinitializer, i128 0 }>, i16 0, [6 x i8] zeroinitializer }], align 16 + +_BitInt(128) get_bi(void) { return l128[1].bi; } +// CIR-LABEL: cir.func no_inline dso_local @get_bi() -> !s128i_bitint +// CIR-NEXT: %[[RET_ALLOC:.*]] = cir.alloca "__retval" align(8) : !cir.ptr<!s128i_bitint> +// CIR-NEXT: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @l128 : !cir.ptr<!cir.array<!rec_Last128 x 2>> +// CIR-NEXT: %[[ARR_GEP:.*]] = cir.get_element %[[GET_GLOB]][%[[ONE]] : !s64i] : !cir.ptr<!cir.array<!rec_Last128 x 2>> -> !cir.ptr<!rec_Last128> +// CIR-NEXT: %[[GET_BI:.*]] = cir.get_member %[[ARR_GEP]][2] {name = "bi"} : !cir.ptr<!rec_Last128> -> !cir.ptr<!s128i_bitint> +// CIR-NEXT: %[[LOAD_BI:.*]] = cir.load align(8) %[[GET_BI]] : !cir.ptr<!s128i_bitint>, !s128i_bitint +// CIR-NEXT: cir.store %[[LOAD_BI]], %[[RET_ALLOC]] : !s128i_bitint, !cir.ptr<!s128i_bitint> +// CIR-NEXT: %[[RET_LOAD:.*]] = cir.load %[[RET_ALLOC]] : !cir.ptr<!s128i_bitint>, !s128i_bitint +// CIR-NEXT: cir.return %[[RET_LOAD]] : !s128i_bitint +// LLVM-LABEL: define dso_local i128 @get_bi() +// LLVM: load i128, ptr getelementptr inbounds nuw (i8, ptr @l128, i64 32), align 8 + +_BitInt(128) get_bi2(void) { return arrMem[1].bi[1]; } +// CIR-LABEL: cir.func no_inline dso_local @get_bi2() -> !s128i_bitint attributes {"cir.target-features" = "+cx8,+mmx,+sse,+sse2,+x87", nothrow} { +// CIR-NEXT: %[[RET_ALLOC:.*]] = cir.alloca "__retval" align(8) : !cir.ptr<!s128i_bitint> +// CIR-NEXT: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR-NEXT: %[[ONE_2:.*]] = cir.const #cir.int<1> : !s64i +// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @arrMem : !cir.ptr<!cir.array<!rec_ArrMem x 2>> +// CIR-NEXT: %[[ARR_GEP:.*]] = cir.get_element %[[GET_GLOB]][%[[ONE_2]] : !s64i] : !cir.ptr<!cir.array<!rec_ArrMem x 2>> -> !cir.ptr<!rec_ArrMem> +// CIR-NEXT: %[[GET_BI_ARR:.*]] = cir.get_member %[[ARR_GEP]][2] {name = "bi"} : !cir.ptr<!rec_ArrMem> -> !cir.ptr<!cir.array<!s128i_bitint x 2>> +// CIR-NEXT: %[[GET_BI_ELT:.*]] = cir.get_element %[[GET_BI_ARR]][%[[ONE]] : !s64i] : !cir.ptr<!cir.array<!s128i_bitint x 2>> -> !cir.ptr<!s128i_bitint> +// CIR-NEXT: %[[LOAD_BI:.*]] = cir.load align(8) %[[GET_BI_ELT]] : !cir.ptr<!s128i_bitint>, !s128i_bitint +// CIR-NEXT: cir.store %[[LOAD_BI]], %[[RET_ALLOC]] : !s128i_bitint, !cir.ptr<!s128i_bitint> +// CIR-NEXT: %[[RET_LOAD:.*]] = cir.load %[[RET_ALLOC]] : !cir.ptr<!s128i_bitint>, !s128i_bitint +// CIR-NEXT: cir.return %[[RET_LOAD]] : !s128i_bitint +// LLVM-LABEL: define dso_local i128 @get_bi2() +// LLVM: load i128, ptr getelementptr inbounds nuw (i8, ptr @arrMem, i64 64), align 8 + + +void force_emit() { + union BIUnionArr b; + struct SmallerUnionMem su; +} + diff --git a/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c b/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c index f536901476c62..a228506d9ad41 100644 --- a/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c +++ b/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c @@ -4,6 +4,8 @@ // RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-call-conv-lowering -emit-llvm -DALLOCA %s -o - 2>&1 | FileCheck %s --check-prefix=ALLOCA // RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-call-conv-lowering -emit-llvm -DSTORE %s -o - 2>&1 | FileCheck %s --check-prefix=STORE // RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-call-conv-lowering -emit-llvm -DLOAD %s -o - 2>&1 | FileCheck %s --check-prefix=LOAD +// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-call-conv-lowering -emit-llvm -DSTRUCT %s -o - 2>&1 | FileCheck %s --check-prefix=STRUCT +// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-call-conv-lowering -emit-llvm -DARRAY %s -o - 2>&1 | FileCheck %s --check-prefix=ARRAY #ifdef GLOBAL signed _BitInt(129) g129 = 1; @@ -27,3 +29,23 @@ void store_lit(signed _BitInt(129) *p) { *p = (signed _BitInt(129))1; } int load_cmp(signed _BitInt(129) *p) { return *p != 0; } // LOAD: NYI: lowering load of a type with no memory representation #endif + +#ifdef STRUCT +// FIXME: Make sure we test that the layout of this and the array struct are +// 'correct' when this lowering is completed. +struct HasWide129 { + int i; + signed _BitInt(129) bi; +}; +struct HasWide129 g_struct; +// STRUCT: NYI: lowering global of a type with no memory representation +#endif + +#ifdef ARRAY +struct HasWide129Array { + int i; + signed _BitInt(129) bi[2]; +}; +struct HasWide129Array g_array; +// ARRAY: NYI: lowering global of a type with no memory representation +#endif diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c index e8785a0b283f1..6c00e8bfa8634 100644 --- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c +++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c @@ -201,14 +201,14 @@ int call_wide_char(Pair2 p, WideChar w) { return vf(p, w); } // declared parameter. int ell_bitint17(Pair2 p, _BitInt(17) b) { return vf(p, b); } -// CIR-LABEL: cir.func {{.*}}@ell_bitint17(%arg0: !u64i loc({{.+}}), %arg1: !cir.int<s, 17, bitint> {llvm.signext} loc({{.+}})) -> !s32i +// CIR-LABEL: cir.func {{.*}}@ell_bitint17(%arg0: !u64i loc({{.+}}), %arg1: !cir.int<s, 17, bitint> {llvm.noundef, llvm.signext} loc({{.+}})) -> !s32i // CIR: cir.store %arg1, %[[BSLOT:[0-9]+]] : !cir.int<s, 17, bitint>, !cir.ptr<!cir.int<s, 17, bitint>> // CIR: %[[BV:[0-9]+]] = cir.load align(4) %[[BSLOT]] : !cir.ptr<!cir.int<s, 17, bitint>>, !cir.int<s, 17, bitint> // CIR: %[[PV:[0-9]+]] = cir.load %{{[0-9]+}} : !cir.ptr<!u64i>, !u64i -// CIR: cir.call @vf(%[[PV]], %[[BV]]) : (!u64i, !cir.int<s, 17, bitint> {llvm.signext}) -> !s32i +// CIR: cir.call @vf(%[[PV]], %[[BV]]) : (!u64i, !cir.int<s, 17, bitint> {llvm.noundef, llvm.signext}) -> !s32i // LLVM-CIR-LABEL: define dso_local i32 @ell_bitint17( -// LLVM-CIR-SAME: i64 %[[P:[0-9a-zA-Z._]+]], i17 signext %[[B:[0-9a-zA-Z._]+]]) +// LLVM-CIR-SAME: i64 %[[P:[0-9a-zA-Z._]+]], i17 noundef signext %[[B:[0-9a-zA-Z._]+]]) // LLVM-OGCG-LABEL: define dso_local i32 @ell_bitint17( // LLVM-OGCG-SAME: i64 %[[P:[0-9a-zA-Z._]+]], i17 noundef signext %[[B:[0-9a-zA-Z._]+]]) // LLVM: %[[EXT:[0-9a-zA-Z._]+]] = sext i17 %[[B]] to i32 @@ -216,7 +216,7 @@ int ell_bitint17(Pair2 p, _BitInt(17) b) { return vf(p, b); } // LLVM: %[[RE:[0-9a-zA-Z._]+]] = load i32, ptr %[[BSLOT]], align 4 // LLVM: %[[TR:[0-9a-zA-Z._]+]] = trunc i32 %[[RE]] to i17 // LLVM: %[[PV:[0-9a-zA-Z._]+]] = load i64, ptr %{{[0-9a-zA-Z._]+}}, align -// LLVM-CIR: call i32 (i64, ...) @vf(i64 %[[PV]], i17 signext %[[TR]]) +// LLVM-CIR: call i32 (i64, ...) @vf(i64 %[[PV]], i17 noundef signext %[[TR]]) // LLVM-OGCG: call i32 (i64, ...) @vf(i64 %[[PV]], i17 noundef signext %[[TR]]) // A width between 33 and 63 widens to one register. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
