Skip to content

[clang] Emit nuw GEPs for array subscript expressions #103088

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions clang/lib/CodeGen/CGBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "CodeGenTypeCache.h"
#include "llvm/Analysis/Utils/Local.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GEPNoWrapFlags.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Type.h"

Expand Down Expand Up @@ -334,9 +335,10 @@ class CGBuilderTy : public CGBuilderBaseTy {

Address CreateGEP(Address Addr, ArrayRef<llvm::Value *> IdxList,
llvm::Type *ElementType, CharUnits Align,
const Twine &Name = "") {
const Twine &Name = "",
llvm::GEPNoWrapFlags NW = llvm::GEPNoWrapFlags::none()) {
llvm::Value *Ptr = emitRawPointerFromAddress(Addr);
return RawAddress(CreateGEP(Addr.getElementType(), Ptr, IdxList, Name),
return RawAddress(CreateGEP(Addr.getElementType(), Ptr, IdxList, Name, NW),
ElementType, Align);
}

Expand Down
41 changes: 27 additions & 14 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3959,13 +3959,13 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF,
static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
ArrayRef<llvm::Value *> indices,
llvm::Type *elementType, bool inbounds,
bool signedIndices, SourceLocation loc,
CharUnits align,
bool nuw, bool signedIndices,
SourceLocation loc, CharUnits align,
const llvm::Twine &name = "arrayidx") {
if (inbounds) {
return CGF.EmitCheckedInBoundsGEP(addr, indices, elementType, signedIndices,
CodeGenFunction::NotSubtraction, loc,
align, name);
align, name, nuw);
} else {
return CGF.Builder.CreateGEP(addr, indices, elementType, align, name);
}
Expand Down Expand Up @@ -4060,7 +4060,7 @@ static bool IsPreserveAIArrayBase(CodeGenFunction &CGF, const Expr *ArrayBase) {

static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
ArrayRef<llvm::Value *> indices,
QualType eltType, bool inbounds,
QualType eltType, bool inbounds, bool nuw,
bool signedIndices, SourceLocation loc,
QualType *arrayType = nullptr,
const Expr *Base = nullptr,
Expand Down Expand Up @@ -4091,7 +4091,7 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
if (!LastIndex ||
(!CGF.IsInPreservedAIRegion && !IsPreserveAIArrayBase(CGF, Base))) {
addr = emitArraySubscriptGEP(CGF, addr, indices,
CGF.ConvertTypeForMem(eltType), inbounds,
CGF.ConvertTypeForMem(eltType), inbounds, nuw,
signedIndices, loc, eltAlign, name);
return addr;
} else {
Expand Down Expand Up @@ -4214,7 +4214,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,

QualType EltType = LV.getType()->castAs<VectorType>()->getElementType();
Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true,
SignedIndices, E->getExprLoc());
/*nuw=*/false, SignedIndices, E->getExprLoc());
return MakeAddrLValue(Addr, EltType, LV.getBaseInfo(),
CGM.getTBAAInfoForSubobject(LV, EltType));
}
Expand Down Expand Up @@ -4245,7 +4245,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,

Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(),
!getLangOpts().isSignedOverflowDefined(),
SignedIndices, E->getExprLoc());
/*nuw=*/false, SignedIndices, E->getExprLoc());

} else if (const ObjCObjectType *OIT = E->getType()->getAs<ObjCObjectType>()){
// Indexing over an interface, as in "NSString *P; P[4];"
Expand Down Expand Up @@ -4332,10 +4332,20 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,

// Propagate the alignment from the array itself to the result.
QualType arrayType = Array->getType();
Addr = emitArraySubscriptGEP(
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
E->getExprLoc(), &arrayType, E->getBase());

bool Inbounds = !getLangOpts().isSignedOverflowDefined();
// (ISO/IEC 9899:TC3, 6.5.6.8) / (C++ expr.add 4.2)
// If A in A[i] is the base of a constant size array, then the addition of
// the index to the base pointer cannot wrap in an unsigned sense without
// violating the inbounds constraint.
bool NUW = !SignedIndices && Inbounds &&
(getLangOpts().C99 || getLangOpts().CPlusPlus) &&
getContext().getAsConstantArrayType(arrayType);

Addr = emitArraySubscriptGEP(*this, ArrayLV.getAddress(),
{CGM.getSize(CharUnits::Zero()), Idx},
E->getType(), Inbounds, NUW, SignedIndices,
E->getExprLoc(), &arrayType, E->getBase());
EltBaseInfo = ArrayLV.getBaseInfo();
EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
} else {
Expand All @@ -4345,8 +4355,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
QualType ptrType = E->getBase()->getType();
Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
!getLangOpts().isSignedOverflowDefined(),
SignedIndices, E->getExprLoc(), &ptrType,
E->getBase());
/*nuw=*/false, SignedIndices, E->getExprLoc(),
&ptrType, E->getBase());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the handling for arrays and pointers here different? Aren't they essentially semantically equivalent?

}

LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
Expand Down Expand Up @@ -4543,6 +4553,7 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
Idx = Builder.CreateNSWMul(Idx, NumElements);
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, VLA->getElementType(),
!getLangOpts().isSignedOverflowDefined(),
/*nuw=*/false,
/*signedIndices=*/false, E->getExprLoc());
} else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) {
// If this is A[i] where A is an array, the frontend will have decayed the
Expand All @@ -4563,6 +4574,7 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
EltPtr = emitArraySubscriptGEP(
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
ResultExprTy, !getLangOpts().isSignedOverflowDefined(),
/*nuw=*/false,
/*signedIndices=*/false, E->getExprLoc());
BaseInfo = ArrayLV.getBaseInfo();
TBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, ResultExprTy);
Expand All @@ -4572,7 +4584,8 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
ResultExprTy, IsLowerBound);
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy,
!getLangOpts().isSignedOverflowDefined(),
/*signedIndices=*/false, E->getExprLoc());
/*signedIndices=*/false, /*nuw=*/false,
E->getExprLoc());
}

return MakeAddrLValue(EltPtr, ResultExprTy, BaseInfo, TBAAInfo);
Expand Down
38 changes: 24 additions & 14 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/FixedPointBuilder.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GEPNoWrapFlags.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Intrinsics.h"
Expand Down Expand Up @@ -5713,13 +5714,18 @@ static GEPOffsetAndOverflow EmitGEPOffsetInBytes(Value *BasePtr, Value *GEPVal,
return {TotalOffset, OffsetOverflows};
}

