From 9e67b9922bb19279efadec86e6b9203c21ba90ee Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 26 Sep 2016 23:49:47 +0000 Subject: [PATCH] P0145R3 (C++17 evaluation order tweaks): consistently emit the LHS of array subscripting before the RHS, regardless of which is the base and which is the index. llvm-svn: 282453 --- clang/lib/CodeGen/CGExpr.cpp | 50 +++-- clang/test/CodeGen/captured-statements-nested.c | 4 +- clang/test/CodeGenCXX/catch-undef-behavior.cpp | 8 +- .../CodeGenCXX/cxx1y-initializer-aggregate.cpp | 2 +- clang/test/CodeGenCXX/cxx1z-eval-order.cpp | 214 +++++++++++++++++++++ clang/test/CodeGenCXX/pragma-loop-safety.cpp | 24 +-- clang/test/CodeGenCXX/vla-lambda-capturing.cpp | 4 +- 7 files changed, 270 insertions(+), 36 deletions(-) create mode 100644 clang/test/CodeGenCXX/cxx1z-eval-order.cpp diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 7fee798..c6011cb 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2875,13 +2875,30 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, bool Accessed) { - // The index must always be an integer, which is not an aggregate. Emit it. - llvm::Value *Idx = EmitScalarExpr(E->getIdx()); - QualType IdxTy = E->getIdx()->getType(); - bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType(); + // The index must always be an integer, which is not an aggregate. Emit it + // in lexical order (this complexity is, sadly, required by C++17). + llvm::Value *IdxPre = + (E->getLHS() == E->getIdx()) ? EmitScalarExpr(E->getIdx()) : nullptr; + auto EmitIdxAfterBase = [&, IdxPre](bool Promote = true) -> llvm::Value * { + auto *Idx = IdxPre; + if (E->getLHS() != E->getIdx()) { + assert(E->getRHS() == E->getIdx() && "index was neither LHS nor RHS"); + Idx = EmitScalarExpr(E->getIdx()); + } + + QualType IdxTy = E->getIdx()->getType(); + bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType(); - if (SanOpts.has(SanitizerKind::ArrayBounds)) - EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed); + if (SanOpts.has(SanitizerKind::ArrayBounds)) + EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed); + + // Extend or truncate the index type to 32 or 64-bits. + if (Promote && Idx->getType() != IntPtrTy) + Idx = Builder.CreateIntCast(Idx, IntPtrTy, IdxSigned, "idxprom"); + + return Idx; + }; + IdxPre = nullptr; // If the base is a vector type, then we are forming a vector element lvalue // with this subscript. @@ -2889,6 +2906,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, !isa(E->getBase())) { // Emit the vector as an lvalue to get its address. LValue LHS = EmitLValue(E->getBase()); + auto *Idx = EmitIdxAfterBase(/*Promote*/false); assert(LHS.isSimple() && "Can only subscript lvalue vectors here!"); return LValue::MakeVectorElt(LHS.getAddress(), Idx, E->getBase()->getType(), @@ -2897,13 +2915,10 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, // All the other cases basically behave like simple offsetting. - // Extend or truncate the index type to 32 or 64-bits. - if (Idx->getType() != IntPtrTy) - Idx = Builder.CreateIntCast(Idx, IntPtrTy, IdxSigned, "idxprom"); - // Handle the extvector case we ignored above. if (isa(E->getBase())) { LValue LV = EmitLValue(E->getBase()); + auto *Idx = EmitIdxAfterBase(/*Promote*/true); Address Addr = EmitExtVectorElementLValue(LV); QualType EltType = LV.getType()->castAs()->getElementType(); @@ -2919,6 +2934,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, // it. It needs to be emitted first in case it's what captures // the VLA bounds. Addr = EmitPointerWithAlignment(E->getBase(), &AlignSource); + auto *Idx = EmitIdxAfterBase(/*Promote*/true); // The element count here is the total number of non-VLA elements. llvm::Value *numElements = getVLASize(vla).first; @@ -2938,14 +2954,16 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, } else if (const ObjCObjectType *OIT = E->getType()->getAs()){ // Indexing over an interface, as in "NSString *P; P[4];" - CharUnits InterfaceSize = getContext().getTypeSizeInChars(OIT); - llvm::Value *InterfaceSizeVal = - llvm::ConstantInt::get(Idx->getType(), InterfaceSize.getQuantity());; - - llvm::Value *ScaledIdx = Builder.CreateMul(Idx, InterfaceSizeVal); // Emit the base pointer. Addr = EmitPointerWithAlignment(E->getBase(), &AlignSource); + auto *Idx = EmitIdxAfterBase(/*Promote*/true); + + CharUnits InterfaceSize = getContext().getTypeSizeInChars(OIT); + llvm::Value *InterfaceSizeVal = + llvm::ConstantInt::get(Idx->getType(), InterfaceSize.getQuantity()); + + llvm::Value *ScaledIdx = Builder.CreateMul(Idx, InterfaceSizeVal); // We don't necessarily build correct LLVM struct types for ObjC // interfaces, so we can't rely on GEP to do this scaling @@ -2977,6 +2995,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, ArrayLV = EmitArraySubscriptExpr(ASE, /*Accessed*/ true); else ArrayLV = EmitLValue(Array); + auto *Idx = EmitIdxAfterBase(/*Promote*/true); // Propagate the alignment from the array itself to the result. Addr = emitArraySubscriptGEP(*this, ArrayLV.getAddress(), @@ -2987,6 +3006,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, } else { // The base must be a pointer; emit it with an estimate of its alignment. Addr = EmitPointerWithAlignment(E->getBase(), &AlignSource); + auto *Idx = EmitIdxAfterBase(/*Promote*/true); Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(), !getLangOpts().isSignedOverflowDefined()); } diff --git a/clang/test/CodeGen/captured-statements-nested.c b/clang/test/CodeGen/captured-statements-nested.c index b81705b..c078f72 100644 --- a/clang/test/CodeGen/captured-statements-nested.c +++ b/clang/test/CodeGen/captured-statements-nested.c @@ -69,7 +69,7 @@ void test_nest_captured_stmt(int param, int size, int param_arr[size]) { // CHECK1-NEXT: getelementptr inbounds %struct.A, %struct.A* // CHECK1-NEXT: store i8 99 // - // CHECK1: [[SIZE_ADDR_REF:%.*]] = getelementptr inbounds [[T]], [[T]]* {{.*}}, i{{.+}} 0, i{{.+}} 7 + // CHECK1-DAG: [[SIZE_ADDR_REF:%.*]] = getelementptr inbounds [[T]], [[T]]* {{.*}}, i{{.+}} 0, i{{.+}} 7 // CHECK1-DAG: [[SIZE_ADDR:%.*]] = load i{{.+}}*, i{{.+}}** [[SIZE_ADDR_REF]] // CHECK1-DAG: [[SIZE:%.*]] = load i{{.+}}, i{{.+}}* [[SIZE_ADDR]] // CHECK1-DAG: [[PARAM_ARR_IDX:%.*]] = sub nsw i{{.+}} [[SIZE]], 1 @@ -79,7 +79,7 @@ void test_nest_captured_stmt(int param, int size, int param_arr[size]) { // CHECK1-DAG: [[PARAM_ARR_SIZE_MINUS_1_ADDR:%.*]] = getelementptr inbounds i{{.+}}, i{{.+}}* [[PARAM_ARR]], i{{.*}} // CHECK1: store i{{.+}} 2, i{{.+}}* [[PARAM_ARR_SIZE_MINUS_1_ADDR]] // - // CHECK1: [[Z_ADDR_REF:%.*]] = getelementptr inbounds [[T]], [[T]]* {{.*}}, i{{.+}} 0, i{{.+}} 2 + // CHECK1-DAG: [[Z_ADDR_REF:%.*]] = getelementptr inbounds [[T]], [[T]]* {{.*}}, i{{.+}} 0, i{{.+}} 2 // CHECK1-DAG: [[Z_ADDR:%.*]] = load %struct.A*, %struct.A** [[Z_ADDR_REF]] // CHECK1-DAG: [[Z_A_ADDR:%.*]] = getelementptr inbounds %struct.A, %struct.A* [[Z_ADDR]], i{{.+}} 0, i{{.+}} 0 // CHECK1-DAG: [[ARR_IDX_2:%.*]] = load i{{.+}}, i{{.+}}* [[Z_A_ADDR]] diff --git a/clang/test/CodeGenCXX/catch-undef-behavior.cpp b/clang/test/CodeGenCXX/catch-undef-behavior.cpp index 3ca7f6d..179c334 100644 --- a/clang/test/CodeGenCXX/catch-undef-behavior.cpp +++ b/clang/test/CodeGenCXX/catch-undef-behavior.cpp @@ -277,13 +277,13 @@ int array_index(const int (&a)[4], int n) { int multi_array_index(int n, int m) { int arr[4][6]; - // CHECK: %[[IDX2_OK:.*]] = icmp ult i64 %{{.*}}, 6 - // CHECK: br i1 %[[IDX2_OK]] - // CHECK: call void @__ubsan_handle_out_of_bounds( - // CHECK: %[[IDX1_OK:.*]] = icmp ult i64 %{{.*}}, 4 // CHECK: br i1 %[[IDX1_OK]] // CHECK: call void @__ubsan_handle_out_of_bounds( + + // CHECK: %[[IDX2_OK:.*]] = icmp ult i64 %{{.*}}, 6 + // CHECK: br i1 %[[IDX2_OK]] + // CHECK: call void @__ubsan_handle_out_of_bounds( return arr[n][m]; } diff --git a/clang/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp b/clang/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp index 50629b5..6d0ae8a 100644 --- a/clang/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp +++ b/clang/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp @@ -51,8 +51,8 @@ C n{}; // CHECK: store i32 0, i32* getelementptr inbounds ({{.*}} @a, i32 0, i32 0) // CHECK: store i8* {{.*}} @[[STR_A]]{{.*}}, i8** getelementptr inbounds ({{.*}} @a, i32 0, i32 1) -// CHECK: load i32, i32* getelementptr inbounds ({{.*}} @a, i32 0, i32 0) // CHECK: load i8*, i8** getelementptr inbounds ({{.*}} @a, i32 0, i32 1) +// CHECK: load i32, i32* getelementptr inbounds ({{.*}} @a, i32 0, i32 0) // CHECK: getelementptr inbounds i8, i8* %{{.*}}, {{.*}} %{{.*}} // CHECK: store i8 %{{.*}}, i8* getelementptr inbounds ({{.*}} @a, i32 0, i32 2) // CHECK: call i32 @_ZN1A1fEv({{.*}} @a) diff --git a/clang/test/CodeGenCXX/cxx1z-eval-order.cpp b/clang/test/CodeGenCXX/cxx1z-eval-order.cpp new file mode 100644 index 0000000..3531891 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx1z-eval-order.cpp @@ -0,0 +1,214 @@ +// RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - -triple %itanium_abi_triple | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ITANIUM +// RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - -triple %ms_abi_triple | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-WINDOWS + +struct B; +struct A { + A(); + A(const A&); + + void operator[](B b); + + int a_member_f(B); +}; +struct B { + B(); + ~B(); +}; + +struct C { + operator int *(); + A *operator->(); + void operator->*(B); + + friend void operator<<(C, B); + friend void operator>>(C, B); + void operator<<(A); + void operator>>(A); + + void operator=(B); + void operator+=(B); +}; + +A make_a(); +A *make_a_ptr(); +int A::*make_mem_ptr_a(); +void (A::*make_mem_fn_ptr_a())(); +B make_b(); +C make_c(); +void side_effect(); + +void callee(A); +void (*get_f())(A); + + +// CHECK-LABEL: define {{.*}}@{{.*}}postfix_before_args{{.*}}( +void postfix_before_args() { + // CHECK: call {{.*}}@{{.*}}get_f{{.*}}( + // CHECK-ITANIUM: call {{.*}}@_ZN1AC1Ev( + // CHECK-WINDOWS: call {{.*}}@"\01??0A@@QEAA@XZ"( + // CHECK: call {{.*}}%{{.*}}( + get_f()(A{}); + + // CHECK: call {{.*}}@{{.*}}side_effect{{.*}}( + // CHECK-ITANIUM: call {{.*}}@_ZN1AC1Ev( + // CHECK-WINDOWS: call {{.*}}@"\01??0A@@QEAA@XZ"( + // CHECK: call {{.*}}@{{.*}}callee{{.*}}( + (side_effect(), callee)(A{}); +// CHECK: } +} + + +// CHECK-LABEL: define {{.*}}@{{.*}}dot_lhs_before_rhs{{.*}}( +void dot_lhs_before_rhs() { + // CHECK: call {{.*}}@{{.*}}make_a{{.*}}( + // CHECK: call {{.*}}@{{.*}}make_b{{.*}}( + // CHECK: call {{.*}}@{{.*}}a_member_f{{.*}}( + make_a().a_member_f(make_b()); + + // CHECK: call {{.*}}@{{.*}}make_a_ptr{{.*}}( + // CHECK: call {{.*}}@{{.*}}make_b{{.*}}( + // CHECK: call {{.*}}@{{.*}}a_member_f{{.*}}( + make_a_ptr()->a_member_f(make_b()); + + // CHECK: call {{.*}}@{{.*}}make_c{{.*}}( + // CHECK: call {{.*}}@{{.*}}make_b{{.*}}( + // CHECK: call {{.*}}@{{.*}}a_member_f{{.*}}( + make_c()->a_member_f(make_b()); +// CHECK: } +} + + +// CHECK-LABEL: define {{.*}}@{{.*}}array_lhs_before_rhs{{.*}}( +void array_lhs_before_rhs() { + int (&get_arr())[10]; + extern int get_index(); + + // CHECK: call {{.*}}@{{.*}}get_arr{{.*}}( + // CHECK: call {{.*}}@{{.*}}get_index{{.*}}( + get_arr()[get_index()] = 0; + + // CHECK: call {{.*}}@{{.*}}get_index{{.*}}( + // CHECK: call {{.*}}@{{.*}}get_arr{{.*}}( + get_index()[get_arr()] = 0; + + // CHECK: call {{.*}}@{{.*}}make_a{{.*}}( + // CHECK: call {{.*}}@{{.*}}make_b{{.*}}( + // CHECK: call + make_a()[make_b()]; + + // CHECK: call {{.*}}@{{.*}}make_c{{.*}}( + // CHECK: call {{.*}}@{{.*}}get_index{{.*}}( + // CHECK: call + make_c()[get_index()] = 0; + + // CHECK: call {{.*}}@{{.*}}get_index{{.*}}( + // CHECK: call {{.*}}@{{.*}}make_c{{.*}}( + // CHECK: call + get_index()[make_c()] = 0; +// CHECK: } +} + + +void *operator new(decltype(sizeof(0)), C); + +// CHECK-LABEL: define {{.*}}@{{.*}}alloc_before_init{{.*}}( +void alloc_before_init() { + struct Q { Q(A) {} }; + // CHECK-ITANIUM: call {{.*}}@_Znw{{.*}}( + // CHECK-WINDOWS: call {{.*}}@"\01??2@YAPEAX_K@Z"( + // CHECK: call {{.*}}@{{.*}}make_a{{.*}}( + delete new Q(make_a()); + + // CHECK: call {{.*}}@{{.*}}make_c{{.*}}( + // CHECK: call {{.*}}@{{.*}}make_a{{.*}}( + new (make_c()) Q(make_a()); +// CHECK: } +} + +#if 0 +// CHECKDISABLED-LABEL: define {{.*}}@{{.*}}dotstar_lhs_before_rhs{{.*}}( +int dotstar_lhs_before_rhs() { + // CHECKDISABLED: call {{.*}}@{{.*}}make_a{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_mem_ptr_a{{.*}}( + int a = make_a().*make_mem_ptr_a(); + + // CHECKDISABLED: call {{.*}}@{{.*}}make_a_ptr{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_mem_ptr_a{{.*}}( + int b = make_a_ptr()->*make_mem_ptr_a(); + + // CHECKDISABLED: call {{.*}}@{{.*}}make_c{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_b{{.*}}( + make_c()->*make_b(); + + // CHECKDISABLED: call {{.*}}@{{.*}}make_a{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_mem_fn_ptr_a{{.*}}( + // CHECKDISABLED: call + (make_a().*make_mem_fn_ptr_a())(); + + // CHECKDISABLED: call {{.*}}@{{.*}}make_a_ptr{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_mem_fn_ptr_a{{.*}}( + // CHECKDISABLED: call + (make_a_ptr()->*make_mem_fn_ptr_a())(); + + return a + b; +// CHECKDISABLED: } +} +#endif +#if 0 +// CHECKDISABLED-LABEL: define {{.*}}@{{.*}}assign_lhs_before_rhs{{.*}}( +void assign_rhs_before_lhs() { + extern int &lhs_ref(), rhs(); + + // CHECKDISABLED: call {{.*}}@{{.*}}rhs{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}lhs_ref{{.*}}( + lhs_ref() = rhs(); + + // CHECKDISABLED: call {{.*}}@{{.*}}rhs{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}lhs_ref{{.*}}( + lhs_ref() += rhs(); + + // CHECKDISABLED: call {{.*}}@{{.*}}rhs{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}lhs_ref{{.*}}( + lhs_ref() %= rhs(); + + // CHECKDISABLED: call {{.*}}@{{.*}}make_b{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_c{{.*}}( + make_c() = make_b(); + + // CHECKDISABLED: call {{.*}}@{{.*}}make_b{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_c{{.*}}( + make_c() += make_b(); +// CHECKDISABLED: } +} +#endif +#if 0 +// CHECKDISABLED-LABEL: define {{.*}}@{{.*}}shift_lhs_before_rhs{{.*}}( +void shift_lhs_before_rhs() { + extern int lhs(), rhs(); + + // CHECKDISABLED: call {{.*}}@{{.*}}lhs{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}rhs{{.*}}( + (void)(lhs() << rhs()); + + // CHECKDISABLED: call {{.*}}@{{.*}}lhs{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}rhs{{.*}}( + (void)(lhs() >> rhs()); + + // CHECKDISABLED: call {{.*}}@{{.*}}make_c{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_a{{.*}}( + make_c() << make_a(); + + // CHECKDISABLED: call {{.*}}@{{.*}}make_c{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_a{{.*}}( + make_c() >> make_a(); + + // CHECKDISABLED: call {{.*}}@{{.*}}make_c{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_b{{.*}}( + make_c() << make_b(); + + // CHECKDISABLED: call {{.*}}@{{.*}}make_c{{.*}}( + // CHECKDISABLED: call {{.*}}@{{.*}}make_b{{.*}}( + make_c() >> make_b(); +// CHECKDISABLED: } +} +#endif diff --git a/clang/test/CodeGenCXX/pragma-loop-safety.cpp b/clang/test/CodeGenCXX/pragma-loop-safety.cpp index 393f0a3..c6ce827 100644 --- a/clang/test/CodeGenCXX/pragma-loop-safety.cpp +++ b/clang/test/CodeGenCXX/pragma-loop-safety.cpp @@ -10,12 +10,12 @@ void vectorize_test(int *List, int Length) { #pragma clang loop vectorize(assume_safety) interleave(disable) unroll(disable) for (int i = 0; i < Length; i++) { // CHECK: [[RHIV1:.+]] = load i32, i32* [[IV1]], {{.*}}!llvm.mem.parallel_loop_access ![[LOOP1_ID]] - // CHECK-NEXT: [[CALC1:.+]] = mul nsw i32[[RHIV1]], 2 - // CHECK-NEXT: [[SIV1:.+]] = load i32, i32* [[IV1]]{{.*}}!llvm.mem.parallel_loop_access ![[LOOP1_ID]] - // CHECK-NEXT: [[INDEX1:.+]] = sext i32[[SIV1]] to i64 - // CHECK-NEXT: [[ARRAY1:.+]] = load i32*, i32** [[LIST1:.*]], {{.*}}!llvm.mem.parallel_loop_access ![[LOOP1_ID]] - // CHECK-NEXT: [[PTR1:.+]] = getelementptr inbounds i32, i32*[[ARRAY1]], i64[[INDEX1]] - // CHECK-NEXT: store i32[[CALC1]], i32*[[PTR1]], {{.*}}!llvm.mem.parallel_loop_access ![[LOOP1_ID]] + // CHECK-DAG: [[CALC1:.+]] = mul nsw i32[[RHIV1]], 2 + // CHECK-DAG: [[SIV1:.+]] = load i32, i32* [[IV1]]{{.*}}!llvm.mem.parallel_loop_access ![[LOOP1_ID]] + // CHECK-DAG: [[INDEX1:.+]] = sext i32[[SIV1]] to i64 + // CHECK-DAG: [[ARRAY1:.+]] = load i32*, i32** [[LIST1:.*]], {{.*}}!llvm.mem.parallel_loop_access ![[LOOP1_ID]] + // CHECK-DAG: [[PTR1:.+]] = getelementptr inbounds i32, i32*[[ARRAY1]], i64[[INDEX1]] + // CHECK: store i32[[CALC1]], i32*[[PTR1]], {{.*}}!llvm.mem.parallel_loop_access ![[LOOP1_ID]] // CHECK-NEXT: br label [[LOOP1_INC:[^,]+]] List[i] = i * 2; @@ -33,12 +33,12 @@ void interleave_test(int *List, int Length) { #pragma clang loop interleave(assume_safety) vectorize(disable) unroll(disable) for (int i = 0; i < Length; i++) { // CHECK: [[RHIV2:.+]] = load i32, i32* [[IV2]], {{.*}}!llvm.mem.parallel_loop_access ![[LOOP2_ID]] - // CHECK-NEXT: [[CALC2:.+]] = mul nsw i32[[RHIV2]], 2 - // CHECK-NEXT: [[SIV2:.+]] = load i32, i32* [[IV2]]{{.*}}!llvm.mem.parallel_loop_access ![[LOOP2_ID]] - // CHECK-NEXT: [[INDEX2:.+]] = sext i32[[SIV2]] to i64 - // CHECK-NEXT: [[ARRAY2:.+]] = load i32*, i32** [[LIST2:.*]], {{.*}}!llvm.mem.parallel_loop_access ![[LOOP2_ID]] - // CHECK-NEXT: [[PTR2:.+]] = getelementptr inbounds i32, i32*[[ARRAY2]], i64[[INDEX2]] - // CHECK-NEXT: store i32[[CALC2]], i32*[[PTR2]], {{.*}}!llvm.mem.parallel_loop_access ![[LOOP2_ID]] + // CHECK-DAG: [[CALC2:.+]] = mul nsw i32[[RHIV2]], 2 + // CHECK-DAG: [[SIV2:.+]] = load i32, i32* [[IV2]]{{.*}}!llvm.mem.parallel_loop_access ![[LOOP2_ID]] + // CHECK-DAG: [[INDEX2:.+]] = sext i32[[SIV2]] to i64 + // CHECK-DAG: [[ARRAY2:.+]] = load i32*, i32** [[LIST2:.*]], {{.*}}!llvm.mem.parallel_loop_access ![[LOOP2_ID]] + // CHECK-DAG: [[PTR2:.+]] = getelementptr inbounds i32, i32*[[ARRAY2]], i64[[INDEX2]] + // CHECK: store i32[[CALC2]], i32*[[PTR2]], {{.*}}!llvm.mem.parallel_loop_access ![[LOOP2_ID]] // CHECK-NEXT: br label [[LOOP2_INC:[^,]+]] List[i] = i * 2; diff --git a/clang/test/CodeGenCXX/vla-lambda-capturing.cpp b/clang/test/CodeGenCXX/vla-lambda-capturing.cpp index 44b6a25..5081f14 100644 --- a/clang/test/CodeGenCXX/vla-lambda-capturing.cpp +++ b/clang/test/CodeGenCXX/vla-lambda-capturing.cpp @@ -125,11 +125,11 @@ int main() { // CHECK: [[SIZE2:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SIZE2_REF]] // CHECK: [[SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]], [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 2 // CHECK: [[SIZE1:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SIZE1_REF]] +// CHECK: [[BUFFER1_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]], [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 3 +// CHECK: [[BUFFER1_ADDR:%.+]] = load [[INTPTR_T]]*, [[INTPTR_T]]** [[BUFFER1_ADDR_REF]] // CHECK: [[N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]], [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // CHECK: [[N_ADDR:%.+]] = load [[INTPTR_T]]*, [[INTPTR_T]]** [[N_ADDR_REF]] // CHECK: [[N:%.+]] = load [[INTPTR_T]], [[INTPTR_T]]* [[N_ADDR]] -// CHECK: [[BUFFER1_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]], [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 3 -// CHECK: [[BUFFER1_ADDR:%.+]] = load [[INTPTR_T]]*, [[INTPTR_T]]** [[BUFFER1_ADDR_REF]] // CHECK: [[ELEM_OFFSET:%.+]] = mul {{.*}} i{{[0-9]+}} [[N]], [[SIZE1]] // CHECK: [[ELEM_ADDR:%.+]] = getelementptr inbounds [[INTPTR_T]], [[INTPTR_T]]* [[BUFFER1_ADDR]], i{{[0-9]+}} [[ELEM_OFFSET]] // CHECK: [[SIZEOF:%.+]] = mul {{.*}} i{{[0-9]+}} {{[0-9]+}}, [[SIZE1]] -- 2.7.4