llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clangir Author: adams381 <details> <summary>Changes</summary> ClangIR keeps a `_BitInt(N)` at its literal width, but in memory it has to live in a wider padded integer, the same way `bool` is `i1` as a value and `i8` in memory. Because CIRGen emitted the constant at its exact width, the storage padding was left undefined: a `signed _BitInt(6) = -1` wrote `0x3f` where classic CodeGen and GCC write `0xff`. @<!-- -->andykaylor pointed this out on [#<!-- -->205605](https://github.com/llvm/llvm-project/pull/205605). The fix widens `_BitInt` to its storage integer `iM` and sign/zero-extends by signedness during lowering to the LLVM dialect, the same place `bool` becomes `i8` (`convertTypeForMemory` and the to/from-memory helpers). CIRGen keeps the literal `!cir.int<N, bitint>` unchanged. The byte-array storage form for wide "split" widths, where the storage integer's alloc size exceeds its store size (e.g. `_BitInt(129)` to `i192`, 32 vs 24 bytes), is not implemented. The global, alloca, load, and store lowerings report an NYI error and the aggregate type converters fail the conversion, rather than emit a wrong-sized integer. Atomic read-modify-write on a padded `_BitInt` and vector-of-`_BitInt` are also unimplemented. The storage width comes from `IntType::getABIAlignment`, which assumes a fixed 64-bit maximum alignment (x86-64). It is verified byte-for-byte on x86-64; on targets with a larger maximum (e.g. AArch64) any width that would be mis-sized instead hits the split-storage NYI. On a target whose `_BitInt` maximum alignment is below 64 bits (e.g. a 32-bit target) the storage can be mis-sized. Making the computation target-aware needs the target's `getBitIntAlign`, which is not in the data layout, and is left as a follow-up. The approach follows the RFC [Widen bool / _BitInt / ext-vector-bool to their in-memory types in lowering](https://discourse.llvm.org/t/rfc-clangir-widen-bool-bitint-ext-vector-bool-to-their-in-memory-types-in-lowering/91160). It supersedes [#<!-- -->205605](https://github.com/llvm/llvm-project/pull/205605), which emitted the constant at its literal width. --- Patch is 27.05 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/206606.diff 8 Files Affected: - (modified) clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp (+4-3) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+174-19) - (modified) clang/lib/CIR/Lowering/LoweringHelpers.cpp (+13-2) - (modified) clang/test/CIR/CodeGen/array.cpp (+4-3) - (added) clang/test/CIR/CodeGen/bitint-memory.c (+61) - (added) clang/test/CIR/CodeGen/bitint-split-storage-nyi.c (+11) - (modified) clang/test/CIR/CodeGen/bitint.c (+2-10) - (modified) clang/test/CIR/Lowering/global-var-simple.cpp (+2-2) ``````````diff diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp index 9ad172211ea60..3ba93fda17e68 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -1255,9 +1255,10 @@ mlir::Attribute ConstantEmitter::emitForMemory(CIRGenModule &cgm, cgm.errorNYI("emitForMemory: zero-extend HLSL bool vectors"); } - if (destType->isBitIntType()) { - cgm.errorNYI("emitForMemory: _BitInt type"); - } + // CIR represents source types as literally as possible. Some types, such as + // bool and _BitInt(N), are kept at their literal width here and expanded to + // their wider "in memory" types during lowering to the LLVM dialect, so the + // constant is already in the right form and needs no adjustment. return c; } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index e0fc9e58ed4b7..71320837ae576 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -76,6 +76,32 @@ 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. @@ -89,9 +115,46 @@ static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter, dataLayout.getTypeSizeInBits(type)); } + // _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); } +/// True for a _BitInt atomic operand whose width is not a natural atomic-legal +/// integer width. Such an operand's value type iN differs from its in-memory +/// storage iM, and the atomic op lowerings here pass the value through without +/// the widening the load/store helpers apply, so they must report errorNYI. +static bool isUnsupportedBitIntAtomic(mlir::Type cirType) { + auto intTy = mlir::dyn_cast<cir::IntType>(cirType); + if (!intTy || !intTy.isBitInt()) + return false; + unsigned width = intTy.getWidth(); + return width != 8 && width != 16 && width != 32 && width != 64 && + width != 128; +} + +/// 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). +static uint64_t getMemoryFallbackAlignment(mlir::Type cirType, + mlir::Type llvmMemType, + const mlir::DataLayout &dataLayout) { + if (auto intTy = mlir::dyn_cast<cir::IntType>(cirType); + intTy && intTy.isBitInt()) + return intTy.getABIAlignment(dataLayout, {}); + return dataLayout.getTypeABIAlignment(llvmMemType); +} + static mlir::Value createIntCast(mlir::OpBuilder &bld, mlir::Value src, mlir::IntegerType dstTy, bool isSigned = false) { @@ -137,6 +200,16 @@ static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter, return createIntCast(rewriter, value, rewriter.getI1Type()); } + // Truncate the padded storage integer back to the _BitInt's literal width. + if (auto intTy = mlir::dyn_cast<cir::IntType>(op.getType()); + intTy && intTy.isBitInt()) { + unsigned storageBits = getBitIntMemoryStorageBits(intTy, dataLayout); + if (storageBits == intTy.getWidth()) + return value; + return createIntCast(rewriter, value, + rewriter.getIntegerType(intTy.getWidth())); + } + return value; } @@ -155,6 +228,18 @@ static mlir::Value emitToMemory(mlir::ConversionPatternRewriter &rewriter, return createIntCast(rewriter, value, memType); } + // Sign/zero-extend the _BitInt value to its padded storage integer so the + // in-memory padding bits are well-defined (sign bits for signed, zero + // otherwise), matching classic CodeGen. + if (auto intTy = mlir::dyn_cast<cir::IntType>(origType); + intTy && intTy.isBitInt()) { + unsigned storageBits = getBitIntMemoryStorageBits(intTy, dataLayout); + if (storageBits == intTy.getWidth()) + return value; + return createIntCast(rewriter, value, rewriter.getIntegerType(storageBits), + intTy.isSigned()); + } + return value; } @@ -423,9 +508,14 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::BoolAttr boolAttr) { /// IntAttr visitor. mlir::Value CIRAttrToValue::visitCirAttr(cir::IntAttr intAttr) { mlir::Location loc = parentOp->getLoc(); - return mlir::LLVM::ConstantOp::create( + mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>()); + // Materialize the value at its literal width, then widen to the in-memory + // storage type (a no-op except for _BitInt) so aggregate members built here + // match the iM struct/array fields produced by convertTypeForMemory. + mlir::Value val = mlir::LLVM::ConstantOp::create( rewriter, loc, converter->convertType(intAttr.getType()), intAttr.getValue()); + return emitToMemory(rewriter, layout, intAttr.getType(), val); } /// FPAttr visitor. @@ -709,15 +799,19 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr typeInfoAttr) { /// UndefAttr visitor. mlir::Value CIRAttrToValue::visitCirAttr(cir::UndefAttr undefAttr) { mlir::Location loc = parentOp->getLoc(); + mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>()); return mlir::LLVM::UndefOp::create( - rewriter, loc, converter->convertType(undefAttr.getType())); + rewriter, loc, + convertTypeForMemory(*converter, layout, undefAttr.getType())); } /// PoisonAttr visitor. mlir::Value CIRAttrToValue::visitCirAttr(cir::PoisonAttr poisonAttr) { mlir::Location loc = parentOp->getLoc(); + mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>()); return mlir::LLVM::PoisonOp::create( - rewriter, loc, converter->convertType(poisonAttr.getType())); + rewriter, loc, + convertTypeForMemory(*converter, layout, poisonAttr.getType())); } // VTableAttr visitor. @@ -738,8 +832,9 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::VTableAttr vtableArr) { /// ZeroAttr visitor. mlir::Value CIRAttrToValue::visitCirAttr(cir::ZeroAttr attr) { mlir::Location loc = parentOp->getLoc(); - return mlir::LLVM::ZeroOp::create(rewriter, loc, - converter->convertType(attr.getType())); + mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>()); + return mlir::LLVM::ZeroOp::create( + rewriter, loc, convertTypeForMemory(*converter, layout, attr.getType())); } // This class handles rewriting initializer attributes for types that do not @@ -758,7 +853,17 @@ class GlobalInitAttrRewriter { } mlir::Attribute visitCirAttr(cir::IntAttr attr) { - return rewriter.getIntegerAttr(llvmType, attr.getValue()); + // A _BitInt(N) global stores its value in a padded integer iM; sign/zero- + // extend the APInt to that width (a no-op for plain integers, whose value + // width already matches llvmType) so the IntegerAttr is well-typed. + llvm::APInt val = attr.getValue(); + auto destTy = mlir::cast<mlir::IntegerType>(llvmType); + if (val.getBitWidth() != destTy.getWidth()) { + auto cirIntTy = mlir::cast<cir::IntType>(attr.getType()); + val = cirIntTy.isSigned() ? val.sext(destTy.getWidth()) + : val.zext(destTy.getWidth()); + } + return rewriter.getIntegerAttr(llvmType, val); } mlir::Attribute visitCirAttr(cir::FPAttr attr) { @@ -909,6 +1014,9 @@ getLLVMSyncScope(std::optional<cir::SyncScopeKind> syncScope) { mlir::LogicalResult CIRToLLVMAtomicCmpXchgOpLowering::matchAndRewrite( cir::AtomicCmpXchgOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { + if (isUnsupportedBitIntAtomic(op.getExpected().getType())) + return op.emitError() + << "NYI: atomic compare-exchange on a _BitInt with padded storage"; mlir::Value expected = adaptor.getExpected(); mlir::Value desired = adaptor.getDesired(); @@ -935,6 +1043,9 @@ mlir::LogicalResult CIRToLLVMAtomicCmpXchgOpLowering::matchAndRewrite( mlir::LogicalResult CIRToLLVMAtomicXchgOpLowering::matchAndRewrite( cir::AtomicXchgOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { + if (isUnsupportedBitIntAtomic(op.getVal().getType())) + return op.emitError() + << "NYI: atomic exchange on a _BitInt with padded storage"; assert(!cir::MissingFeatures::atomicSyncScopeID()); mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(adaptor.getMemOrder()); llvm::StringRef llvmSyncScope = getLLVMSyncScope(adaptor.getSyncScope()); @@ -1107,6 +1218,9 @@ mlir::Value CIRToLLVMAtomicFetchOpLowering::buildMinMaxPostOp( mlir::LogicalResult CIRToLLVMAtomicFetchOpLowering::matchAndRewrite( cir::AtomicFetchOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { + if (isUnsupportedBitIntAtomic(op.getVal().getType())) + return op.emitError() + << "NYI: atomic fetch on a _BitInt with padded storage"; bool isInt = false; bool isSignedInt = false; if (auto intTy = mlir::dyn_cast<cir::IntType>(op.getVal().getType())) { @@ -1710,6 +1824,9 @@ mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite( typeConverter->convertType(rewriter.getIndexType()), 1); mlir::Type elementTy = convertTypeForMemory(*getTypeConverter(), dataLayout, op.getAllocaType()); + if (!elementTy) + return op.emitError() + << "NYI: lowering alloca of a _BitInt with byte-array storage"; mlir::Type resultTy = convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType()); @@ -1916,10 +2033,13 @@ mlir::LogicalResult CIRToLLVMLoadOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { const mlir::Type llvmTy = convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType()); + if (!llvmTy) + return op.emitError() + << "NYI: lowering load of a _BitInt with byte-array storage"; mlir::LLVM::AtomicOrdering ordering = getLLVMMemOrder(op.getMemOrder()); std::optional<size_t> opAlign = op.getAlignment(); - unsigned alignment = - (unsigned)opAlign.value_or(dataLayout.getTypeABIAlignment(llvmTy)); + unsigned alignment = (unsigned)opAlign.value_or( + getMemoryFallbackAlignment(op.getType(), llvmTy, dataLayout)); assert(!cir::MissingFeatures::lowerModeOptLevel()); @@ -1946,6 +2066,9 @@ cir::direct::CIRToLLVMVecMaskedLoadOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { const mlir::Type llvmResTy = convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType()); + if (!llvmResTy) + return op.emitError() + << "NYI: lowering masked load of a _BitInt with byte-array storage"; std::optional<size_t> opAlign = op.getAlignment(); unsigned alignment = @@ -1965,11 +2088,15 @@ mlir::LogicalResult CIRToLLVMStoreOpLowering::matchAndRewrite( cir::StoreOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { mlir::LLVM::AtomicOrdering memorder = getLLVMMemOrder(op.getMemOrder()); - const mlir::Type llvmTy = - getTypeConverter()->convertType(op.getValue().getType()); + mlir::Type valueType = op.getValue().getType(); + if (auto intTy = mlir::dyn_cast<cir::IntType>(valueType); + intTy && isSplitStorageBitInt(intTy, dataLayout)) + return op.emitError() + << "NYI: lowering store of a _BitInt with byte-array storage"; + const mlir::Type llvmTy = getTypeConverter()->convertType(valueType); std::optional<size_t> opAlign = op.getAlignment(); - unsigned alignment = - (unsigned)opAlign.value_or(dataLayout.getTypeABIAlignment(llvmTy)); + unsigned alignment = (unsigned)opAlign.value_or( + getMemoryFallbackAlignment(valueType, llvmTy, dataLayout)); assert(!cir::MissingFeatures::lowerModeOptLevel()); @@ -2505,6 +2632,9 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite( // This is the LLVM dialect type. const mlir::Type llvmType = convertTypeForMemory(*getTypeConverter(), dataLayout, cirSymType); + if (!llvmType) + return op.emitError() + << "NYI: lowering global of a _BitInt with byte-array storage"; // FIXME: These default values are placeholders until the the equivalent // attributes are available on cir.global ops. @@ -3288,9 +3418,19 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, converter.addConversion([&](cir::ArrayType type) -> mlir::Type { mlir::Type ty = convertTypeForMemory(converter, dataLayout, type.getElementType()); + // A null element type means an unsupported member (e.g. a _BitInt with + // byte-array storage); propagate the conversion failure. + if (!ty) + return {}; return mlir::LLVM::LLVMArrayType::get(ty, type.getSize()); }); converter.addConversion([&](cir::VectorType type) -> mlir::Type { + // Vector-of-_BitInt memory layout is not modeled here (the element would + // stay at its literal width); report a conversion failure rather than emit + // an unvalidated vector. + if (auto intTy = mlir::dyn_cast<cir::IntType>(type.getElementType()); + intTy && intTy.isBitInt()) + return {}; const mlir::Type ty = converter.convertType(type.getElementType()); return mlir::VectorType::get(type.getSize(), ty, {type.getIsScalable()}); }); @@ -3342,8 +3482,15 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, }); converter.addConversion([&](cir::StructType type) -> mlir::Type { llvm::SmallVector<mlir::Type> llvmMembers; - for (mlir::Type ty : type.getMembers()) - llvmMembers.push_back(convertTypeForMemory(converter, dataLayout, ty)); + for (mlir::Type ty : type.getMembers()) { + mlir::Type memberTy = convertTypeForMemory(converter, dataLayout, ty); + // A null member means an unsupported type (e.g. a _BitInt with byte-array + // storage); propagate the conversion failure instead of building an + // invalid struct body. + if (!memberTy) + return {}; + llvmMembers.push_back(memberTy); + } mlir::LLVM::LLVMStructType llvmStruct; if (type.getName()) { @@ -3361,11 +3508,19 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, converter.addConversion([&](cir::UnionType type) -> mlir::Type { llvm::SmallVector<mlir::Type> llvmMembers; if (!type.getMembers().empty()) - if (auto storage = type.getUnionStorageType(dataLayout)) - llvmMembers.push_back( - convertTypeForMemory(converter, dataLayout, storage)); - if (mlir::Type pad = type.getPadding()) - llvmMembers.push_back(convertTypeForMemory(converter, dataLayout, pad)); + if (auto storage = type.getUnionStorageType(dataLayout)) { + mlir::Type storageTy = + convertTypeForMemory(converter, dataLayout, storage); + if (!storageTy) + return {}; + llvmMembers.push_back(storageTy); + } + if (mlir::Type pad = type.getPadding()) { + mlir::Type padTy = convertTypeForMemory(converter, dataLayout, pad); + if (!padTy) + return {}; + llvmMembers.push_back(padTy); + } mlir::LLVM::LLVMStructType llvmStruct; if (type.getName()) { diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp b/clang/lib/CIR/Lowering/LoweringHelpers.cpp index dfd8886cb8f1c..4b5b4bf9a1173 100644 --- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp +++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp @@ -236,9 +236,15 @@ lowerConstArrayAttr(cir::ConstArrayAttr constArr, if (mlir::isa<mlir::StringAttr>(constArr.getElts())) return convertStringAttrToDenseElementsAttr(constArr, converter->convertType(type)); - if (mlir::isa<cir::IntType>(type)) + if (mlir::isa<cir::IntType>(type)) { + // A _BitInt array element is stored in a padded integer in memory; the + // dense-attribute path here cannot express that widening, so fall back to + // the insertvalue region, which widens each element via emitToMemory. + if (mlir::cast<cir::IntType>(type).isBitInt()) + return std::nullopt; return convertToDenseElementsAttr<cir::IntAttr, mlir::APInt>( constArr, dims, type, converter->convertType(type)); + } if (mlir::isa<cir::BoolType>(type)) return convertToDenseElementsAttr<cir::IntAttr, mlir::APInt>( @@ -297,9 +303,14 @@ lowerConstRecordMemberAttr(mlir::Attribute attr, if (mlir::isa<cir::UndefAttr>(attr)) return mlir::LLVM::UndefAttr::get(ctx); - if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(attr)) + if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(attr)) { + // A _BitInt member is stored in a padded integer in memory; defer to the + // insertvalue region (CIRAttrToValue), which performs the extension. + if (mlir::cast<cir::IntType>(intAttr.getType()).isBitInt()) + return std::nullopt; return mlir::IntegerAttr::get(converter->convertType(intAttr.getType()), intAttr.getValue()); + } if (auto boolAttr = mlir::dyn_cast<cir::BoolAttr>(attr)) return mlir::IntegerAttr::get(converter->convertType(boolAttr.getType()), diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp index 835166da8c7c6..9cba7c2b01162 100644 --- a/clang/test/CIR/CodeGen/array.cpp +++ b/clang/test/CIR/CodeGen/array.cpp @@ -534,11 +534,12 @@ void bitint_index_access(_BitInt(7) i) { // CIR: cir.store{{.*}} %[[VAL]], %[[N_ADDR]] : !s32i, !cir.ptr<!s32i> // LLVM: define{{.*}} @_Z19bitint_index_accessDB7_(i7 {{[^)]*}}) -// LLVM: %[[I_ADDR:.*]] = alloca i7 +// LLVM: %[[I_ADDR:.*]] = alloca i8 // LLVM: %[[ARR_ADDR:.*]] = alloca [10 x i32] // LLVM: %[[N_ADDR:.*]] = alloca i32 -// LLVM: %[[I:.*]] = load i7, ptr %[[I_ADDR]] -// LLVM: %[[IDX:.*]] = sext i7 %[[I]] to i64 +// LLVM: %[[I:.*]] = load i8, ptr %[[I_ADDR]] +// LLVM: %[[I_CAST:.*]] = trunc i8 %[[I]] to i7 +// LLVM: %[[IDX:.*]] = sext i7 %[[I_CAST]] to i64 // LLVM: %[[ELE:.*]] = getelementptr [10 x i32], ptr %[[ARR_ADDR]], i32 0, i64 %[[IDX]] // LLVM: %[[VAL:.*]] = load i32, ptr %[[ELE]] // LLVM: store i32 %[[VAL]], ptr %[[... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/206606 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