Value *
CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr,
ArrayRef<Value *> IdxList,
bool SignedIndices, bool IsSubtraction,
SourceLocation Loc, const Twine &Name) {
Value *CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr,
ArrayRef<Value *> IdxList,
bool SignedIndices,
bool IsSubtraction,
SourceLocation Loc,
const Twine &Name, bool NUW) {
llvm::Type *PtrTy = Ptr->getType();
Value *GEPVal = Builder.CreateInBoundsGEP(ElemTy, Ptr, IdxList, Name);

llvm::GEPNoWrapFlags NWFlags = llvm::GEPNoWrapFlags::inBounds();
if (NUW)
NWFlags |= llvm::GEPNoWrapFlags::noUnsignedWrap();
Value *GEPVal = Builder.CreateGEP(ElemTy, Ptr, IdxList, Name, NWFlags);

// If the pointer overflow sanitizer isn't enabled, do nothing.
if (!SanOpts.has(SanitizerKind::PointerOverflow))
Expand Down Expand Up @@ -5833,12 +5839,16 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr,
Address CodeGenFunction::EmitCheckedInBoundsGEP(
Address Addr, ArrayRef<Value *> IdxList, llvm::Type *elementType,
bool SignedIndices, bool IsSubtraction, SourceLocation Loc, CharUnits Align,
const Twine &Name) {
if (!SanOpts.has(SanitizerKind::PointerOverflow))
return Builder.CreateInBoundsGEP(Addr, IdxList, elementType, Align, Name);

return RawAddress(
EmitCheckedInBoundsGEP(Addr.getElementType(), Addr.emitRawPointer(*this),
IdxList, SignedIndices, IsSubtraction, Loc, Name),
elementType, Align);
const Twine &Name, bool NUW) {
if (!SanOpts.has(SanitizerKind::PointerOverflow)) {
llvm::GEPNoWrapFlags NWFlags = llvm::GEPNoWrapFlags::inBounds();
if (NUW)
NWFlags |= llvm::GEPNoWrapFlags::noUnsignedWrap();
return Builder.CreateGEP(Addr, IdxList, elementType, Align, Name, NWFlags);
}

return RawAddress(EmitCheckedInBoundsGEP(
Addr.getElementType(), Addr.emitRawPointer(*this),
IdxList, SignedIndices, IsSubtraction, Loc, Name, NUW),
elementType, Align);
}
9 changes: 5 additions & 4 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -5057,17 +5057,18 @@ class CodeGenFunction : public CodeGenTypeCache {
/// \p SignedIndices indicates whether any of the GEP indices are signed.
/// \p IsSubtraction indicates whether the expression used to form the GEP
/// is a subtraction.
/// \p NUW indicates whether the GEP is nuw.
llvm::Value *EmitCheckedInBoundsGEP(llvm::Type *ElemTy, llvm::Value *Ptr,
ArrayRef<llvm::Value *> IdxList,
bool SignedIndices,
bool IsSubtraction,
bool SignedIndices, bool IsSubtraction,
SourceLocation Loc,
const Twine &Name = "");
const Twine &Name = "", bool NUW = false);

Address EmitCheckedInBoundsGEP(Address Addr, ArrayRef<llvm::Value *> IdxList,
llvm::Type *elementType, bool SignedIndices,
bool IsSubtraction, SourceLocation Loc,
CharUnits Align, const Twine &Name = "");
CharUnits Align, const Twine &Name = "",
bool NUW = false);

/// Specifies which type of sanitizer check to apply when handling a
/// particular builtin.
Expand Down
12 changes: 6 additions & 6 deletions clang/test/CodeGen/PowerPC/ppc-emmintrin.c
Original file line number Diff line number Diff line change
Expand Up @@ -1012,14 +1012,14 @@ test_shuffle() {
// CHECK: %[[SHR:[0-9a-zA-Z_.]+]] = ashr i32 %{{[0-9a-zA-Z_.]+}}, 6
// CHECK: %[[AND4:[0-9a-zA-Z_.]+]] = and i32 %[[SHR]], 3
// CHECK: sext i32 %[[AND4]] to i64
// CHECK: getelementptr inbounds [4 x i32], ptr @_mm_shuffle_epi32.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: getelementptr inbounds nuw [4 x i32], ptr @_mm_shuffle_epi32.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: insertelement <4 x i32> %{{[0-9a-zA-Z_.]+}}, i32 %{{[0-9a-zA-Z_.]+}}, i32 0
// CHECK: getelementptr inbounds [4 x i32], ptr @_mm_shuffle_epi32.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: getelementptr inbounds nuw [4 x i32], ptr @_mm_shuffle_epi32.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: insertelement <4 x i32> %{{[0-9a-zA-Z_.]+}}, i32 %{{[0-9a-zA-Z_.]+}}, i32 1
// CHECK: getelementptr inbounds [4 x i32], ptr @_mm_shuffle_epi32.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: getelementptr inbounds nuw [4 x i32], ptr @_mm_shuffle_epi32.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: %[[ADD:[0-9a-zA-Z_.]+]] = add i32 %{{[0-9a-zA-Z_.]+}}, 269488144
// CHECK: insertelement <4 x i32> %{{[0-9a-zA-Z_.]+}}, i32 %[[ADD]], i32 2
// CHECK: getelementptr inbounds [4 x i32], ptr @_mm_shuffle_epi32.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: getelementptr inbounds nuw [4 x i32], ptr @_mm_shuffle_epi32.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: add i32 %{{[0-9a-zA-Z_.]+}}, 269488144
// CHECK: call <4 x i32> @vec_perm(int vector[4], int vector[4], unsigned char vector[16])

Expand Down Expand Up @@ -1050,7 +1050,7 @@ test_shuffle() {
// CHECK: sext i32 %[[AND4]] to i64
// CHECK-LE: store <2 x i64> <i64 1663540288323457296, i64 0>, ptr %{{[0-9a-zA-Z_.]+}}, align 16
// CHECK-BE: store <2 x i64> <i64 1157726452361532951, i64 0>, ptr %{{[0-9a-zA-Z_.]+}}, align 16
// CHECK-COUNT-4: getelementptr inbounds [4 x i16], ptr @_mm_shufflehi_epi16.__permute_selectors, i64 0, i64 {{[0-9a-zA-Z_%.]+}}
// CHECK-COUNT-4: getelementptr inbounds nuw [4 x i16], ptr @_mm_shufflehi_epi16.__permute_selectors, i64 0, i64 {{[0-9a-zA-Z_%.]+}}
// CHECK: call <2 x i64> @vec_perm(unsigned long long vector[2], unsigned long long vector[2], unsigned char vector[16])

// CHECK-LABEL: define available_externally <2 x i64> @_mm_shufflelo_epi16
Expand All @@ -1067,7 +1067,7 @@ test_shuffle() {
// CHECK: sext i32 %[[AND4]] to i64
// CHECK-LE: store <2 x i64> <i64 0, i64 2242261671028070680>, ptr %{{[0-9a-zA-Z_.]+}}, align 16
// CHECK-BE: store <2 x i64> <i64 0, i64 1736447835066146335>, ptr %{{[0-9a-zA-Z_.]+}}, align 16
// CHECK-COUNT-4: getelementptr inbounds [4 x i16], ptr @_mm_shufflelo_epi16.__permute_selectors, i64 0, i64 {{[0-9a-zA-Z_%.]+}}
// CHECK-COUNT-4: getelementptr inbounds nuw [4 x i16], ptr @_mm_shufflelo_epi16.__permute_selectors, i64 0, i64 {{[0-9a-zA-Z_%.]+}}
// CHECK: call <2 x i64> @vec_perm(unsigned long long vector[2], unsigned long long vector[2], unsigned char vector[16])

void __attribute__((noinline))
Expand Down
16 changes: 8 additions & 8 deletions clang/test/CodeGen/PowerPC/ppc-xmmintrin.c
Original file line number Diff line number Diff line change
Expand Up @@ -894,16 +894,16 @@ test_shuffle() {
// CHECK: %[[SHR3:[0-9a-zA-Z_.]+]] = ashr i32 %{{[0-9a-zA-Z_.]+}}, 6
// CHECK: %[[AND4:[0-9a-zA-Z_.]+]] = and i32 %[[SHR3]], 3
// CHECK: sext i32 %[[AND4]] to i64
// CHECK: getelementptr inbounds [4 x i16], ptr @_mm_shuffle_pi16.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: getelementptr inbounds nuw [4 x i16], ptr @_mm_shuffle_pi16.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK-LE: getelementptr inbounds [4 x i16], ptr %{{[0-9a-zA-Z_.]+}}, i64 0, i64 0
// CHECK-BE: getelementptr inbounds [4 x i16], ptr %{{[0-9a-zA-Z_.]+}}, i64 0, i64 3
// CHECK: getelementptr inbounds [4 x i16], ptr @_mm_shuffle_pi16.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: getelementptr inbounds nuw [4 x i16], ptr @_mm_shuffle_pi16.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK-LE: getelementptr inbounds [4 x i16], ptr %{{[0-9a-zA-Z_.]+}}, i64 0, i64 1
// CHECK-BE: getelementptr inbounds [4 x i16], ptr %{{[0-9a-zA-Z_.]+}}, i64 0, i64 2
// CHECK: getelementptr inbounds [4 x i16], ptr @_mm_shuffle_pi16.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: getelementptr inbounds nuw [4 x i16], ptr @_mm_shuffle_pi16.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK-LE: getelementptr inbounds [4 x i16], ptr %{{[0-9a-zA-Z_.]+}}, i64 0, i64 2
// CHECK-BE: getelementptr inbounds [4 x i16], ptr %{{[0-9a-zA-Z_.]+}}, i64 0, i64 1
// CHECK: getelementptr inbounds [4 x i16], ptr @_mm_shuffle_pi16.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK: getelementptr inbounds nuw [4 x i16], ptr @_mm_shuffle_pi16.__permute_selectors, i64 0, i64 %{{[0-9a-zA-Z_.]+}}
// CHECK-LE: getelementptr inbounds [4 x i16], ptr %{{[0-9a-zA-Z_.]+}}, i64 0, i64 3
// CHECK-BE: getelementptr inbounds [4 x i16], ptr %{{[0-9a-zA-Z_.]+}}, i64 0, i64 0
// CHECK: call <2 x i64> @vec_splats(unsigned long long)
Expand All @@ -923,14 +923,14 @@ test_shuffle() {
// CHECK: %[[SHR3:[0-9a-zA-Z_.]+]] = ashr i32 %{{[0-9a-zA-Z_.]+}}, 6
// CHECK: %[[AND4:[0-9a-zA-Z_.]+]] = and i32 %[[SHR3]], 3
// CHECK: sext i32 %[[AND4]] to i64
// CHECK: getelementptr inbounds [4 x i32], ptr @_mm_shuffle_ps.__permute_selectors, i64 0, i64
// CHECK: getelementptr inbounds nuw [4 x i32], ptr @_mm_shuffle_ps.__permute_selectors, i64 0, i64
// CHECK: insertelement <4 x i32> %{{[0-9a-zA-Z_.]+}}, i32 %{{[0-9a-zA-Z_.]+}}, i32 0
// CHECK: getelementptr inbounds [4 x i32], ptr @_mm_shuffle_ps.__permute_selectors, i64 0, i64
// CHECK: getelementptr inbounds nuw [4 x i32], ptr @_mm_shuffle_ps.__permute_selectors, i64 0, i64
// CHECK: insertelement <4 x i32> %{{[0-9a-zA-Z_.]+}}, i32 %{{[0-9a-zA-Z_.]+}}, i32 1
// CHECK: getelementptr inbounds [4 x i32], ptr @_mm_shuffle_ps.__permute_selectors, i64 0, i64
// CHECK: getelementptr inbounds nuw [4 x i32], ptr @_mm_shuffle_ps.__permute_selectors, i64 0, i64
// CHECK: %[[ADD:[0-9a-zA-Z_.]+]] = add i32 %{{[0-9a-zA-Z_.]+}}, 269488144
// CHECK: insertelement <4 x i32> %{{[0-9a-zA-Z_.]+}}, i32 %[[ADD]], i32 2
// CHECK: getelementptr inbounds [4 x i32], ptr @_mm_shuffle_ps.__permute_selectors, i64 0, i64
// CHECK: getelementptr inbounds nuw [4 x i32], ptr @_mm_shuffle_ps.__permute_selectors, i64 0, i64
// CHECK: %[[ADD2:[0-9a-zA-Z_.]+]] = add i32 %{{[0-9a-zA-Z_.]+}}, 269488144
// CHECK: insertelement <4 x i32> %{{[0-9a-zA-Z_.]+}}, i32 %[[ADD2]], i32 3
// CHECK: call <4 x float> @vec_perm(float vector[4], float vector[4], unsigned char vector[16])
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGenCXX/pr45964-decomp-transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void (*d)(){test_transform<0>};
// CHECK-NEXT: [[BODY]]:
// CHECK-NEXT: [[CUR:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[NEXT:%.*]], %[[BODY]] ]
// CHECK-NEXT: [[DEST:%.*]] = getelementptr inbounds i32, ptr [[BEGIN]], i64 [[CUR]]
// CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds [1 x i32], ptr @a, i64 0, i64 [[CUR]]
// CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds nuw [1 x i32], ptr @a, i64 0, i64 [[CUR]]
// CHECK-NEXT: [[X:%.*]] = load i32, ptr [[SRC]]
// CHECK-NEXT: store i32 [[X]], ptr [[DEST]]
// CHECK-NEXT: [[NEXT]] = add nuw i64 [[CUR]], 1
Expand Down
Loading