From 162351a655bcc71ad6c76710c30518b032231ab4 Mon Sep 17 00:00:00 2001 From: Sirraide Date: Wed, 26 Nov 2025 17:15:21 +0100 Subject: [PATCH 1/2] [Clang] [C++26] Expansion Statements (Part 8) --- clang/lib/CodeGen/CGStmt.cpp | 41 +- clang/lib/CodeGen/CodeGenFunction.h | 3 + .../cxx2c-destructuring-expansion-stmt.cpp | 471 +++++ ...cxx2c-enumerating-expansion-statements.cpp | 1518 +++++++++++++++++ .../cxx2c-expansion-stmts-control-flow.cpp | 429 +++++ .../cxx2c-expansion-stmts-templates.cpp | 208 +++ .../cxx2c-iterating-expansion-stmt.cpp | 474 +++++ 7 files changed, 3143 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGenCXX/cxx2c-destructuring-expansion-stmt.cpp create mode 100644 clang/test/CodeGenCXX/cxx2c-enumerating-expansion-statements.cpp create mode 100644 clang/test/CodeGenCXX/cxx2c-expansion-stmts-control-flow.cpp create mode 100644 clang/test/CodeGenCXX/cxx2c-expansion-stmts-templates.cpp create mode 100644 clang/test/CodeGenCXX/cxx2c-iterating-expansion-stmt.cpp diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 40c92035008ae..d6c6d159a5438 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -210,7 +210,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef Attrs) { case Stmt::CXXDependentExpansionStmtPatternClass: llvm_unreachable("unexpanded expansion statements should not be emitted"); case Stmt::CXXExpansionStmtInstantiationClass: - llvm_unreachable("Todo"); + EmitCXXExpansionStmtInstantiation(cast(*S)); + break; case Stmt::SEHTryStmtClass: EmitSEHTryStmt(cast(*S)); break; @@ -1563,6 +1564,44 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S, } } +void CodeGenFunction::EmitCXXExpansionStmtInstantiation( + const CXXExpansionStmtInstantiation &S) { + // FIXME: For reasons beyond my understanding, two scopes are required to emit + // the destructors of lifetime-extended temporaries in the right place, but + // only in some templates. There are some other issues with lifetime-extended + // temporaries currently (https://github.com/llvm/llvm-project/issues/165182); + // perhaps resolving those will allow us to remove the second scope here + // because there really ought to be a better way of doing this. + LexicalScope Scope(*this, S.getSourceRange()); + LexicalScope Scope2(*this, S.getSourceRange()); + + for (const Stmt *DS : S.getSharedStmts()) + EmitStmt(DS); + + if (S.getInstantiations().empty() || !HaveInsertPoint()) + return; + + JumpDest ExpandExit = getJumpDestInCurrentScope("expand.end"); + JumpDest ContinueDest; + for (auto [N, Inst] : enumerate(S.getInstantiations())) { + if (!HaveInsertPoint()) { + EmitBlock(ExpandExit.getBlock(), true); + return; + } + + if (N == S.getInstantiations().size() - 1) + ContinueDest = ExpandExit; + else + ContinueDest = getJumpDestInCurrentScope("expand.next"); + + LexicalScope ExpansionScope(*this, S.getSourceRange()); + BreakContinueStack.push_back(BreakContinue(S, ExpandExit, ContinueDest)); + EmitStmt(Inst); + BreakContinueStack.pop_back(); + EmitBlock(ContinueDest.getBlock(), true); + } +} + void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) { if (RV.isScalar()) { Builder.CreateStore(RV.getScalarVal(), ReturnValue); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 8c4c1c8c2dc95..a895f187f3946 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3690,6 +3690,9 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitCXXForRangeStmt(const CXXForRangeStmt &S, ArrayRef Attrs = {}); + void + EmitCXXExpansionStmtInstantiation(const CXXExpansionStmtInstantiation &S); + /// Controls insertion of cancellation exit blocks in worksharing constructs. class OMPCancelStackRAII { CodeGenFunction &CGF; diff --git a/clang/test/CodeGenCXX/cxx2c-destructuring-expansion-stmt.cpp b/clang/test/CodeGenCXX/cxx2c-destructuring-expansion-stmt.cpp new file mode 100644 index 0000000000000..16d8c370a9d3f --- /dev/null +++ b/clang/test/CodeGenCXX/cxx2c-destructuring-expansion-stmt.cpp @@ -0,0 +1,471 @@ +// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +struct A {}; +struct B { int x = 1; }; +struct C { int a = 1, b = 2, c = 3; }; + +void g(int); + +int references_destructuring() { + C c; + template for (auto& x : c) { ++x; } + template for (auto&& x : c) { ++x; } + return c.a + c.b + c.c; +} + +template +int destructure() { + int sum = 0; + template for (auto x : v) sum += x; + template for (constexpr auto x : v) sum += x; + return sum; +} + +void f() { + destructure(); + destructure(); + destructure(); +} + +void empty() { + static constexpr A a; + template for (auto x : A()) g(x); + template for (auto& x : a) g(x); + template for (auto&& x : A()) g(x); + template for (constexpr auto x : a) g(x); +} + +namespace apply_lifetime_extension { +struct T { + int& x; + T(int& x) noexcept : x(x) {} + ~T() noexcept { x = 42; } +}; + +const T& f(const T& t) noexcept { return t; } +T g(int& x) noexcept { return T(x); } + +// CWG 3043: +// +// Lifetime extension only applies to destructuring expansion statements +// (enumerating statements don't have a range variable, and the range variable +// of iterating statements is constexpr). +int lifetime_extension() { + int x = 5; + int sum = 0; + template for (auto e : f(g(x))) { + sum += x; + } + return sum + x; +} + +template +int lifetime_extension_instantiate_expansions() { + int x = 5; + int sum = 0; + template for (T e : f(g(x))) { + sum += x; + } + return sum + x; +} + +template +int lifetime_extension_dependent_expansion_stmt() { + int x = 5; + int sum = 0; + template for (int e : f(g((T&)x))) { + sum += x; + } + return sum + x; +} + +template +struct foo { + template + int lifetime_extension_multiple_instantiations() { + int x = 5; + int sum = 0; + template for (T e : f(g((U&)x))) { + sum += x; + } + return sum + x; + } +}; + +void instantiate() { + lifetime_extension_instantiate_expansions(); + lifetime_extension_dependent_expansion_stmt(); + foo().lifetime_extension_multiple_instantiations(); +} +} + +// CHECK: @_ZZ5emptyvE1a = internal constant %struct.A zeroinitializer, align 1 +// CHECK: @_ZTAXtl1BLi10EEE = {{.*}} constant %struct.B { i32 10 }, comdat +// CHECK: @_ZTAXtl1CLi1ELi2ELi3EEE = {{.*}} constant %struct.C { i32 1, i32 2, i32 3 }, comdat +// CHECK: @_ZTAXtl1CLi3ELi4ELi5EEE = {{.*}} constant %struct.C { i32 3, i32 4, i32 5 }, comdat + + +// CHECK-LABEL: define {{.*}} i32 @_Z24references_destructuringv() +// CHECK: entry: +// CHECK-NEXT: %c = alloca %struct.C, align 4 +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca ptr, align 8 +// CHECK-NEXT: %x1 = alloca ptr, align 8 +// CHECK-NEXT: %x4 = alloca ptr, align 8 +// CHECK-NEXT: %1 = alloca ptr, align 8 +// CHECK-NEXT: %x7 = alloca ptr, align 8 +// CHECK-NEXT: %x11 = alloca ptr, align 8 +// CHECK-NEXT: %x15 = alloca ptr, align 8 +// CHECK-NEXT: call void @_ZN1CC1Ev(ptr {{.*}} %c) +// CHECK-NEXT: store ptr %c, ptr %0, align 8 +// CHECK-NEXT: %2 = load ptr, ptr %0, align 8 +// CHECK-NEXT: %a = getelementptr inbounds nuw %struct.C, ptr %2, i32 0, i32 0 +// CHECK-NEXT: store ptr %a, ptr %x, align 8 +// CHECK-NEXT: %3 = load ptr, ptr %x, align 8 +// CHECK-NEXT: %4 = load i32, ptr %3, align 4 +// CHECK-NEXT: %inc = add nsw i32 %4, 1 +// CHECK-NEXT: store i32 %inc, ptr %3, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: %5 = load ptr, ptr %0, align 8 +// CHECK-NEXT: %b = getelementptr inbounds nuw %struct.C, ptr %5, i32 0, i32 1 +// CHECK-NEXT: store ptr %b, ptr %x1, align 8 +// CHECK-NEXT: %6 = load ptr, ptr %x1, align 8 +// CHECK-NEXT: %7 = load i32, ptr %6, align 4 +// CHECK-NEXT: %inc2 = add nsw i32 %7, 1 +// CHECK-NEXT: store i32 %inc2, ptr %6, align 4 +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: %8 = load ptr, ptr %0, align 8 +// CHECK-NEXT: %c5 = getelementptr inbounds nuw %struct.C, ptr %8, i32 0, i32 2 +// CHECK-NEXT: store ptr %c5, ptr %x4, align 8 +// CHECK-NEXT: %9 = load ptr, ptr %x4, align 8 +// CHECK-NEXT: %10 = load i32, ptr %9, align 4 +// CHECK-NEXT: %inc6 = add nsw i32 %10, 1 +// CHECK-NEXT: store i32 %inc6, ptr %9, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store ptr %c, ptr %1, align 8 +// CHECK-NEXT: %11 = load ptr, ptr %1, align 8 +// CHECK-NEXT: %a8 = getelementptr inbounds nuw %struct.C, ptr %11, i32 0, i32 0 +// CHECK-NEXT: store ptr %a8, ptr %x7, align 8 +// CHECK-NEXT: %12 = load ptr, ptr %x7, align 8 +// CHECK-NEXT: %13 = load i32, ptr %12, align 4 +// CHECK-NEXT: %inc9 = add nsw i32 %13, 1 +// CHECK-NEXT: store i32 %inc9, ptr %12, align 4 +// CHECK-NEXT: br label %expand.next10 +// CHECK: expand.next10: +// CHECK-NEXT: %14 = load ptr, ptr %1, align 8 +// CHECK-NEXT: %b12 = getelementptr inbounds nuw %struct.C, ptr %14, i32 0, i32 1 +// CHECK-NEXT: store ptr %b12, ptr %x11, align 8 +// CHECK-NEXT: %15 = load ptr, ptr %x11, align 8 +// CHECK-NEXT: %16 = load i32, ptr %15, align 4 +// CHECK-NEXT: %inc13 = add nsw i32 %16, 1 +// CHECK-NEXT: store i32 %inc13, ptr %15, align 4 +// CHECK-NEXT: br label %expand.next14 +// CHECK: expand.next14: +// CHECK-NEXT: %17 = load ptr, ptr %1, align 8 +// CHECK-NEXT: %c16 = getelementptr inbounds nuw %struct.C, ptr %17, i32 0, i32 2 +// CHECK-NEXT: store ptr %c16, ptr %x15, align 8 +// CHECK-NEXT: %18 = load ptr, ptr %x15, align 8 +// CHECK-NEXT: %19 = load i32, ptr %18, align 4 +// CHECK-NEXT: %inc17 = add nsw i32 %19, 1 +// CHECK-NEXT: store i32 %inc17, ptr %18, align 4 +// CHECK-NEXT: br label %expand.end18 +// CHECK: expand.end18: +// CHECK-NEXT: %a19 = getelementptr inbounds nuw %struct.C, ptr %c, i32 0, i32 0 +// CHECK-NEXT: %20 = load i32, ptr %a19, align 4 +// CHECK-NEXT: %b20 = getelementptr inbounds nuw %struct.C, ptr %c, i32 0, i32 1 +// CHECK-NEXT: %21 = load i32, ptr %b20, align 4 +// CHECK-NEXT: %add = add nsw i32 %20, %21 +// CHECK-NEXT: %c21 = getelementptr inbounds nuw %struct.C, ptr %c, i32 0, i32 2 +// CHECK-NEXT: %22 = load i32, ptr %c21, align 4 +// CHECK-NEXT: %add22 = add nsw i32 %add, %22 +// CHECK-NEXT: ret i32 %add22 + + +// CHECK-LABEL: define {{.*}} void @_Z1fv() +// CHECK: entry: +// CHECK-NEXT: %call = call {{.*}} i32 @_Z11destructureITnDaXtl1BLi10EEEEiv() +// CHECK-NEXT: %call1 = call {{.*}} i32 @_Z11destructureITnDaXtl1CLi1ELi2ELi3EEEEiv() +// CHECK-NEXT: %call2 = call {{.*}} i32 @_Z11destructureITnDaXtl1CLi3ELi4ELi5EEEEiv() +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} i32 @_Z11destructureITnDaXtl1BLi10EEEEiv() +// CHECK: entry: +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %1 = alloca ptr, align 8 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: store ptr @_ZTAXtl1BLi10EEE, ptr %0, align 8 +// CHECK-NEXT: store i32 10, ptr %x, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x, align 4 +// CHECK-NEXT: %3 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %3, %2 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store ptr @_ZTAXtl1BLi10EEE, ptr %1, align 8 +// CHECK-NEXT: store i32 10, ptr %x1, align 4 +// CHECK-NEXT: %4 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add2 = add nsw i32 %4, 10 +// CHECK-NEXT: store i32 %add2, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end3 +// CHECK: expand.end3: +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %5 + + +// CHECK-LABEL: define {{.*}} i32 @_Z11destructureITnDaXtl1CLi1ELi2ELi3EEEEiv() +// CHECK: entry: +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x4 = alloca i32, align 4 +// CHECK-NEXT: %1 = alloca ptr, align 8 +// CHECK-NEXT: %x6 = alloca i32, align 4 +// CHECK-NEXT: %x9 = alloca i32, align 4 +// CHECK-NEXT: %x12 = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: store ptr @_ZTAXtl1CLi1ELi2ELi3EEE, ptr %0, align 8 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x, align 4 +// CHECK-NEXT: %3 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %3, %2 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 2, ptr %x1, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x1, align 4 +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add2 = add nsw i32 %5, %4 +// CHECK-NEXT: store i32 %add2, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: store i32 3, ptr %x4, align 4 +// CHECK-NEXT: %6 = load i32, ptr %x4, align 4 +// CHECK-NEXT: %7 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add5 = add nsw i32 %7, %6 +// CHECK-NEXT: store i32 %add5, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store ptr @_ZTAXtl1CLi1ELi2ELi3EEE, ptr %1, align 8 +// CHECK-NEXT: store i32 1, ptr %x6, align 4 +// CHECK-NEXT: %8 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add7 = add nsw i32 %8, 1 +// CHECK-NEXT: store i32 %add7, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next8 +// CHECK: expand.next8: +// CHECK-NEXT: store i32 2, ptr %x9, align 4 +// CHECK-NEXT: %9 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add10 = add nsw i32 %9, 2 +// CHECK-NEXT: store i32 %add10, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next11 +// CHECK: expand.next11: +// CHECK-NEXT: store i32 3, ptr %x12, align 4 +// CHECK-NEXT: %10 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add13 = add nsw i32 %10, 3 +// CHECK-NEXT: store i32 %add13, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end14 +// CHECK: expand.end14: +// CHECK-NEXT: %11 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %11 + + +// CHECK-LABEL: define {{.*}} i32 @_Z11destructureITnDaXtl1CLi3ELi4ELi5EEEEiv() +// CHECK: entry: +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x4 = alloca i32, align 4 +// CHECK-NEXT: %1 = alloca ptr, align 8 +// CHECK-NEXT: %x6 = alloca i32, align 4 +// CHECK-NEXT: %x9 = alloca i32, align 4 +// CHECK-NEXT: %x12 = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: store ptr @_ZTAXtl1CLi3ELi4ELi5EEE, ptr %0, align 8 +// CHECK-NEXT: store i32 3, ptr %x, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x, align 4 +// CHECK-NEXT: %3 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %3, %2 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 4, ptr %x1, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x1, align 4 +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add2 = add nsw i32 %5, %4 +// CHECK-NEXT: store i32 %add2, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: store i32 5, ptr %x4, align 4 +// CHECK-NEXT: %6 = load i32, ptr %x4, align 4 +// CHECK-NEXT: %7 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add5 = add nsw i32 %7, %6 +// CHECK-NEXT: store i32 %add5, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store ptr @_ZTAXtl1CLi3ELi4ELi5EEE, ptr %1, align 8 +// CHECK-NEXT: store i32 3, ptr %x6, align 4 +// CHECK-NEXT: %8 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add7 = add nsw i32 %8, 3 +// CHECK-NEXT: store i32 %add7, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next8 +// CHECK: expand.next8: +// CHECK-NEXT: store i32 4, ptr %x9, align 4 +// CHECK-NEXT: %9 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add10 = add nsw i32 %9, 4 +// CHECK-NEXT: store i32 %add10, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next11 +// CHECK: expand.next11: +// CHECK-NEXT: store i32 5, ptr %x12, align 4 +// CHECK-NEXT: %10 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add13 = add nsw i32 %10, 5 +// CHECK-NEXT: store i32 %add13, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end14 +// CHECK: expand.end14: +// CHECK-NEXT: %11 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %11 + + +// CHECK-LABEL: define {{.*}} void @_Z5emptyv() +// CHECK: entry: +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK-NEXT: %ref.tmp = alloca %struct.A, align 1 +// CHECK-NEXT: %1 = alloca ptr, align 8 +// CHECK-NEXT: %2 = alloca ptr, align 8 +// CHECK-NEXT: %ref.tmp1 = alloca %struct.A, align 1 +// CHECK-NEXT: %3 = alloca ptr, align 8 +// CHECK-NEXT: store ptr %ref.tmp, ptr %0, align 8 +// CHECK-NEXT: store ptr @_ZZ5emptyvE1a, ptr %1, align 8 +// CHECK-NEXT: store ptr %ref.tmp1, ptr %2, align 8 +// CHECK-NEXT: store ptr @_ZZ5emptyvE1a, ptr %3, align 8 +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} i32 @_ZN24apply_lifetime_extension18lifetime_extensionEv() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK: %ref.tmp = alloca %"struct.apply_lifetime_extension::T", align 8 +// CHECK-NEXT: %e = alloca i32, align 4 +// CHECK-NEXT: store i32 5, ptr %x, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK: call void @_ZN24apply_lifetime_extension1gERi(ptr dead_on_unwind writable sret(%"struct.apply_lifetime_extension::T") align 8 %ref.tmp, ptr {{.*}} %x) +// CHECK-NEXT: %call = call {{.*}} ptr @_ZN24apply_lifetime_extension1fERKNS_1TE(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: store ptr %call, ptr %0, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %0, align 8 +// CHECK: %x1 = getelementptr inbounds nuw %"struct.apply_lifetime_extension::T", ptr %1, i32 0, i32 0 +// CHECK-NEXT: %2 = load ptr, ptr %x1, align 8 +// CHECK-NEXT: %3 = load i32, ptr %2, align 4 +// CHECK-NEXT: store i32 %3, ptr %e, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x, align 4 +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %5, %4 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: call void @_ZN24apply_lifetime_extension1TD1Ev(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: %6 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %7 = load i32, ptr %x, align 4 +// CHECK-NEXT: %add2 = add nsw i32 %6, %7 +// CHECK-NEXT: ret i32 %add2 + + +// CHECK-LABEL: define {{.*}} i32 @_ZN24apply_lifetime_extension41lifetime_extension_instantiate_expansionsIiEEiv() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK: %ref.tmp = alloca %"struct.apply_lifetime_extension::T", align 8 +// CHECK-NEXT: %e = alloca i32, align 4 +// CHECK-NEXT: store i32 5, ptr %x, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK: call void @_ZN24apply_lifetime_extension1gERi(ptr dead_on_unwind writable sret(%"struct.apply_lifetime_extension::T") align 8 %ref.tmp, ptr {{.*}} %x) +// CHECK-NEXT: %call = call {{.*}} ptr @_ZN24apply_lifetime_extension1fERKNS_1TE(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: store ptr %call, ptr %0, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %0, align 8 +// CHECK: %x1 = getelementptr inbounds nuw %"struct.apply_lifetime_extension::T", ptr %1, i32 0, i32 0 +// CHECK-NEXT: %2 = load ptr, ptr %x1, align 8 +// CHECK-NEXT: %3 = load i32, ptr %2, align 4 +// CHECK-NEXT: store i32 %3, ptr %e, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x, align 4 +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %5, %4 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: call void @_ZN24apply_lifetime_extension1TD1Ev(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: %6 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %7 = load i32, ptr %x, align 4 +// CHECK-NEXT: %add2 = add nsw i32 %6, %7 +// CHECK-NEXT: ret i32 %add2 + + +// CHECK-LABEL: define {{.*}} i32 @_ZN24apply_lifetime_extension43lifetime_extension_dependent_expansion_stmtIiEEiv() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK: %ref.tmp = alloca %"struct.apply_lifetime_extension::T", align 8 +// CHECK-NEXT: %e = alloca i32, align 4 +// CHECK-NEXT: store i32 5, ptr %x, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK: call void @_ZN24apply_lifetime_extension1gERi(ptr dead_on_unwind writable sret(%"struct.apply_lifetime_extension::T") align 8 %ref.tmp, ptr {{.*}} %x) +// CHECK-NEXT: %call = call {{.*}} ptr @_ZN24apply_lifetime_extension1fERKNS_1TE(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: store ptr %call, ptr %0, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %0, align 8 +// CHECK: %x1 = getelementptr inbounds nuw %"struct.apply_lifetime_extension::T", ptr %1, i32 0, i32 0 +// CHECK-NEXT: %2 = load ptr, ptr %x1, align 8 +// CHECK-NEXT: %3 = load i32, ptr %2, align 4 +// CHECK-NEXT: store i32 %3, ptr %e, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x, align 4 +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %5, %4 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: call void @_ZN24apply_lifetime_extension1TD1Ev(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: %6 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %7 = load i32, ptr %x, align 4 +// CHECK-NEXT: %add2 = add nsw i32 %6, %7 +// CHECK-NEXT: ret i32 %add2 + + +// CHECK-LABEL: define {{.*}} i32 @_ZN24apply_lifetime_extension3fooIiE42lifetime_extension_multiple_instantiationsIiEEiv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK: %ref.tmp = alloca %"struct.apply_lifetime_extension::T", align 8 +// CHECK-NEXT: %e = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: store i32 5, ptr %x, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK: call void @_ZN24apply_lifetime_extension1gERi(ptr dead_on_unwind writable sret(%"struct.apply_lifetime_extension::T") align 8 %ref.tmp, ptr {{.*}} %x) +// CHECK-NEXT: %call = call {{.*}} ptr @_ZN24apply_lifetime_extension1fERKNS_1TE(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: store ptr %call, ptr %0, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %0, align 8 +// CHECK: %x2 = getelementptr inbounds nuw %"struct.apply_lifetime_extension::T", ptr %1, i32 0, i32 0 +// CHECK-NEXT: %2 = load ptr, ptr %x2, align 8 +// CHECK-NEXT: %3 = load i32, ptr %2, align 4 +// CHECK-NEXT: store i32 %3, ptr %e, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x, align 4 +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %5, %4 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: call void @_ZN24apply_lifetime_extension1TD1Ev(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: %6 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %7 = load i32, ptr %x, align 4 +// CHECK-NEXT: %add3 = add nsw i32 %6, %7 +// CHECK-NEXT: ret i32 %add3 diff --git a/clang/test/CodeGenCXX/cxx2c-enumerating-expansion-statements.cpp b/clang/test/CodeGenCXX/cxx2c-enumerating-expansion-statements.cpp new file mode 100644 index 0000000000000..c82b345de206b --- /dev/null +++ b/clang/test/CodeGenCXX/cxx2c-enumerating-expansion-statements.cpp @@ -0,0 +1,1518 @@ +// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +struct S { + int x; + constexpr S(int x) : x{x} {} +}; + +void g(int); +void g(long); +void g(const char*); +void g(S); + +template constexpr int tg() { return n; } + +void h(int, int); + +void f1() { + template for (auto x : {1, 2, 3}) g(x); +} + +void f2() { + template for (auto x : {1, "123", S(45)}) g(x); +} + +void f3() { + template for (auto x : {}) g(x); +} + +void f4() { + template for (auto x : {1, 2}) + template for (auto y : {3, 4}) + h(x, y); +} + +void f5() { + template for (auto x : {}) static_assert(false, "discarded"); + template for (constexpr auto x : {}) static_assert(false, "discarded"); + template for (auto x : {1}) g(x); + template for (auto x : {2, 3, 4}) g(x); + template for (constexpr auto x : {5}) g(x); + template for (constexpr auto x : {6, 7, 8}) g(x); + template for (constexpr auto x : {9}) tg(); + template for (constexpr auto x : {10, 11, 12}) + static_assert(tg()); + + template for (int x : {13, 14, 15}) g(x); + template for (S x : {16, 17, 18}) g(x.x); + template for (constexpr S x : {19, 20, 21}) tg(); +} + +template +void t1() { + template for (T x : {}) g(x); + template for (constexpr T x : {}) g(x); + template for (auto x : {}) g(x); + template for (constexpr auto x : {}) g(x); + template for (T x : {1, 2}) g(x); + template for (T x : {T(3), T(4)}) g(x); + template for (auto x : {T(5), T(6)}) g(x); + template for (constexpr T x : {T(7), T(8)}) static_assert(tg()); + template for (constexpr auto x : {T(9), T(10)}) static_assert(tg()); +} + +template +struct s1 { + template + void tf() { + template for (T x : {}) g(x); + template for (constexpr T x : {}) g(x); + template for (U x : {}) g(x); + template for (constexpr U x : {}) g(x); + template for (auto x : {}) g(x); + template for (constexpr auto x : {}) g(x); + template for (T x : {1, 2}) g(x); + template for (U x : {3, 4}) g(x); + template for (U x : {T(5), T(6)}) g(x); + template for (T x : {U(7), U(8)}) g(x); + template for (auto x : {T(9), T(10)}) g(x); + template for (auto x : {U(11), T(12)}) g(x); + template for (constexpr U x : {T(13), T(14)}) static_assert(tg()); + template for (constexpr T x : {U(15), U(16)}) static_assert(tg()); + template for (constexpr auto x : {T(17), U(18)}) static_assert(tg()); + } +}; + +template +void t2() { + template for (T x : {}) g(x); +} + +void f6() { + t1(); + t1(); + s1().tf(); + s1().tf(); + s1().tf(); + s1().tf(); + t2(); + t2(); + t2(); +} + +struct X { + int a, b, c; +}; + +template +void t3(Ts... ts) { + template for (auto x : {ts...}) g(x); + template for (auto x : {1, ts..., 2, ts..., 3}) g(x); + template for (auto x : {4, ts..., ts..., 5}) g(x); + template for (X x : {{ts...}, {ts...}, {6, 7, 8}}) g(x.a); + template for (X x : {X{ts...}}) g(x.a); +} + +template +void t4() { + template for (constexpr auto x : {is...}) { + g(x); + tg(); + } + + template for (constexpr auto x : {1, is..., 2, is..., 3}) { + g(x); + tg(); + } + + template for (constexpr auto x : {4, is..., is..., 5}) { + g(x); + tg(); + } + + template for (constexpr X x : {{is...}, {is...}, {6, 7, 8}}) { + g(x.a); + tg(); + } + + template for (constexpr X x : {X{is...}}) { + g(x.a); + tg(); + } +} + +template +struct s2 { + template + void tf() { + template for (auto x : {is..., js...}) g(x); + template for (X x : {{is...}, {js...}}) g(x.a); + template for (constexpr auto x : {is..., js...}) tg(); + template for (constexpr X x : {{is...}, {js...}}) tg(); + } +}; + +void f7() { + t3(42, 43, 44); + t4<42, 43, 44>(); + s2<1, 2, 3>().tf<4, 5, 6>(); +} + +template +void t5() { + ([] { + template for (constexpr auto x : {is}) { + g(x); + tg(); + } + }(), ...); +} + +void f8() { + t5<1, 2, 3>(); +} + +int references_enumerating() { + int x = 1, y = 2, z = 3; + template for (auto& v : {x, y, z}) { ++v; } + template for (auto&& v : {x, y, z}) { ++v; } + return x + y + z; +} + +// CHECK-LABEL: define {{.*}} void @_Z2f1v() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x3 = alloca i32, align 4 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %0) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 2, ptr %x1, align 4 +// CHECK-NEXT: %1 = load i32, ptr %x1, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %1) +// CHECK-NEXT: br label %expand.next2 +// CHECK: expand.next2: +// CHECK-NEXT: store i32 3, ptr %x3, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x3, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %2) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2f2v() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca ptr, align 8 +// CHECK-NEXT: %x3 = alloca %struct.S, align 4 +// CHECK-NEXT: %agg.tmp = alloca %struct.S, align 4 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %0) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store ptr @.str, ptr %x1, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %x1, align 8 +// CHECK-NEXT: call void @_Z1gPKc(ptr {{.*}} %1) +// CHECK-NEXT: br label %expand.next2 +// CHECK: expand.next2: +// CHECK-NEXT: call void @_ZN1SC1Ei(ptr {{.*}} %x3, i32 {{.*}} 45) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %x3, i64 4, i1 false) +// CHECK-NEXT: %coerce.dive = getelementptr inbounds nuw %struct.S, ptr %agg.tmp, i32 0, i32 0 +// CHECK-NEXT: %2 = load i32, ptr %coerce.dive, align 4 +// CHECK-NEXT: call void @_Z1g1S(i32 %2) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2f3v() +// CHECK: entry: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2f4v() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %y = alloca i32, align 4 +// CHECK-NEXT: %y1 = alloca i32, align 4 +// CHECK-NEXT: %x3 = alloca i32, align 4 +// CHECK-NEXT: %y4 = alloca i32, align 4 +// CHECK-NEXT: %y6 = alloca i32, align 4 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: store i32 3, ptr %y, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: %1 = load i32, ptr %y, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} %0, i32 {{.*}} %1) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 4, ptr %y1, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x, align 4 +// CHECK-NEXT: %3 = load i32, ptr %y1, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} %2, i32 {{.*}} %3) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: br label %expand.next2 +// CHECK: expand.next2: +// CHECK-NEXT: store i32 2, ptr %x3, align 4 +// CHECK-NEXT: store i32 3, ptr %y4, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x3, align 4 +// CHECK-NEXT: %5 = load i32, ptr %y4, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} %4, i32 {{.*}} %5) +// CHECK-NEXT: br label %expand.next5 +// CHECK: expand.next5: +// CHECK-NEXT: store i32 4, ptr %y6, align 4 +// CHECK-NEXT: %6 = load i32, ptr %x3, align 4 +// CHECK-NEXT: %7 = load i32, ptr %y6, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} %6, i32 {{.*}} %7) +// CHECK-NEXT: br label %expand.end7 +// CHECK: expand.end7: +// CHECK-NEXT: br label %expand.end8 +// CHECK: expand.end8: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2f5v() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x2 = alloca i32, align 4 +// CHECK-NEXT: %x4 = alloca i32, align 4 +// CHECK-NEXT: %x6 = alloca i32, align 4 +// CHECK-NEXT: %x8 = alloca i32, align 4 +// CHECK-NEXT: %x10 = alloca i32, align 4 +// CHECK-NEXT: %x12 = alloca i32, align 4 +// CHECK-NEXT: %x14 = alloca i32, align 4 +// CHECK-NEXT: %x16 = alloca i32, align 4 +// CHECK-NEXT: %x18 = alloca i32, align 4 +// CHECK-NEXT: %x20 = alloca i32, align 4 +// CHECK-NEXT: %x22 = alloca i32, align 4 +// CHECK-NEXT: %x24 = alloca i32, align 4 +// CHECK-NEXT: %x26 = alloca i32, align 4 +// CHECK-NEXT: %x28 = alloca %struct.S, align 4 +// CHECK-NEXT: %x31 = alloca %struct.S, align 4 +// CHECK-NEXT: %x34 = alloca %struct.S, align 4 +// CHECK-NEXT: %x37 = alloca %struct.S, align 4 +// CHECK-NEXT: %x40 = alloca %struct.S, align 4 +// CHECK-NEXT: %x43 = alloca %struct.S, align 4 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %0) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store i32 2, ptr %x1, align 4 +// CHECK-NEXT: %1 = load i32, ptr %x1, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %1) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 3, ptr %x2, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x2, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %2) +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: store i32 4, ptr %x4, align 4 +// CHECK-NEXT: %3 = load i32, ptr %x4, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %3) +// CHECK-NEXT: br label %expand.end5 +// CHECK: expand.end5: +// CHECK-NEXT: store i32 5, ptr %x6, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 5) +// CHECK-NEXT: br label %expand.end7 +// CHECK: expand.end7: +// CHECK-NEXT: store i32 6, ptr %x8, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 6) +// CHECK-NEXT: br label %expand.next9 +// CHECK: expand.next9: +// CHECK-NEXT: store i32 7, ptr %x10, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 7) +// CHECK-NEXT: br label %expand.next11 +// CHECK: expand.next11: +// CHECK-NEXT: store i32 8, ptr %x12, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 8) +// CHECK-NEXT: br label %expand.end13 +// CHECK: expand.end13: +// CHECK-NEXT: store i32 9, ptr %x14, align 4 +// CHECK-NEXT: %call = call {{.*}} i32 @_Z2tgILi9EEiv() +// CHECK-NEXT: br label %expand.end15 +// CHECK: expand.end15: +// CHECK-NEXT: store i32 10, ptr %x16, align 4 +// CHECK-NEXT: br label %expand.next17 +// CHECK: expand.next17: +// CHECK-NEXT: store i32 11, ptr %x18, align 4 +// CHECK-NEXT: br label %expand.next19 +// CHECK: expand.next19: +// CHECK-NEXT: store i32 12, ptr %x20, align 4 +// CHECK-NEXT: br label %expand.end21 +// CHECK: expand.end21: +// CHECK-NEXT: store i32 13, ptr %x22, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x22, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %4) +// CHECK-NEXT: br label %expand.next23 +// CHECK: expand.next23: +// CHECK-NEXT: store i32 14, ptr %x24, align 4 +// CHECK-NEXT: %5 = load i32, ptr %x24, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %5) +// CHECK-NEXT: br label %expand.next25 +// CHECK: expand.next25: +// CHECK-NEXT: store i32 15, ptr %x26, align 4 +// CHECK-NEXT: %6 = load i32, ptr %x26, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %6) +// CHECK-NEXT: br label %expand.end27 +// CHECK: expand.end27: +// CHECK-NEXT: call void @_ZN1SC1Ei(ptr {{.*}} %x28, i32 {{.*}} 16) +// CHECK-NEXT: %x29 = getelementptr inbounds nuw %struct.S, ptr %x28, i32 0, i32 0 +// CHECK-NEXT: %7 = load i32, ptr %x29, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %7) +// CHECK-NEXT: br label %expand.next30 +// CHECK: expand.next30: +// CHECK-NEXT: call void @_ZN1SC1Ei(ptr {{.*}} %x31, i32 {{.*}} 17) +// CHECK-NEXT: %x32 = getelementptr inbounds nuw %struct.S, ptr %x31, i32 0, i32 0 +// CHECK-NEXT: %8 = load i32, ptr %x32, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %8) +// CHECK-NEXT: br label %expand.next33 +// CHECK: expand.next33: +// CHECK-NEXT: call void @_ZN1SC1Ei(ptr {{.*}} %x34, i32 {{.*}} 18) +// CHECK-NEXT: %x35 = getelementptr inbounds nuw %struct.S, ptr %x34, i32 0, i32 0 +// CHECK-NEXT: %9 = load i32, ptr %x35, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %9) +// CHECK-NEXT: br label %expand.end36 +// CHECK: expand.end36: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x37, ptr align 4 @__const._Z2f5v.x, i64 4, i1 false) +// CHECK-NEXT: %call38 = call {{.*}} i32 @_Z2tgILi19EEiv() +// CHECK-NEXT: br label %expand.next39 +// CHECK: expand.next39: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x40, ptr align 4 @__const._Z2f5v.x.1, i64 4, i1 false) +// CHECK-NEXT: %call41 = call {{.*}} i32 @_Z2tgILi20EEiv() +// CHECK-NEXT: br label %expand.next42 +// CHECK: expand.next42: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x43, ptr align 4 @__const._Z2f5v.x.2, i64 4, i1 false) +// CHECK-NEXT: %call44 = call {{.*}} i32 @_Z2tgILi21EEiv() +// CHECK-NEXT: br label %expand.end45 +// CHECK: expand.end45: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2f6v() +// CHECK: entry: +// CHECK-NEXT: %ref.tmp = alloca %struct.s1, align 1 +// CHECK-NEXT: %ref.tmp1 = alloca %struct.s1.0, align 1 +// CHECK-NEXT: %ref.tmp2 = alloca %struct.s1.0, align 1 +// CHECK-NEXT: %ref.tmp3 = alloca %struct.s1, align 1 +// CHECK-NEXT: call void @_Z2t1IiEvv() +// CHECK-NEXT: call void @_Z2t1IlEvv() +// CHECK-NEXT: call void @_ZN2s1IlE2tfIlEEvv(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: call void @_ZN2s1IiE2tfIiEEvv(ptr {{.*}} %ref.tmp1) +// CHECK-NEXT: call void @_ZN2s1IiE2tfIlEEvv(ptr {{.*}} %ref.tmp2) +// CHECK-NEXT: call void @_ZN2s1IlE2tfIiEEvv(ptr {{.*}} %ref.tmp3) +// CHECK-NEXT: call void @_Z2t2I1SEvv() +// CHECK-NEXT: call void @_Z2t2IA1231_1SEvv() +// CHECK-NEXT: call void @_Z2t2IPPP1SEvv() +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2t1IiEvv() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x2 = alloca i32, align 4 +// CHECK-NEXT: %x4 = alloca i32, align 4 +// CHECK-NEXT: %x6 = alloca i32, align 4 +// CHECK-NEXT: %x8 = alloca i32, align 4 +// CHECK-NEXT: %x10 = alloca i32, align 4 +// CHECK-NEXT: %x12 = alloca i32, align 4 +// CHECK-NEXT: %x14 = alloca i32, align 4 +// CHECK-NEXT: %x16 = alloca i32, align 4 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %0) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 2, ptr %x1, align 4 +// CHECK-NEXT: %1 = load i32, ptr %x1, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %1) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store i32 3, ptr %x2, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x2, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %2) +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: store i32 4, ptr %x4, align 4 +// CHECK-NEXT: %3 = load i32, ptr %x4, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %3) +// CHECK-NEXT: br label %expand.end5 +// CHECK: expand.end5: +// CHECK-NEXT: store i32 5, ptr %x6, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x6, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %4) +// CHECK-NEXT: br label %expand.next7 +// CHECK: expand.next7: +// CHECK-NEXT: store i32 6, ptr %x8, align 4 +// CHECK-NEXT: %5 = load i32, ptr %x8, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %5) +// CHECK-NEXT: br label %expand.end9 +// CHECK: expand.end9: +// CHECK-NEXT: store i32 7, ptr %x10, align 4 +// CHECK-NEXT: br label %expand.next11 +// CHECK: expand.next11: +// CHECK-NEXT: store i32 8, ptr %x12, align 4 +// CHECK-NEXT: br label %expand.end13 +// CHECK: expand.end13: +// CHECK-NEXT: store i32 9, ptr %x14, align 4 +// CHECK-NEXT: br label %expand.next15 +// CHECK: expand.next15: +// CHECK-NEXT: store i32 10, ptr %x16, align 4 +// CHECK-NEXT: br label %expand.end17 +// CHECK: expand.end17: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2t1IlEvv() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i64, align 8 +// CHECK-NEXT: %x1 = alloca i64, align 8 +// CHECK-NEXT: %x2 = alloca i64, align 8 +// CHECK-NEXT: %x4 = alloca i64, align 8 +// CHECK-NEXT: %x6 = alloca i64, align 8 +// CHECK-NEXT: %x8 = alloca i64, align 8 +// CHECK-NEXT: %x10 = alloca i64, align 8 +// CHECK-NEXT: %x12 = alloca i64, align 8 +// CHECK-NEXT: %x14 = alloca i64, align 8 +// CHECK-NEXT: %x16 = alloca i64, align 8 +// CHECK-NEXT: store i64 1, ptr %x, align 8 +// CHECK-NEXT: %0 = load i64, ptr %x, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %0) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i64 2, ptr %x1, align 8 +// CHECK-NEXT: %1 = load i64, ptr %x1, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %1) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store i64 3, ptr %x2, align 8 +// CHECK-NEXT: %2 = load i64, ptr %x2, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %2) +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: store i64 4, ptr %x4, align 8 +// CHECK-NEXT: %3 = load i64, ptr %x4, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %3) +// CHECK-NEXT: br label %expand.end5 +// CHECK: expand.end5: +// CHECK-NEXT: store i64 5, ptr %x6, align 8 +// CHECK-NEXT: %4 = load i64, ptr %x6, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %4) +// CHECK-NEXT: br label %expand.next7 +// CHECK: expand.next7: +// CHECK-NEXT: store i64 6, ptr %x8, align 8 +// CHECK-NEXT: %5 = load i64, ptr %x8, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %5) +// CHECK-NEXT: br label %expand.end9 +// CHECK: expand.end9: +// CHECK-NEXT: store i64 7, ptr %x10, align 8 +// CHECK-NEXT: br label %expand.next11 +// CHECK: expand.next11: +// CHECK-NEXT: store i64 8, ptr %x12, align 8 +// CHECK-NEXT: br label %expand.end13 +// CHECK: expand.end13: +// CHECK-NEXT: store i64 9, ptr %x14, align 8 +// CHECK-NEXT: br label %expand.next15 +// CHECK: expand.next15: +// CHECK-NEXT: store i64 10, ptr %x16, align 8 +// CHECK-NEXT: br label %expand.end17 +// CHECK: expand.end17: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_ZN2s1IlE2tfIlEEvv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i64, align 8 +// CHECK-NEXT: %x2 = alloca i64, align 8 +// CHECK-NEXT: %x3 = alloca i64, align 8 +// CHECK-NEXT: %x5 = alloca i64, align 8 +// CHECK-NEXT: %x7 = alloca i64, align 8 +// CHECK-NEXT: %x9 = alloca i64, align 8 +// CHECK-NEXT: %x11 = alloca i64, align 8 +// CHECK-NEXT: %x13 = alloca i64, align 8 +// CHECK-NEXT: %x15 = alloca i64, align 8 +// CHECK-NEXT: %x17 = alloca i64, align 8 +// CHECK-NEXT: %x19 = alloca i64, align 8 +// CHECK-NEXT: %x21 = alloca i64, align 8 +// CHECK-NEXT: %x23 = alloca i64, align 8 +// CHECK-NEXT: %x25 = alloca i64, align 8 +// CHECK-NEXT: %x27 = alloca i64, align 8 +// CHECK-NEXT: %x29 = alloca i64, align 8 +// CHECK-NEXT: %x31 = alloca i64, align 8 +// CHECK-NEXT: %x33 = alloca i64, align 8 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: store i64 1, ptr %x, align 8 +// CHECK-NEXT: %0 = load i64, ptr %x, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %0) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i64 2, ptr %x2, align 8 +// CHECK-NEXT: %1 = load i64, ptr %x2, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %1) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store i64 3, ptr %x3, align 8 +// CHECK-NEXT: %2 = load i64, ptr %x3, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %2) +// CHECK-NEXT: br label %expand.next4 +// CHECK: expand.next4: +// CHECK-NEXT: store i64 4, ptr %x5, align 8 +// CHECK-NEXT: %3 = load i64, ptr %x5, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %3) +// CHECK-NEXT: br label %expand.end6 +// CHECK: expand.end6: +// CHECK-NEXT: store i64 5, ptr %x7, align 8 +// CHECK-NEXT: %4 = load i64, ptr %x7, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %4) +// CHECK-NEXT: br label %expand.next8 +// CHECK: expand.next8: +// CHECK-NEXT: store i64 6, ptr %x9, align 8 +// CHECK-NEXT: %5 = load i64, ptr %x9, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %5) +// CHECK-NEXT: br label %expand.end10 +// CHECK: expand.end10: +// CHECK-NEXT: store i64 7, ptr %x11, align 8 +// CHECK-NEXT: %6 = load i64, ptr %x11, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %6) +// CHECK-NEXT: br label %expand.next12 +// CHECK: expand.next12: +// CHECK-NEXT: store i64 8, ptr %x13, align 8 +// CHECK-NEXT: %7 = load i64, ptr %x13, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %7) +// CHECK-NEXT: br label %expand.end14 +// CHECK: expand.end14: +// CHECK-NEXT: store i64 9, ptr %x15, align 8 +// CHECK-NEXT: %8 = load i64, ptr %x15, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %8) +// CHECK-NEXT: br label %expand.next16 +// CHECK: expand.next16: +// CHECK-NEXT: store i64 10, ptr %x17, align 8 +// CHECK-NEXT: %9 = load i64, ptr %x17, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %9) +// CHECK-NEXT: br label %expand.end18 +// CHECK: expand.end18: +// CHECK-NEXT: store i64 11, ptr %x19, align 8 +// CHECK-NEXT: %10 = load i64, ptr %x19, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %10) +// CHECK-NEXT: br label %expand.next20 +// CHECK: expand.next20: +// CHECK-NEXT: store i64 12, ptr %x21, align 8 +// CHECK-NEXT: %11 = load i64, ptr %x21, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %11) +// CHECK-NEXT: br label %expand.end22 +// CHECK: expand.end22: +// CHECK-NEXT: store i64 13, ptr %x23, align 8 +// CHECK-NEXT: br label %expand.next24 +// CHECK: expand.next24: +// CHECK-NEXT: store i64 14, ptr %x25, align 8 +// CHECK-NEXT: br label %expand.end26 +// CHECK: expand.end26: +// CHECK-NEXT: store i64 15, ptr %x27, align 8 +// CHECK-NEXT: br label %expand.next28 +// CHECK: expand.next28: +// CHECK-NEXT: store i64 16, ptr %x29, align 8 +// CHECK-NEXT: br label %expand.end30 +// CHECK: expand.end30: +// CHECK-NEXT: store i64 17, ptr %x31, align 8 +// CHECK-NEXT: br label %expand.next32 +// CHECK: expand.next32: +// CHECK-NEXT: store i64 18, ptr %x33, align 8 +// CHECK-NEXT: br label %expand.end34 +// CHECK: expand.end34: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_ZN2s1IiE2tfIiEEvv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x2 = alloca i32, align 4 +// CHECK-NEXT: %x3 = alloca i32, align 4 +// CHECK-NEXT: %x5 = alloca i32, align 4 +// CHECK-NEXT: %x7 = alloca i32, align 4 +// CHECK-NEXT: %x9 = alloca i32, align 4 +// CHECK-NEXT: %x11 = alloca i32, align 4 +// CHECK-NEXT: %x13 = alloca i32, align 4 +// CHECK-NEXT: %x15 = alloca i32, align 4 +// CHECK-NEXT: %x17 = alloca i32, align 4 +// CHECK-NEXT: %x19 = alloca i32, align 4 +// CHECK-NEXT: %x21 = alloca i32, align 4 +// CHECK-NEXT: %x23 = alloca i32, align 4 +// CHECK-NEXT: %x25 = alloca i32, align 4 +// CHECK-NEXT: %x27 = alloca i32, align 4 +// CHECK-NEXT: %x29 = alloca i32, align 4 +// CHECK-NEXT: %x31 = alloca i32, align 4 +// CHECK-NEXT: %x33 = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %0) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 2, ptr %x2, align 4 +// CHECK-NEXT: %1 = load i32, ptr %x2, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %1) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store i32 3, ptr %x3, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x3, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %2) +// CHECK-NEXT: br label %expand.next4 +// CHECK: expand.next4: +// CHECK-NEXT: store i32 4, ptr %x5, align 4 +// CHECK-NEXT: %3 = load i32, ptr %x5, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %3) +// CHECK-NEXT: br label %expand.end6 +// CHECK: expand.end6: +// CHECK-NEXT: store i32 5, ptr %x7, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x7, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %4) +// CHECK-NEXT: br label %expand.next8 +// CHECK: expand.next8: +// CHECK-NEXT: store i32 6, ptr %x9, align 4 +// CHECK-NEXT: %5 = load i32, ptr %x9, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %5) +// CHECK-NEXT: br label %expand.end10 +// CHECK: expand.end10: +// CHECK-NEXT: store i32 7, ptr %x11, align 4 +// CHECK-NEXT: %6 = load i32, ptr %x11, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %6) +// CHECK-NEXT: br label %expand.next12 +// CHECK: expand.next12: +// CHECK-NEXT: store i32 8, ptr %x13, align 4 +// CHECK-NEXT: %7 = load i32, ptr %x13, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %7) +// CHECK-NEXT: br label %expand.end14 +// CHECK: expand.end14: +// CHECK-NEXT: store i32 9, ptr %x15, align 4 +// CHECK-NEXT: %8 = load i32, ptr %x15, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %8) +// CHECK-NEXT: br label %expand.next16 +// CHECK: expand.next16: +// CHECK-NEXT: store i32 10, ptr %x17, align 4 +// CHECK-NEXT: %9 = load i32, ptr %x17, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %9) +// CHECK-NEXT: br label %expand.end18 +// CHECK: expand.end18: +// CHECK-NEXT: store i32 11, ptr %x19, align 4 +// CHECK-NEXT: %10 = load i32, ptr %x19, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %10) +// CHECK-NEXT: br label %expand.next20 +// CHECK: expand.next20: +// CHECK-NEXT: store i32 12, ptr %x21, align 4 +// CHECK-NEXT: %11 = load i32, ptr %x21, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %11) +// CHECK-NEXT: br label %expand.end22 +// CHECK: expand.end22: +// CHECK-NEXT: store i32 13, ptr %x23, align 4 +// CHECK-NEXT: br label %expand.next24 +// CHECK: expand.next24: +// CHECK-NEXT: store i32 14, ptr %x25, align 4 +// CHECK-NEXT: br label %expand.end26 +// CHECK: expand.end26: +// CHECK-NEXT: store i32 15, ptr %x27, align 4 +// CHECK-NEXT: br label %expand.next28 +// CHECK: expand.next28: +// CHECK-NEXT: store i32 16, ptr %x29, align 4 +// CHECK-NEXT: br label %expand.end30 +// CHECK: expand.end30: +// CHECK-NEXT: store i32 17, ptr %x31, align 4 +// CHECK-NEXT: br label %expand.next32 +// CHECK: expand.next32: +// CHECK-NEXT: store i32 18, ptr %x33, align 4 +// CHECK-NEXT: br label %expand.end34 +// CHECK: expand.end34: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_ZN2s1IiE2tfIlEEvv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i64, align 8 +// CHECK-NEXT: %x2 = alloca i64, align 8 +// CHECK-NEXT: %x3 = alloca i32, align 4 +// CHECK-NEXT: %x5 = alloca i32, align 4 +// CHECK-NEXT: %x7 = alloca i32, align 4 +// CHECK-NEXT: %x9 = alloca i32, align 4 +// CHECK-NEXT: %x11 = alloca i64, align 8 +// CHECK-NEXT: %x13 = alloca i64, align 8 +// CHECK-NEXT: %x15 = alloca i64, align 8 +// CHECK-NEXT: %x17 = alloca i64, align 8 +// CHECK-NEXT: %x19 = alloca i32, align 4 +// CHECK-NEXT: %x21 = alloca i64, align 8 +// CHECK-NEXT: %x23 = alloca i32, align 4 +// CHECK-NEXT: %x25 = alloca i32, align 4 +// CHECK-NEXT: %x27 = alloca i64, align 8 +// CHECK-NEXT: %x29 = alloca i64, align 8 +// CHECK-NEXT: %x31 = alloca i64, align 8 +// CHECK-NEXT: %x33 = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: store i64 1, ptr %x, align 8 +// CHECK-NEXT: %0 = load i64, ptr %x, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %0) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i64 2, ptr %x2, align 8 +// CHECK-NEXT: %1 = load i64, ptr %x2, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %1) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store i32 3, ptr %x3, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x3, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %2) +// CHECK-NEXT: br label %expand.next4 +// CHECK: expand.next4: +// CHECK-NEXT: store i32 4, ptr %x5, align 4 +// CHECK-NEXT: %3 = load i32, ptr %x5, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %3) +// CHECK-NEXT: br label %expand.end6 +// CHECK: expand.end6: +// CHECK-NEXT: store i32 5, ptr %x7, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x7, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %4) +// CHECK-NEXT: br label %expand.next8 +// CHECK: expand.next8: +// CHECK-NEXT: store i32 6, ptr %x9, align 4 +// CHECK-NEXT: %5 = load i32, ptr %x9, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %5) +// CHECK-NEXT: br label %expand.end10 +// CHECK: expand.end10: +// CHECK-NEXT: store i64 7, ptr %x11, align 8 +// CHECK-NEXT: %6 = load i64, ptr %x11, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %6) +// CHECK-NEXT: br label %expand.next12 +// CHECK: expand.next12: +// CHECK-NEXT: store i64 8, ptr %x13, align 8 +// CHECK-NEXT: %7 = load i64, ptr %x13, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %7) +// CHECK-NEXT: br label %expand.end14 +// CHECK: expand.end14: +// CHECK-NEXT: store i64 9, ptr %x15, align 8 +// CHECK-NEXT: %8 = load i64, ptr %x15, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %8) +// CHECK-NEXT: br label %expand.next16 +// CHECK: expand.next16: +// CHECK-NEXT: store i64 10, ptr %x17, align 8 +// CHECK-NEXT: %9 = load i64, ptr %x17, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %9) +// CHECK-NEXT: br label %expand.end18 +// CHECK: expand.end18: +// CHECK-NEXT: store i32 11, ptr %x19, align 4 +// CHECK-NEXT: %10 = load i32, ptr %x19, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %10) +// CHECK-NEXT: br label %expand.next20 +// CHECK: expand.next20: +// CHECK-NEXT: store i64 12, ptr %x21, align 8 +// CHECK-NEXT: %11 = load i64, ptr %x21, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %11) +// CHECK-NEXT: br label %expand.end22 +// CHECK: expand.end22: +// CHECK-NEXT: store i32 13, ptr %x23, align 4 +// CHECK-NEXT: br label %expand.next24 +// CHECK: expand.next24: +// CHECK-NEXT: store i32 14, ptr %x25, align 4 +// CHECK-NEXT: br label %expand.end26 +// CHECK: expand.end26: +// CHECK-NEXT: store i64 15, ptr %x27, align 8 +// CHECK-NEXT: br label %expand.next28 +// CHECK: expand.next28: +// CHECK-NEXT: store i64 16, ptr %x29, align 8 +// CHECK-NEXT: br label %expand.end30 +// CHECK: expand.end30: +// CHECK-NEXT: store i64 17, ptr %x31, align 8 +// CHECK-NEXT: br label %expand.next32 +// CHECK: expand.next32: +// CHECK-NEXT: store i32 18, ptr %x33, align 4 +// CHECK-NEXT: br label %expand.end34 +// CHECK: expand.end34: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_ZN2s1IlE2tfIiEEvv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x2 = alloca i32, align 4 +// CHECK-NEXT: %x3 = alloca i64, align 8 +// CHECK-NEXT: %x5 = alloca i64, align 8 +// CHECK-NEXT: %x7 = alloca i64, align 8 +// CHECK-NEXT: %x9 = alloca i64, align 8 +// CHECK-NEXT: %x11 = alloca i32, align 4 +// CHECK-NEXT: %x13 = alloca i32, align 4 +// CHECK-NEXT: %x15 = alloca i32, align 4 +// CHECK-NEXT: %x17 = alloca i32, align 4 +// CHECK-NEXT: %x19 = alloca i64, align 8 +// CHECK-NEXT: %x21 = alloca i32, align 4 +// CHECK-NEXT: %x23 = alloca i64, align 8 +// CHECK-NEXT: %x25 = alloca i64, align 8 +// CHECK-NEXT: %x27 = alloca i32, align 4 +// CHECK-NEXT: %x29 = alloca i32, align 4 +// CHECK-NEXT: %x31 = alloca i32, align 4 +// CHECK-NEXT: %x33 = alloca i64, align 8 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %0) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 2, ptr %x2, align 4 +// CHECK-NEXT: %1 = load i32, ptr %x2, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %1) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store i64 3, ptr %x3, align 8 +// CHECK-NEXT: %2 = load i64, ptr %x3, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %2) +// CHECK-NEXT: br label %expand.next4 +// CHECK: expand.next4: +// CHECK-NEXT: store i64 4, ptr %x5, align 8 +// CHECK-NEXT: %3 = load i64, ptr %x5, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %3) +// CHECK-NEXT: br label %expand.end6 +// CHECK: expand.end6: +// CHECK-NEXT: store i64 5, ptr %x7, align 8 +// CHECK-NEXT: %4 = load i64, ptr %x7, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %4) +// CHECK-NEXT: br label %expand.next8 +// CHECK: expand.next8: +// CHECK-NEXT: store i64 6, ptr %x9, align 8 +// CHECK-NEXT: %5 = load i64, ptr %x9, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %5) +// CHECK-NEXT: br label %expand.end10 +// CHECK: expand.end10: +// CHECK-NEXT: store i32 7, ptr %x11, align 4 +// CHECK-NEXT: %6 = load i32, ptr %x11, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %6) +// CHECK-NEXT: br label %expand.next12 +// CHECK: expand.next12: +// CHECK-NEXT: store i32 8, ptr %x13, align 4 +// CHECK-NEXT: %7 = load i32, ptr %x13, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %7) +// CHECK-NEXT: br label %expand.end14 +// CHECK: expand.end14: +// CHECK-NEXT: store i32 9, ptr %x15, align 4 +// CHECK-NEXT: %8 = load i32, ptr %x15, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %8) +// CHECK-NEXT: br label %expand.next16 +// CHECK: expand.next16: +// CHECK-NEXT: store i32 10, ptr %x17, align 4 +// CHECK-NEXT: %9 = load i32, ptr %x17, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %9) +// CHECK-NEXT: br label %expand.end18 +// CHECK: expand.end18: +// CHECK-NEXT: store i64 11, ptr %x19, align 8 +// CHECK-NEXT: %10 = load i64, ptr %x19, align 8 +// CHECK-NEXT: call void @_Z1gl(i64 {{.*}} %10) +// CHECK-NEXT: br label %expand.next20 +// CHECK: expand.next20: +// CHECK-NEXT: store i32 12, ptr %x21, align 4 +// CHECK-NEXT: %11 = load i32, ptr %x21, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %11) +// CHECK-NEXT: br label %expand.end22 +// CHECK: expand.end22: +// CHECK-NEXT: store i64 13, ptr %x23, align 8 +// CHECK-NEXT: br label %expand.next24 +// CHECK: expand.next24: +// CHECK-NEXT: store i64 14, ptr %x25, align 8 +// CHECK-NEXT: br label %expand.end26 +// CHECK: expand.end26: +// CHECK-NEXT: store i32 15, ptr %x27, align 4 +// CHECK-NEXT: br label %expand.next28 +// CHECK: expand.next28: +// CHECK-NEXT: store i32 16, ptr %x29, align 4 +// CHECK-NEXT: br label %expand.end30 +// CHECK: expand.end30: +// CHECK-NEXT: store i32 17, ptr %x31, align 4 +// CHECK-NEXT: br label %expand.next32 +// CHECK: expand.next32: +// CHECK-NEXT: store i64 18, ptr %x33, align 8 +// CHECK-NEXT: br label %expand.end34 +// CHECK: expand.end34: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2f7v() +// CHECK: entry: +// CHECK-NEXT: %ref.tmp = alloca %struct.s2, align 1 +// CHECK-NEXT: call void @_Z2t3IJiiiEEvDpT_(i32 {{.*}} 42, i32 {{.*}} 43, i32 {{.*}} 44) +// CHECK-NEXT: call void @_Z2t4IJLi42ELi43ELi44EEEvv() +// CHECK-NEXT: call void @_ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: ret void + +// CHECK-LABEL: define {{.*}} void @_Z2t3IJiiiEEvDpT_(i32 {{.*}} %ts, i32 {{.*}} %ts1, i32 {{.*}} %ts3) +// CHECK: entry: +// CHECK-NEXT: %ts.addr = alloca i32, align 4 +// CHECK-NEXT: %ts.addr2 = alloca i32, align 4 +// CHECK-NEXT: %ts.addr4 = alloca i32, align 4 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x5 = alloca i32, align 4 +// CHECK-NEXT: %x7 = alloca i32, align 4 +// CHECK-NEXT: %x8 = alloca i32, align 4 +// CHECK-NEXT: %x10 = alloca i32, align 4 +// CHECK-NEXT: %x12 = alloca i32, align 4 +// CHECK-NEXT: %x14 = alloca i32, align 4 +// CHECK-NEXT: %x16 = alloca i32, align 4 +// CHECK-NEXT: %x18 = alloca i32, align 4 +// CHECK-NEXT: %x20 = alloca i32, align 4 +// CHECK-NEXT: %x22 = alloca i32, align 4 +// CHECK-NEXT: %x24 = alloca i32, align 4 +// CHECK-NEXT: %x26 = alloca i32, align 4 +// CHECK-NEXT: %x28 = alloca i32, align 4 +// CHECK-NEXT: %x30 = alloca i32, align 4 +// CHECK-NEXT: %x32 = alloca i32, align 4 +// CHECK-NEXT: %x34 = alloca i32, align 4 +// CHECK-NEXT: %x36 = alloca i32, align 4 +// CHECK-NEXT: %x38 = alloca i32, align 4 +// CHECK-NEXT: %x40 = alloca i32, align 4 +// CHECK-NEXT: %x42 = alloca %struct.X, align 4 +// CHECK-NEXT: %x45 = alloca %struct.X, align 4 +// CHECK-NEXT: %x51 = alloca %struct.X, align 4 +// CHECK-NEXT: %x54 = alloca %struct.X, align 4 +// CHECK-NEXT: store i32 %ts, ptr %ts.addr, align 4 +// CHECK-NEXT: store i32 %ts1, ptr %ts.addr2, align 4 +// CHECK-NEXT: store i32 %ts3, ptr %ts.addr4, align 4 +// CHECK-NEXT: %0 = load i32, ptr %ts.addr, align 4 +// CHECK-NEXT: store i32 %0, ptr %x, align 4 +// CHECK-NEXT: %1 = load i32, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %1) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: %2 = load i32, ptr %ts.addr2, align 4 +// CHECK-NEXT: store i32 %2, ptr %x5, align 4 +// CHECK-NEXT: %3 = load i32, ptr %x5, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %3) +// CHECK-NEXT: br label %expand.next6 +// CHECK: expand.next6: +// CHECK-NEXT: %4 = load i32, ptr %ts.addr4, align 4 +// CHECK-NEXT: store i32 %4, ptr %x7, align 4 +// CHECK-NEXT: %5 = load i32, ptr %x7, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %5) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store i32 1, ptr %x8, align 4 +// CHECK-NEXT: %6 = load i32, ptr %x8, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %6) +// CHECK-NEXT: br label %expand.next9 +// CHECK: expand.next9: +// CHECK-NEXT: %7 = load i32, ptr %ts.addr, align 4 +// CHECK-NEXT: store i32 %7, ptr %x10, align 4 +// CHECK-NEXT: %8 = load i32, ptr %x10, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %8) +// CHECK-NEXT: br label %expand.next11 +// CHECK: expand.next11: +// CHECK-NEXT: %9 = load i32, ptr %ts.addr2, align 4 +// CHECK-NEXT: store i32 %9, ptr %x12, align 4 +// CHECK-NEXT: %10 = load i32, ptr %x12, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %10) +// CHECK-NEXT: br label %expand.next13 +// CHECK: expand.next13: +// CHECK-NEXT: %11 = load i32, ptr %ts.addr4, align 4 +// CHECK-NEXT: store i32 %11, ptr %x14, align 4 +// CHECK-NEXT: %12 = load i32, ptr %x14, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %12) +// CHECK-NEXT: br label %expand.next15 +// CHECK: expand.next15: +// CHECK-NEXT: store i32 2, ptr %x16, align 4 +// CHECK-NEXT: %13 = load i32, ptr %x16, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %13) +// CHECK-NEXT: br label %expand.next17 +// CHECK: expand.next17: +// CHECK-NEXT: %14 = load i32, ptr %ts.addr, align 4 +// CHECK-NEXT: store i32 %14, ptr %x18, align 4 +// CHECK-NEXT: %15 = load i32, ptr %x18, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %15) +// CHECK-NEXT: br label %expand.next19 +// CHECK: expand.next19: +// CHECK-NEXT: %16 = load i32, ptr %ts.addr2, align 4 +// CHECK-NEXT: store i32 %16, ptr %x20, align 4 +// CHECK-NEXT: %17 = load i32, ptr %x20, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %17) +// CHECK-NEXT: br label %expand.next21 +// CHECK: expand.next21: +// CHECK-NEXT: %18 = load i32, ptr %ts.addr4, align 4 +// CHECK-NEXT: store i32 %18, ptr %x22, align 4 +// CHECK-NEXT: %19 = load i32, ptr %x22, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %19) +// CHECK-NEXT: br label %expand.next23 +// CHECK: expand.next23: +// CHECK-NEXT: store i32 3, ptr %x24, align 4 +// CHECK-NEXT: %20 = load i32, ptr %x24, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %20) +// CHECK-NEXT: br label %expand.end25 +// CHECK: expand.end25: +// CHECK-NEXT: store i32 4, ptr %x26, align 4 +// CHECK-NEXT: %21 = load i32, ptr %x26, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %21) +// CHECK-NEXT: br label %expand.next27 +// CHECK: expand.next27: +// CHECK-NEXT: %22 = load i32, ptr %ts.addr, align 4 +// CHECK-NEXT: store i32 %22, ptr %x28, align 4 +// CHECK-NEXT: %23 = load i32, ptr %x28, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %23) +// CHECK-NEXT: br label %expand.next29 +// CHECK: expand.next29: +// CHECK-NEXT: %24 = load i32, ptr %ts.addr2, align 4 +// CHECK-NEXT: store i32 %24, ptr %x30, align 4 +// CHECK-NEXT: %25 = load i32, ptr %x30, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %25) +// CHECK-NEXT: br label %expand.next31 +// CHECK: expand.next31: +// CHECK-NEXT: %26 = load i32, ptr %ts.addr4, align 4 +// CHECK-NEXT: store i32 %26, ptr %x32, align 4 +// CHECK-NEXT: %27 = load i32, ptr %x32, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %27) +// CHECK-NEXT: br label %expand.next33 +// CHECK: expand.next33: +// CHECK-NEXT: %28 = load i32, ptr %ts.addr, align 4 +// CHECK-NEXT: store i32 %28, ptr %x34, align 4 +// CHECK-NEXT: %29 = load i32, ptr %x34, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %29) +// CHECK-NEXT: br label %expand.next35 +// CHECK: expand.next35: +// CHECK-NEXT: %30 = load i32, ptr %ts.addr2, align 4 +// CHECK-NEXT: store i32 %30, ptr %x36, align 4 +// CHECK-NEXT: %31 = load i32, ptr %x36, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %31) +// CHECK-NEXT: br label %expand.next37 +// CHECK: expand.next37: +// CHECK-NEXT: %32 = load i32, ptr %ts.addr4, align 4 +// CHECK-NEXT: store i32 %32, ptr %x38, align 4 +// CHECK-NEXT: %33 = load i32, ptr %x38, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %33) +// CHECK-NEXT: br label %expand.next39 +// CHECK: expand.next39: +// CHECK-NEXT: store i32 5, ptr %x40, align 4 +// CHECK-NEXT: %34 = load i32, ptr %x40, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %34) +// CHECK-NEXT: br label %expand.end41 +// CHECK: expand.end41: +// CHECK-NEXT: %a = getelementptr inbounds nuw %struct.X, ptr %x42, i32 0, i32 0 +// CHECK-NEXT: %35 = load i32, ptr %ts.addr, align 4 +// CHECK-NEXT: store i32 %35, ptr %a, align 4 +// CHECK-NEXT: %b = getelementptr inbounds nuw %struct.X, ptr %x42, i32 0, i32 1 +// CHECK-NEXT: %36 = load i32, ptr %ts.addr2, align 4 +// CHECK-NEXT: store i32 %36, ptr %b, align 4 +// CHECK-NEXT: %c = getelementptr inbounds nuw %struct.X, ptr %x42, i32 0, i32 2 +// CHECK-NEXT: %37 = load i32, ptr %ts.addr4, align 4 +// CHECK-NEXT: store i32 %37, ptr %c, align 4 +// CHECK-NEXT: %a43 = getelementptr inbounds nuw %struct.X, ptr %x42, i32 0, i32 0 +// CHECK-NEXT: %38 = load i32, ptr %a43, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %38) +// CHECK-NEXT: br label %expand.next44 +// CHECK: expand.next44: +// CHECK-NEXT: %a46 = getelementptr inbounds nuw %struct.X, ptr %x45, i32 0, i32 0 +// CHECK-NEXT: %39 = load i32, ptr %ts.addr, align 4 +// CHECK-NEXT: store i32 %39, ptr %a46, align 4 +// CHECK-NEXT: %b47 = getelementptr inbounds nuw %struct.X, ptr %x45, i32 0, i32 1 +// CHECK-NEXT: %40 = load i32, ptr %ts.addr2, align 4 +// CHECK-NEXT: store i32 %40, ptr %b47, align 4 +// CHECK-NEXT: %c48 = getelementptr inbounds nuw %struct.X, ptr %x45, i32 0, i32 2 +// CHECK-NEXT: %41 = load i32, ptr %ts.addr4, align 4 +// CHECK-NEXT: store i32 %41, ptr %c48, align 4 +// CHECK-NEXT: %a49 = getelementptr inbounds nuw %struct.X, ptr %x45, i32 0, i32 0 +// CHECK-NEXT: %42 = load i32, ptr %a49, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %42) +// CHECK-NEXT: br label %expand.next50 +// CHECK: expand.next50: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x51, ptr align 4 @__const._Z2t3IJiiiEEvDpT_.x, i64 12, i1 false) +// CHECK-NEXT: %a52 = getelementptr inbounds nuw %struct.X, ptr %x51, i32 0, i32 0 +// CHECK-NEXT: %43 = load i32, ptr %a52, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %43) +// CHECK-NEXT: br label %expand.end53 +// CHECK: expand.end53: +// CHECK-NEXT: %a55 = getelementptr inbounds nuw %struct.X, ptr %x54, i32 0, i32 0 +// CHECK-NEXT: %44 = load i32, ptr %ts.addr, align 4 +// CHECK-NEXT: store i32 %44, ptr %a55, align 4 +// CHECK-NEXT: %b56 = getelementptr inbounds nuw %struct.X, ptr %x54, i32 0, i32 1 +// CHECK-NEXT: %45 = load i32, ptr %ts.addr2, align 4 +// CHECK-NEXT: store i32 %45, ptr %b56, align 4 +// CHECK-NEXT: %c57 = getelementptr inbounds nuw %struct.X, ptr %x54, i32 0, i32 2 +// CHECK-NEXT: %46 = load i32, ptr %ts.addr4, align 4 +// CHECK-NEXT: store i32 %46, ptr %c57, align 4 +// CHECK-NEXT: %a58 = getelementptr inbounds nuw %struct.X, ptr %x54, i32 0, i32 0 +// CHECK-NEXT: %47 = load i32, ptr %a58, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %47) +// CHECK-NEXT: br label %expand.end59 +// CHECK: expand.end59: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2t4IJLi42ELi43ELi44EEEvv() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x4 = alloca i32, align 4 +// CHECK-NEXT: %x6 = alloca i32, align 4 +// CHECK-NEXT: %x9 = alloca i32, align 4 +// CHECK-NEXT: %x12 = alloca i32, align 4 +// CHECK-NEXT: %x15 = alloca i32, align 4 +// CHECK-NEXT: %x18 = alloca i32, align 4 +// CHECK-NEXT: %x21 = alloca i32, align 4 +// CHECK-NEXT: %x24 = alloca i32, align 4 +// CHECK-NEXT: %x27 = alloca i32, align 4 +// CHECK-NEXT: %x30 = alloca i32, align 4 +// CHECK-NEXT: %x33 = alloca i32, align 4 +// CHECK-NEXT: %x36 = alloca i32, align 4 +// CHECK-NEXT: %x39 = alloca i32, align 4 +// CHECK-NEXT: %x42 = alloca i32, align 4 +// CHECK-NEXT: %x45 = alloca i32, align 4 +// CHECK-NEXT: %x48 = alloca i32, align 4 +// CHECK-NEXT: %x51 = alloca i32, align 4 +// CHECK-NEXT: %x54 = alloca i32, align 4 +// CHECK-NEXT: %x57 = alloca %struct.X, align 4 +// CHECK-NEXT: %x60 = alloca %struct.X, align 4 +// CHECK-NEXT: %x63 = alloca %struct.X, align 4 +// CHECK-NEXT: %x66 = alloca %struct.X, align 4 +// CHECK-NEXT: store i32 42, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 42) +// CHECK-NEXT: %call = call {{.*}} i32 @_Z2tgILi42EEiv() +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 43, ptr %x1, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 43) +// CHECK-NEXT: %call2 = call {{.*}} i32 @_Z2tgILi43EEiv() +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: store i32 44, ptr %x4, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 44) +// CHECK-NEXT: %call5 = call {{.*}} i32 @_Z2tgILi44EEiv() +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store i32 1, ptr %x6, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 1) +// CHECK-NEXT: %call7 = call {{.*}} i32 @_Z2tgILi1EEiv() +// CHECK-NEXT: br label %expand.next8 +// CHECK: expand.next8: +// CHECK-NEXT: store i32 42, ptr %x9, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 42) +// CHECK-NEXT: %call10 = call {{.*}} i32 @_Z2tgILi42EEiv() +// CHECK-NEXT: br label %expand.next11 +// CHECK: expand.next11: +// CHECK-NEXT: store i32 43, ptr %x12, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 43) +// CHECK-NEXT: %call13 = call {{.*}} i32 @_Z2tgILi43EEiv() +// CHECK-NEXT: br label %expand.next14 +// CHECK: expand.next14: +// CHECK-NEXT: store i32 44, ptr %x15, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 44) +// CHECK-NEXT: %call16 = call {{.*}} i32 @_Z2tgILi44EEiv() +// CHECK-NEXT: br label %expand.next17 +// CHECK: expand.next17: +// CHECK-NEXT: store i32 2, ptr %x18, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 2) +// CHECK-NEXT: %call19 = call {{.*}} i32 @_Z2tgILi2EEiv() +// CHECK-NEXT: br label %expand.next20 +// CHECK: expand.next20: +// CHECK-NEXT: store i32 42, ptr %x21, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 42) +// CHECK-NEXT: %call22 = call {{.*}} i32 @_Z2tgILi42EEiv() +// CHECK-NEXT: br label %expand.next23 +// CHECK: expand.next23: +// CHECK-NEXT: store i32 43, ptr %x24, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 43) +// CHECK-NEXT: %call25 = call {{.*}} i32 @_Z2tgILi43EEiv() +// CHECK-NEXT: br label %expand.next26 +// CHECK: expand.next26: +// CHECK-NEXT: store i32 44, ptr %x27, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 44) +// CHECK-NEXT: %call28 = call {{.*}} i32 @_Z2tgILi44EEiv() +// CHECK-NEXT: br label %expand.next29 +// CHECK: expand.next29: +// CHECK-NEXT: store i32 3, ptr %x30, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 3) +// CHECK-NEXT: %call31 = call {{.*}} i32 @_Z2tgILi3EEiv() +// CHECK-NEXT: br label %expand.end32 +// CHECK: expand.end32: +// CHECK-NEXT: store i32 4, ptr %x33, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 4) +// CHECK-NEXT: %call34 = call {{.*}} i32 @_Z2tgILi4EEiv() +// CHECK-NEXT: br label %expand.next35 +// CHECK: expand.next35: +// CHECK-NEXT: store i32 42, ptr %x36, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 42) +// CHECK-NEXT: %call37 = call {{.*}} i32 @_Z2tgILi42EEiv() +// CHECK-NEXT: br label %expand.next38 +// CHECK: expand.next38: +// CHECK-NEXT: store i32 43, ptr %x39, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 43) +// CHECK-NEXT: %call40 = call {{.*}} i32 @_Z2tgILi43EEiv() +// CHECK-NEXT: br label %expand.next41 +// CHECK: expand.next41: +// CHECK-NEXT: store i32 44, ptr %x42, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 44) +// CHECK-NEXT: %call43 = call {{.*}} i32 @_Z2tgILi44EEiv() +// CHECK-NEXT: br label %expand.next44 +// CHECK: expand.next44: +// CHECK-NEXT: store i32 42, ptr %x45, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 42) +// CHECK-NEXT: %call46 = call {{.*}} i32 @_Z2tgILi42EEiv() +// CHECK-NEXT: br label %expand.next47 +// CHECK: expand.next47: +// CHECK-NEXT: store i32 43, ptr %x48, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 43) +// CHECK-NEXT: %call49 = call {{.*}} i32 @_Z2tgILi43EEiv() +// CHECK-NEXT: br label %expand.next50 +// CHECK: expand.next50: +// CHECK-NEXT: store i32 44, ptr %x51, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 44) +// CHECK-NEXT: %call52 = call {{.*}} i32 @_Z2tgILi44EEiv() +// CHECK-NEXT: br label %expand.next53 +// CHECK: expand.next53: +// CHECK-NEXT: store i32 5, ptr %x54, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 5) +// CHECK-NEXT: %call55 = call {{.*}} i32 @_Z2tgILi5EEiv() +// CHECK-NEXT: br label %expand.end56 +// CHECK: expand.end56: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x57, ptr align 4 @__const._Z2t4IJLi42ELi43ELi44EEEvv.x, i64 12, i1 false) +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 42) +// CHECK-NEXT: %call58 = call {{.*}} i32 @_Z2tgILi42EEiv() +// CHECK-NEXT: br label %expand.next59 +// CHECK: expand.next59: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x60, ptr align 4 @__const._Z2t4IJLi42ELi43ELi44EEEvv.x.3, i64 12, i1 false) +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 42) +// CHECK-NEXT: %call61 = call {{.*}} i32 @_Z2tgILi42EEiv() +// CHECK-NEXT: br label %expand.next62 +// CHECK: expand.next62: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x63, ptr align 4 @__const._Z2t4IJLi42ELi43ELi44EEEvv.x.4, i64 12, i1 false) +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 6) +// CHECK-NEXT: %call64 = call {{.*}} i32 @_Z2tgILi6EEiv() +// CHECK-NEXT: br label %expand.end65 +// CHECK: expand.end65: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x66, ptr align 4 @__const._Z2t4IJLi42ELi43ELi44EEEvv.x.5, i64 12, i1 false) +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 42) +// CHECK-NEXT: %call67 = call {{.*}} i32 @_Z2tgILi42EEiv() +// CHECK-NEXT: br label %expand.end68 +// CHECK: expand.end68: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x2 = alloca i32, align 4 +// CHECK-NEXT: %x4 = alloca i32, align 4 +// CHECK-NEXT: %x6 = alloca i32, align 4 +// CHECK-NEXT: %x8 = alloca i32, align 4 +// CHECK-NEXT: %x10 = alloca i32, align 4 +// CHECK-NEXT: %x11 = alloca %struct.X, align 4 +// CHECK-NEXT: %x13 = alloca %struct.X, align 4 +// CHECK-NEXT: %x16 = alloca i32, align 4 +// CHECK-NEXT: %x18 = alloca i32, align 4 +// CHECK-NEXT: %x21 = alloca i32, align 4 +// CHECK-NEXT: %x24 = alloca i32, align 4 +// CHECK-NEXT: %x27 = alloca i32, align 4 +// CHECK-NEXT: %x30 = alloca i32, align 4 +// CHECK-NEXT: %x33 = alloca %struct.X, align 4 +// CHECK-NEXT: %x36 = alloca %struct.X, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %0) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 2, ptr %x2, align 4 +// CHECK-NEXT: %1 = load i32, ptr %x2, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %1) +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: store i32 3, ptr %x4, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x4, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %2) +// CHECK-NEXT: br label %expand.next5 +// CHECK: expand.next5: +// CHECK-NEXT: store i32 4, ptr %x6, align 4 +// CHECK-NEXT: %3 = load i32, ptr %x6, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %3) +// CHECK-NEXT: br label %expand.next7 +// CHECK: expand.next7: +// CHECK-NEXT: store i32 5, ptr %x8, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x8, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %4) +// CHECK-NEXT: br label %expand.next9 +// CHECK: expand.next9: +// CHECK-NEXT: store i32 6, ptr %x10, align 4 +// CHECK-NEXT: %5 = load i32, ptr %x10, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %5) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x11, ptr align 4 @__const._ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv.x, i64 12, i1 false) +// CHECK-NEXT: %a = getelementptr inbounds nuw %struct.X, ptr %x11, i32 0, i32 0 +// CHECK-NEXT: %6 = load i32, ptr %a, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %6) +// CHECK-NEXT: br label %expand.next12 +// CHECK: expand.next12: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x13, ptr align 4 @__const._ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv.x.6, i64 12, i1 false) +// CHECK-NEXT: %a14 = getelementptr inbounds nuw %struct.X, ptr %x13, i32 0, i32 0 +// CHECK-NEXT: %7 = load i32, ptr %a14, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} %7) +// CHECK-NEXT: br label %expand.end15 +// CHECK: expand.end15: +// CHECK-NEXT: store i32 1, ptr %x16, align 4 +// CHECK-NEXT: %call = call {{.*}} i32 @_Z2tgILi1EEiv() +// CHECK-NEXT: br label %expand.next17 +// CHECK: expand.next17: +// CHECK-NEXT: store i32 2, ptr %x18, align 4 +// CHECK-NEXT: %call19 = call {{.*}} i32 @_Z2tgILi2EEiv() +// CHECK-NEXT: br label %expand.next20 +// CHECK: expand.next20: +// CHECK-NEXT: store i32 3, ptr %x21, align 4 +// CHECK-NEXT: %call22 = call {{.*}} i32 @_Z2tgILi3EEiv() +// CHECK-NEXT: br label %expand.next23 +// CHECK: expand.next23: +// CHECK-NEXT: store i32 4, ptr %x24, align 4 +// CHECK-NEXT: %call25 = call {{.*}} i32 @_Z2tgILi4EEiv() +// CHECK-NEXT: br label %expand.next26 +// CHECK: expand.next26: +// CHECK-NEXT: store i32 5, ptr %x27, align 4 +// CHECK-NEXT: %call28 = call {{.*}} i32 @_Z2tgILi5EEiv() +// CHECK-NEXT: br label %expand.next29 +// CHECK: expand.next29: +// CHECK-NEXT: store i32 6, ptr %x30, align 4 +// CHECK-NEXT: %call31 = call {{.*}} i32 @_Z2tgILi6EEiv() +// CHECK-NEXT: br label %expand.end32 +// CHECK: expand.end32: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x33, ptr align 4 @__const._ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv.x.7, i64 12, i1 false) +// CHECK-NEXT: %call34 = call {{.*}} i32 @_Z2tgILi1EEiv() +// CHECK-NEXT: br label %expand.next35 +// CHECK: expand.next35: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x36, ptr align 4 @__const._ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv.x.8, i64 12, i1 false) +// CHECK-NEXT: %call37 = call {{.*}} i32 @_Z2tgILi4EEiv() +// CHECK-NEXT: br label %expand.end38 +// CHECK: expand.end38: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2f8v() +// CHECK: entry: +// CHECK-NEXT: call void @_Z2t5IJLi1ELi2ELi3EEEvv() +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z2t5IJLi1ELi2ELi3EEEvv() +// CHECK: entry: +// CHECK-NEXT: %ref.tmp = alloca %class.anon, align 1 +// CHECK-NEXT: %ref.tmp1 = alloca %class.anon.1, align 1 +// CHECK-NEXT: %ref.tmp2 = alloca %class.anon.3, align 1 +// CHECK-NEXT: call void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE1_clEv(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: call void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE0_clEv(ptr {{.*}} %ref.tmp1) +// CHECK-NEXT: call void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE_clEv(ptr {{.*}} %ref.tmp2) +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} i32 @_Z22references_enumeratingv() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %y = alloca i32, align 4 +// CHECK-NEXT: %z = alloca i32, align 4 +// CHECK-NEXT: %v = alloca ptr, align 8 +// CHECK-NEXT: %v1 = alloca ptr, align 8 +// CHECK-NEXT: %v4 = alloca ptr, align 8 +// CHECK-NEXT: %v6 = alloca ptr, align 8 +// CHECK-NEXT: %v9 = alloca ptr, align 8 +// CHECK-NEXT: %v12 = alloca ptr, align 8 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: store i32 2, ptr %y, align 4 +// CHECK-NEXT: store i32 3, ptr %z, align 4 +// CHECK-NEXT: store ptr %x, ptr %v, align 8 +// CHECK-NEXT: %0 = load ptr, ptr %v, align 8 +// CHECK-NEXT: %1 = load i32, ptr %0, align 4 +// CHECK-NEXT: %inc = add nsw i32 %1, 1 +// CHECK-NEXT: store i32 %inc, ptr %0, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store ptr %y, ptr %v1, align 8 +// CHECK-NEXT: %2 = load ptr, ptr %v1, align 8 +// CHECK-NEXT: %3 = load i32, ptr %2, align 4 +// CHECK-NEXT: %inc2 = add nsw i32 %3, 1 +// CHECK-NEXT: store i32 %inc2, ptr %2, align 4 +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: store ptr %z, ptr %v4, align 8 +// CHECK-NEXT: %4 = load ptr, ptr %v4, align 8 +// CHECK-NEXT: %5 = load i32, ptr %4, align 4 +// CHECK-NEXT: %inc5 = add nsw i32 %5, 1 +// CHECK-NEXT: store i32 %inc5, ptr %4, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store ptr %x, ptr %v6, align 8 +// CHECK-NEXT: %6 = load ptr, ptr %v6, align 8 +// CHECK-NEXT: %7 = load i32, ptr %6, align 4 +// CHECK-NEXT: %inc7 = add nsw i32 %7, 1 +// CHECK-NEXT: store i32 %inc7, ptr %6, align 4 +// CHECK-NEXT: br label %expand.next8 +// CHECK: expand.next8: +// CHECK-NEXT: store ptr %y, ptr %v9, align 8 +// CHECK-NEXT: %8 = load ptr, ptr %v9, align 8 +// CHECK-NEXT: %9 = load i32, ptr %8, align 4 +// CHECK-NEXT: %inc10 = add nsw i32 %9, 1 +// CHECK-NEXT: store i32 %inc10, ptr %8, align 4 +// CHECK-NEXT: br label %expand.next11 +// CHECK: expand.next11: +// CHECK-NEXT: store ptr %z, ptr %v12, align 8 +// CHECK-NEXT: %10 = load ptr, ptr %v12, align 8 +// CHECK-NEXT: %11 = load i32, ptr %10, align 4 +// CHECK-NEXT: %inc13 = add nsw i32 %11, 1 +// CHECK-NEXT: store i32 %inc13, ptr %10, align 4 +// CHECK-NEXT: br label %expand.end14 +// CHECK: expand.end14: +// CHECK-NEXT: %12 = load i32, ptr %x, align 4 +// CHECK-NEXT: %13 = load i32, ptr %y, align 4 +// CHECK-NEXT: %add = add nsw i32 %12, %13 +// CHECK-NEXT: %14 = load i32, ptr %z, align 4 +// CHECK-NEXT: %add15 = add nsw i32 %add, %14 +// CHECK-NEXT: ret i32 %add15 + + +// CHECK-LABEL: define {{.*}} void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE1_clEv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 1) +// CHECK-NEXT: %call = call {{.*}} i32 @_Z2tgILi1EEiv() +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE0_clEv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: store i32 2, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 2) +// CHECK-NEXT: %call = call {{.*}} i32 @_Z2tgILi2EEiv() +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE_clEv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: store i32 3, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1gi(i32 {{.*}} 3) +// CHECK-NEXT: %call = call {{.*}} i32 @_Z2tgILi3EEiv() +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: ret void diff --git a/clang/test/CodeGenCXX/cxx2c-expansion-stmts-control-flow.cpp b/clang/test/CodeGenCXX/cxx2c-expansion-stmts-control-flow.cpp new file mode 100644 index 0000000000000..f94b580290500 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx2c-expansion-stmts-control-flow.cpp @@ -0,0 +1,429 @@ +// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +void h(int, int); + +void break_continue() { + template for (auto x : {1, 2}) { + break; + h(1, x); + } + + template for (auto x : {3, 4}) { + continue; + h(2, x); + } + + template for (auto x : {5, 6}) { + if (x == 2) break; + h(3, x); + } + + template for (auto x : {7, 8}) { + if (x == 2) continue; + h(4, x); + } +} + +int break_continue_nested() { + int sum = 0; + + template for (auto x : {1, 2}) { + template for (auto y : {3, 4}) { + if (x == 2) break; + sum += y; + } + sum += x; + } + + template for (auto x : {5, 6}) { + template for (auto y : {7, 8}) { + if (x == 6) continue; + sum += y; + } + sum += x; + } + + return sum; +} + +void label() { + // Only local labels are allowed in expansion statements. + template for (auto x : {1, 2, 3}) { + __label__ a; + if (x == 1) goto a; + h(1, x); + a:; + } +} + +void nested_label() { + template for (auto x : {1, 2}) { + __label__ a; + template for (auto y : {3, 4}) { + if (y == 3) goto a; + if (y == 4) goto end; + h(x, y); + } + a:; + } + end: +} + + +// CHECK-LABEL: define {{.*}} void @_Z14break_continuev() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x2 = alloca i32, align 4 +// CHECK-NEXT: %x4 = alloca i32, align 4 +// CHECK-NEXT: %x6 = alloca i32, align 4 +// CHECK-NEXT: %x11 = alloca i32, align 4 +// CHECK-NEXT: %x16 = alloca i32, align 4 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store i32 3, ptr %x1, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 4, ptr %x2, align 4 +// CHECK-NEXT: br label %expand.end3 +// CHECK: expand.end3: +// CHECK-NEXT: store i32 5, ptr %x4, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x4, align 4 +// CHECK-NEXT: %cmp = icmp eq i32 %0, 2 +// CHECK-NEXT: br i1 %cmp, label %if.then, label %if.end +// CHECK: if.then: +// CHECK-NEXT: br label %expand.end10 +// CHECK: if.end: +// CHECK-NEXT: %1 = load i32, ptr %x4, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} 3, i32 {{.*}} %1) +// CHECK-NEXT: br label %expand.next5 +// CHECK: expand.next5: +// CHECK-NEXT: store i32 6, ptr %x6, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x6, align 4 +// CHECK-NEXT: %cmp7 = icmp eq i32 %2, 2 +// CHECK-NEXT: br i1 %cmp7, label %if.then8, label %if.end9 +// CHECK: if.then8: +// CHECK-NEXT: br label %expand.end10 +// CHECK: if.end9: +// CHECK-NEXT: %3 = load i32, ptr %x6, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} 3, i32 {{.*}} %3) +// CHECK-NEXT: br label %expand.end10 +// CHECK: expand.end10: +// CHECK-NEXT: store i32 7, ptr %x11, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x11, align 4 +// CHECK-NEXT: %cmp12 = icmp eq i32 %4, 2 +// CHECK-NEXT: br i1 %cmp12, label %if.then13, label %if.end14 +// CHECK: if.then13: +// CHECK-NEXT: br label %expand.next15 +// CHECK: if.end14: +// CHECK-NEXT: %5 = load i32, ptr %x11, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} 4, i32 {{.*}} %5) +// CHECK-NEXT: br label %expand.next15 +// CHECK: expand.next15: +// CHECK-NEXT: store i32 8, ptr %x16, align 4 +// CHECK-NEXT: %6 = load i32, ptr %x16, align 4 +// CHECK-NEXT: %cmp17 = icmp eq i32 %6, 2 +// CHECK-NEXT: br i1 %cmp17, label %if.then18, label %if.end19 +// CHECK: if.then18: +// CHECK-NEXT: br label %expand.end20 +// CHECK: if.end19: +// CHECK-NEXT: %7 = load i32, ptr %x16, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} 4, i32 {{.*}} %7) +// CHECK-NEXT: br label %expand.end20 +// CHECK: expand.end20: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} i32 @_Z21break_continue_nestedv() +// CHECK: entry: +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %y = alloca i32, align 4 +// CHECK-NEXT: %y1 = alloca i32, align 4 +// CHECK-NEXT: %x8 = alloca i32, align 4 +// CHECK-NEXT: %y9 = alloca i32, align 4 +// CHECK-NEXT: %y15 = alloca i32, align 4 +// CHECK-NEXT: %x23 = alloca i32, align 4 +// CHECK-NEXT: %y24 = alloca i32, align 4 +// CHECK-NEXT: %y30 = alloca i32, align 4 +// CHECK-NEXT: %x38 = alloca i32, align 4 +// CHECK-NEXT: %y39 = alloca i32, align 4 +// CHECK-NEXT: %y45 = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: store i32 3, ptr %y, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: %cmp = icmp eq i32 %0, 2 +// CHECK-NEXT: br i1 %cmp, label %if.then, label %if.end +// CHECK: if.then: +// CHECK-NEXT: br label %expand.end +// CHECK: if.end: +// CHECK-NEXT: %1 = load i32, ptr %y, align 4 +// CHECK-NEXT: %2 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %2, %1 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 4, ptr %y1, align 4 +// CHECK-NEXT: %3 = load i32, ptr %x, align 4 +// CHECK-NEXT: %cmp2 = icmp eq i32 %3, 2 +// CHECK-NEXT: br i1 %cmp2, label %if.then3, label %if.end4 +// CHECK: if.then3: +// CHECK-NEXT: br label %expand.end +// CHECK: if.end4: +// CHECK-NEXT: %4 = load i32, ptr %y1, align 4 +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add5 = add nsw i32 %5, %4 +// CHECK-NEXT: store i32 %add5, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: %6 = load i32, ptr %x, align 4 +// CHECK-NEXT: %7 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add6 = add nsw i32 %7, %6 +// CHECK-NEXT: store i32 %add6, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next7 +// CHECK: expand.next7: +// CHECK-NEXT: store i32 2, ptr %x8, align 4 +// CHECK-NEXT: store i32 3, ptr %y9, align 4 +// CHECK-NEXT: %8 = load i32, ptr %x8, align 4 +// CHECK-NEXT: %cmp10 = icmp eq i32 %8, 2 +// CHECK-NEXT: br i1 %cmp10, label %if.then11, label %if.end12 +// CHECK: if.then11: +// CHECK-NEXT: br label %expand.end20 +// CHECK: if.end12: +// CHECK-NEXT: %9 = load i32, ptr %y9, align 4 +// CHECK-NEXT: %10 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add13 = add nsw i32 %10, %9 +// CHECK-NEXT: store i32 %add13, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next14 +// CHECK: expand.next14: +// CHECK-NEXT: store i32 4, ptr %y15, align 4 +// CHECK-NEXT: %11 = load i32, ptr %x8, align 4 +// CHECK-NEXT: %cmp16 = icmp eq i32 %11, 2 +// CHECK-NEXT: br i1 %cmp16, label %if.then17, label %if.end18 +// CHECK: if.then17: +// CHECK-NEXT: br label %expand.end20 +// CHECK: if.end18: +// CHECK-NEXT: %12 = load i32, ptr %y15, align 4 +// CHECK-NEXT: %13 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add19 = add nsw i32 %13, %12 +// CHECK-NEXT: store i32 %add19, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end20 +// CHECK: expand.end20: +// CHECK-NEXT: %14 = load i32, ptr %x8, align 4 +// CHECK-NEXT: %15 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add21 = add nsw i32 %15, %14 +// CHECK-NEXT: store i32 %add21, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end22 +// CHECK: expand.end22: +// CHECK-NEXT: store i32 5, ptr %x23, align 4 +// CHECK-NEXT: store i32 7, ptr %y24, align 4 +// CHECK-NEXT: %16 = load i32, ptr %x23, align 4 +// CHECK-NEXT: %cmp25 = icmp eq i32 %16, 6 +// CHECK-NEXT: br i1 %cmp25, label %if.then26, label %if.end27 +// CHECK: if.then26: +// CHECK-NEXT: br label %expand.next29 +// CHECK: if.end27: +// CHECK-NEXT: %17 = load i32, ptr %y24, align 4 +// CHECK-NEXT: %18 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add28 = add nsw i32 %18, %17 +// CHECK-NEXT: store i32 %add28, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next29 +// CHECK: expand.next29: +// CHECK-NEXT: store i32 8, ptr %y30, align 4 +// CHECK-NEXT: %19 = load i32, ptr %x23, align 4 +// CHECK-NEXT: %cmp31 = icmp eq i32 %19, 6 +// CHECK-NEXT: br i1 %cmp31, label %if.then32, label %if.end33 +// CHECK: if.then32: +// CHECK-NEXT: br label %expand.end35 +// CHECK: if.end33: +// CHECK-NEXT: %20 = load i32, ptr %y30, align 4 +// CHECK-NEXT: %21 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add34 = add nsw i32 %21, %20 +// CHECK-NEXT: store i32 %add34, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end35 +// CHECK: expand.end35: +// CHECK-NEXT: %22 = load i32, ptr %x23, align 4 +// CHECK-NEXT: %23 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add36 = add nsw i32 %23, %22 +// CHECK-NEXT: store i32 %add36, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next37 +// CHECK: expand.next37: +// CHECK-NEXT: store i32 6, ptr %x38, align 4 +// CHECK-NEXT: store i32 7, ptr %y39, align 4 +// CHECK-NEXT: %24 = load i32, ptr %x38, align 4 +// CHECK-NEXT: %cmp40 = icmp eq i32 %24, 6 +// CHECK-NEXT: br i1 %cmp40, label %if.then41, label %if.end42 +// CHECK: if.then41: +// CHECK-NEXT: br label %expand.next44 +// CHECK: if.end42: +// CHECK-NEXT: %25 = load i32, ptr %y39, align 4 +// CHECK-NEXT: %26 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add43 = add nsw i32 %26, %25 +// CHECK-NEXT: store i32 %add43, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next44 +// CHECK: expand.next44: +// CHECK-NEXT: store i32 8, ptr %y45, align 4 +// CHECK-NEXT: %27 = load i32, ptr %x38, align 4 +// CHECK-NEXT: %cmp46 = icmp eq i32 %27, 6 +// CHECK-NEXT: br i1 %cmp46, label %if.then47, label %if.end48 +// CHECK: if.then47: +// CHECK-NEXT: br label %expand.end50 +// CHECK: if.end48: +// CHECK-NEXT: %28 = load i32, ptr %y45, align 4 +// CHECK-NEXT: %29 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add49 = add nsw i32 %29, %28 +// CHECK-NEXT: store i32 %add49, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end50 +// CHECK: expand.end50: +// CHECK-NEXT: %30 = load i32, ptr %x38, align 4 +// CHECK-NEXT: %31 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add51 = add nsw i32 %31, %30 +// CHECK-NEXT: store i32 %add51, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end52 +// CHECK: expand.end52: +// CHECK-NEXT: %32 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %32 + + +// CHECK-LABEL: define {{.*}} void @_Z5labelv() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x7 = alloca i32, align 4 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: %cmp = icmp eq i32 %0, 1 +// CHECK-NEXT: br i1 %cmp, label %if.then, label %if.end +// CHECK: if.then: +// CHECK-NEXT: br label %a +// CHECK: if.end: +// CHECK-NEXT: %1 = load i32, ptr %x, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} 1, i32 {{.*}} %1) +// CHECK-NEXT: br label %a +// CHECK: a: +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 2, ptr %x1, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x1, align 4 +// CHECK-NEXT: %cmp2 = icmp eq i32 %2, 1 +// CHECK-NEXT: br i1 %cmp2, label %if.then3, label %if.end4 +// CHECK: if.then3: +// CHECK-NEXT: br label %a5 +// CHECK: if.end4: +// CHECK-NEXT: %3 = load i32, ptr %x1, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} 1, i32 {{.*}} %3) +// CHECK-NEXT: br label %a5 +// CHECK: a5: +// CHECK-NEXT: br label %expand.next6 +// CHECK: expand.next6: +// CHECK-NEXT: store i32 3, ptr %x7, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x7, align 4 +// CHECK-NEXT: %cmp8 = icmp eq i32 %4, 1 +// CHECK-NEXT: br i1 %cmp8, label %if.then9, label %if.end10 +// CHECK: if.then9: +// CHECK-NEXT: br label %a11 +// CHECK: if.end10: +// CHECK-NEXT: %5 = load i32, ptr %x7, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} 1, i32 {{.*}} %5) +// CHECK-NEXT: br label %a11 +// CHECK: a11: +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_Z12nested_labelv() +// CHECK: entry: +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %y = alloca i32, align 4 +// CHECK-NEXT: %y4 = alloca i32, align 4 +// CHECK-NEXT: %x12 = alloca i32, align 4 +// CHECK-NEXT: %y13 = alloca i32, align 4 +// CHECK-NEXT: %y21 = alloca i32, align 4 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: store i32 3, ptr %y, align 4 +// CHECK-NEXT: %0 = load i32, ptr %y, align 4 +// CHECK-NEXT: %cmp = icmp eq i32 %0, 3 +// CHECK-NEXT: br i1 %cmp, label %if.then, label %if.end +// CHECK: if.then: +// CHECK-NEXT: br label %a +// CHECK: if.end: +// CHECK-NEXT: %1 = load i32, ptr %y, align 4 +// CHECK-NEXT: %cmp1 = icmp eq i32 %1, 4 +// CHECK-NEXT: br i1 %cmp1, label %if.then2, label %if.end3 +// CHECK: if.then2: +// CHECK-NEXT: br label %end +// CHECK: if.end3: +// CHECK-NEXT: %2 = load i32, ptr %x, align 4 +// CHECK-NEXT: %3 = load i32, ptr %y, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} %2, i32 {{.*}} %3) +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 4, ptr %y4, align 4 +// CHECK-NEXT: %4 = load i32, ptr %y4, align 4 +// CHECK-NEXT: %cmp5 = icmp eq i32 %4, 3 +// CHECK-NEXT: br i1 %cmp5, label %if.then6, label %if.end7 +// CHECK: if.then6: +// CHECK-NEXT: br label %a +// CHECK: if.end7: +// CHECK-NEXT: %5 = load i32, ptr %y4, align 4 +// CHECK-NEXT: %cmp8 = icmp eq i32 %5, 4 +// CHECK-NEXT: br i1 %cmp8, label %if.then9, label %if.end10 +// CHECK: if.then9: +// CHECK-NEXT: br label %end +// CHECK: if.end10: +// CHECK-NEXT: %6 = load i32, ptr %x, align 4 +// CHECK-NEXT: %7 = load i32, ptr %y4, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} %6, i32 {{.*}} %7) +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: br label %a +// CHECK: a: +// CHECK-NEXT: br label %expand.next11 +// CHECK: expand.next11: +// CHECK-NEXT: store i32 2, ptr %x12, align 4 +// CHECK-NEXT: store i32 3, ptr %y13, align 4 +// CHECK-NEXT: %8 = load i32, ptr %y13, align 4 +// CHECK-NEXT: %cmp14 = icmp eq i32 %8, 3 +// CHECK-NEXT: br i1 %cmp14, label %if.then15, label %if.end16 +// CHECK: if.then15: +// CHECK-NEXT: br label %a29 +// CHECK: if.end16: +// CHECK-NEXT: %9 = load i32, ptr %y13, align 4 +// CHECK-NEXT: %cmp17 = icmp eq i32 %9, 4 +// CHECK-NEXT: br i1 %cmp17, label %if.then18, label %if.end19 +// CHECK: if.then18: +// CHECK-NEXT: br label %end +// CHECK: if.end19: +// CHECK-NEXT: %10 = load i32, ptr %x12, align 4 +// CHECK-NEXT: %11 = load i32, ptr %y13, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} %10, i32 {{.*}} %11) +// CHECK-NEXT: br label %expand.next20 +// CHECK: expand.next20: +// CHECK-NEXT: store i32 4, ptr %y21, align 4 +// CHECK-NEXT: %12 = load i32, ptr %y21, align 4 +// CHECK-NEXT: %cmp22 = icmp eq i32 %12, 3 +// CHECK-NEXT: br i1 %cmp22, label %if.then23, label %if.end24 +// CHECK: if.then23: +// CHECK-NEXT: br label %a29 +// CHECK: if.end24: +// CHECK-NEXT: %13 = load i32, ptr %y21, align 4 +// CHECK-NEXT: %cmp25 = icmp eq i32 %13, 4 +// CHECK-NEXT: br i1 %cmp25, label %if.then26, label %if.end27 +// CHECK: if.then26: +// CHECK-NEXT: br label %end +// CHECK: if.end27: +// CHECK-NEXT: %14 = load i32, ptr %x12, align 4 +// CHECK-NEXT: %15 = load i32, ptr %y21, align 4 +// CHECK-NEXT: call void @_Z1hii(i32 {{.*}} %14, i32 {{.*}} %15) +// CHECK-NEXT: br label %expand.end28 +// CHECK: expand.end28: +// CHECK-NEXT: br label %a29 +// CHECK: a29: +// CHECK-NEXT: br label %expand.end30 +// CHECK: expand.end30: +// CHECK-NEXT: br label %end +// CHECK: end: +// CHECK-NEXT: ret void diff --git a/clang/test/CodeGenCXX/cxx2c-expansion-stmts-templates.cpp b/clang/test/CodeGenCXX/cxx2c-expansion-stmts-templates.cpp new file mode 100644 index 0000000000000..e0de7ced5baee --- /dev/null +++ b/clang/test/CodeGenCXX/cxx2c-expansion-stmts-templates.cpp @@ -0,0 +1,208 @@ +// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +struct E { + int x, y; + constexpr E(int x, int y) : x{x}, y{y} {} +}; + +template +int unexpanded_pack_good(Es ...es) { + int sum = 0; + ([&] { + template for (auto x : es) sum += x; + template for (Es e : {{5, 6}, {7, 8}}) sum += e.x + e.y; + }(), ...); + return sum; +} + +int unexpanded_pack() { + return unexpanded_pack_good(E{1, 2}, E{3, 4}); +} + + +// CHECK: %struct.E = type { i32, i32 } +// CHECK: %class.anon = type { ptr, ptr } +// CHECK: %class.anon.0 = type { ptr, ptr } + + +// CHECK-LABEL: define {{.*}} i32 @_Z15unexpanded_packv() +// CHECK: entry: +// CHECK-NEXT: %agg.tmp = alloca %struct.E, align 4 +// CHECK-NEXT: %agg.tmp1 = alloca %struct.E, align 4 +// CHECK-NEXT: call void @_ZN1EC1Eii(ptr {{.*}} %agg.tmp, i32 {{.*}} 1, i32 {{.*}} 2) +// CHECK-NEXT: call void @_ZN1EC1Eii(ptr {{.*}} %agg.tmp1, i32 {{.*}} 3, i32 {{.*}} 4) +// CHECK-NEXT: %0 = load i64, ptr %agg.tmp, align 4 +// CHECK-NEXT: %1 = load i64, ptr %agg.tmp1, align 4 +// CHECK-NEXT: %call = call {{.*}} i32 @_Z20unexpanded_pack_goodIJ1ES0_EEiDpT_(i64 %0, i64 %1) +// CHECK-NEXT: ret i32 %call + + +// CHECK-LABEL: define {{.*}} i32 @_Z20unexpanded_pack_goodIJ1ES0_EEiDpT_(i64 %es.coerce, i64 %es.coerce2) +// CHECK: entry: +// CHECK-NEXT: %es = alloca %struct.E, align 4 +// CHECK-NEXT: %es3 = alloca %struct.E, align 4 +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %ref.tmp = alloca %class.anon, align 8 +// CHECK-NEXT: %ref.tmp4 = alloca %class.anon.0, align 8 +// CHECK-NEXT: store i64 %es.coerce, ptr %es, align 4 +// CHECK-NEXT: store i64 %es.coerce2, ptr %es3, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: %0 = getelementptr inbounds nuw %class.anon, ptr %ref.tmp, i32 0, i32 0 +// CHECK-NEXT: store ptr %es, ptr %0, align 8 +// CHECK-NEXT: %1 = getelementptr inbounds nuw %class.anon, ptr %ref.tmp, i32 0, i32 1 +// CHECK-NEXT: store ptr %sum, ptr %1, align 8 +// CHECK-NEXT: call void @_ZZ20unexpanded_pack_goodIJ1ES0_EEiDpT_ENKUlvE0_clEv(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: %2 = getelementptr inbounds nuw %class.anon.0, ptr %ref.tmp4, i32 0, i32 0 +// CHECK-NEXT: store ptr %es3, ptr %2, align 8 +// CHECK-NEXT: %3 = getelementptr inbounds nuw %class.anon.0, ptr %ref.tmp4, i32 0, i32 1 +// CHECK-NEXT: store ptr %sum, ptr %3, align 8 +// CHECK-NEXT: call void @_ZZ20unexpanded_pack_goodIJ1ES0_EEiDpT_ENKUlvE_clEv(ptr {{.*}} %ref.tmp4) +// CHECK-NEXT: %4 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %4 + + +// CHECK-LABEL: define {{.*}} void @_ZN1EC1Eii(ptr {{.*}} %this, i32 {{.*}} %x, i32 {{.*}} %y) {{.*}} +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %x.addr = alloca i32, align 4 +// CHECK-NEXT: %y.addr = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: store i32 %x, ptr %x.addr, align 4 +// CHECK-NEXT: store i32 %y, ptr %y.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: %0 = load i32, ptr %x.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %y.addr, align 4 +// CHECK-NEXT: call void @_ZN1EC2Eii(ptr {{.*}} %this1, i32 {{.*}} %0, i32 {{.*}} %1) +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_ZZ20unexpanded_pack_goodIJ1ES0_EEiDpT_ENKUlvE0_clEv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x3 = alloca i32, align 4 +// CHECK-NEXT: %e = alloca %struct.E, align 4 +// CHECK-NEXT: %e10 = alloca %struct.E, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: %1 = getelementptr inbounds nuw %class.anon, ptr %this1, i32 0, i32 0 +// CHECK-NEXT: %2 = load ptr, ptr %1, align 8 +// CHECK-NEXT: store ptr %2, ptr %0, align 8 +// CHECK-NEXT: %3 = load ptr, ptr %0, align 8 +// CHECK-NEXT: %x2 = getelementptr inbounds nuw %struct.E, ptr %3, i32 0, i32 0 +// CHECK-NEXT: %4 = load i32, ptr %x2, align 4 +// CHECK-NEXT: store i32 %4, ptr %x, align 4 +// CHECK-NEXT: %5 = load i32, ptr %x, align 4 +// CHECK-NEXT: %6 = getelementptr inbounds nuw %class.anon, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %7 = load ptr, ptr %6, align 8 +// CHECK-NEXT: %8 = load i32, ptr %7, align 4 +// CHECK-NEXT: %add = add nsw i32 %8, %5 +// CHECK-NEXT: store i32 %add, ptr %7, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: %9 = load ptr, ptr %0, align 8 +// CHECK-NEXT: %y = getelementptr inbounds nuw %struct.E, ptr %9, i32 0, i32 1 +// CHECK-NEXT: %10 = load i32, ptr %y, align 4 +// CHECK-NEXT: store i32 %10, ptr %x3, align 4 +// CHECK-NEXT: %11 = load i32, ptr %x3, align 4 +// CHECK-NEXT: %12 = getelementptr inbounds nuw %class.anon, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %13 = load ptr, ptr %12, align 8 +// CHECK-NEXT: %14 = load i32, ptr %13, align 4 +// CHECK-NEXT: %add4 = add nsw i32 %14, %11 +// CHECK-NEXT: store i32 %add4, ptr %13, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: call void @_ZN1EC1Eii(ptr {{.*}} %e, i32 {{.*}} 5, i32 {{.*}} 6) +// CHECK-NEXT: %x5 = getelementptr inbounds nuw %struct.E, ptr %e, i32 0, i32 0 +// CHECK-NEXT: %15 = load i32, ptr %x5, align 4 +// CHECK-NEXT: %y6 = getelementptr inbounds nuw %struct.E, ptr %e, i32 0, i32 1 +// CHECK-NEXT: %16 = load i32, ptr %y6, align 4 +// CHECK-NEXT: %add7 = add nsw i32 %15, %16 +// CHECK-NEXT: %17 = getelementptr inbounds nuw %class.anon, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %18 = load ptr, ptr %17, align 8 +// CHECK-NEXT: %19 = load i32, ptr %18, align 4 +// CHECK-NEXT: %add8 = add nsw i32 %19, %add7 +// CHECK-NEXT: store i32 %add8, ptr %18, align 4 +// CHECK-NEXT: br label %expand.next9 +// CHECK: expand.next9: +// CHECK-NEXT: call void @_ZN1EC1Eii(ptr {{.*}} %e10, i32 {{.*}} 7, i32 {{.*}} 8) +// CHECK-NEXT: %x11 = getelementptr inbounds nuw %struct.E, ptr %e10, i32 0, i32 0 +// CHECK-NEXT: %20 = load i32, ptr %x11, align 4 +// CHECK-NEXT: %y12 = getelementptr inbounds nuw %struct.E, ptr %e10, i32 0, i32 1 +// CHECK-NEXT: %21 = load i32, ptr %y12, align 4 +// CHECK-NEXT: %add13 = add nsw i32 %20, %21 +// CHECK-NEXT: %22 = getelementptr inbounds nuw %class.anon, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %23 = load ptr, ptr %22, align 8 +// CHECK-NEXT: %24 = load i32, ptr %23, align 4 +// CHECK-NEXT: %add14 = add nsw i32 %24, %add13 +// CHECK-NEXT: store i32 %add14, ptr %23, align 4 +// CHECK-NEXT: br label %expand.end15 +// CHECK: expand.end15: +// CHECK-NEXT: ret void + + +// CHECK-LABEL: define {{.*}} void @_ZZ20unexpanded_pack_goodIJ1ES0_EEiDpT_ENKUlvE_clEv(ptr {{.*}} %this) +// CHECK: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %0 = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x3 = alloca i32, align 4 +// CHECK-NEXT: %e = alloca %struct.E, align 4 +// CHECK-NEXT: %e10 = alloca %struct.E, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: %1 = getelementptr inbounds nuw %class.anon.0, ptr %this1, i32 0, i32 0 +// CHECK-NEXT: %2 = load ptr, ptr %1, align 8 +// CHECK-NEXT: store ptr %2, ptr %0, align 8 +// CHECK-NEXT: %3 = load ptr, ptr %0, align 8 +// CHECK-NEXT: %x2 = getelementptr inbounds nuw %struct.E, ptr %3, i32 0, i32 0 +// CHECK-NEXT: %4 = load i32, ptr %x2, align 4 +// CHECK-NEXT: store i32 %4, ptr %x, align 4 +// CHECK-NEXT: %5 = load i32, ptr %x, align 4 +// CHECK-NEXT: %6 = getelementptr inbounds nuw %class.anon.0, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %7 = load ptr, ptr %6, align 8 +// CHECK-NEXT: %8 = load i32, ptr %7, align 4 +// CHECK-NEXT: %add = add nsw i32 %8, %5 +// CHECK-NEXT: store i32 %add, ptr %7, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: %9 = load ptr, ptr %0, align 8 +// CHECK-NEXT: %y = getelementptr inbounds nuw %struct.E, ptr %9, i32 0, i32 1 +// CHECK-NEXT: %10 = load i32, ptr %y, align 4 +// CHECK-NEXT: store i32 %10, ptr %x3, align 4 +// CHECK-NEXT: %11 = load i32, ptr %x3, align 4 +// CHECK-NEXT: %12 = getelementptr inbounds nuw %class.anon.0, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %13 = load ptr, ptr %12, align 8 +// CHECK-NEXT: %14 = load i32, ptr %13, align 4 +// CHECK-NEXT: %add4 = add nsw i32 %14, %11 +// CHECK-NEXT: store i32 %add4, ptr %13, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: call void @_ZN1EC1Eii(ptr {{.*}} %e, i32 {{.*}} 5, i32 {{.*}} 6) +// CHECK-NEXT: %x5 = getelementptr inbounds nuw %struct.E, ptr %e, i32 0, i32 0 +// CHECK-NEXT: %15 = load i32, ptr %x5, align 4 +// CHECK-NEXT: %y6 = getelementptr inbounds nuw %struct.E, ptr %e, i32 0, i32 1 +// CHECK-NEXT: %16 = load i32, ptr %y6, align 4 +// CHECK-NEXT: %add7 = add nsw i32 %15, %16 +// CHECK-NEXT: %17 = getelementptr inbounds nuw %class.anon.0, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %18 = load ptr, ptr %17, align 8 +// CHECK-NEXT: %19 = load i32, ptr %18, align 4 +// CHECK-NEXT: %add8 = add nsw i32 %19, %add7 +// CHECK-NEXT: store i32 %add8, ptr %18, align 4 +// CHECK-NEXT: br label %expand.next9 +// CHECK: expand.next9: +// CHECK-NEXT: call void @_ZN1EC1Eii(ptr {{.*}} %e10, i32 {{.*}} 7, i32 {{.*}} 8) +// CHECK-NEXT: %x11 = getelementptr inbounds nuw %struct.E, ptr %e10, i32 0, i32 0 +// CHECK-NEXT: %20 = load i32, ptr %x11, align 4 +// CHECK-NEXT: %y12 = getelementptr inbounds nuw %struct.E, ptr %e10, i32 0, i32 1 +// CHECK-NEXT: %21 = load i32, ptr %y12, align 4 +// CHECK-NEXT: %add13 = add nsw i32 %20, %21 +// CHECK-NEXT: %22 = getelementptr inbounds nuw %class.anon.0, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %23 = load ptr, ptr %22, align 8 +// CHECK-NEXT: %24 = load i32, ptr %23, align 4 +// CHECK-NEXT: %add14 = add nsw i32 %24, %add13 +// CHECK-NEXT: store i32 %add14, ptr %23, align 4 +// CHECK-NEXT: br label %expand.end15 +// CHECK: expand.end15: +// CHECK-NEXT: ret void diff --git a/clang/test/CodeGenCXX/cxx2c-iterating-expansion-stmt.cpp b/clang/test/CodeGenCXX/cxx2c-iterating-expansion-stmt.cpp new file mode 100644 index 0000000000000..ad73972740749 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx2c-iterating-expansion-stmt.cpp @@ -0,0 +1,474 @@ +// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +template +struct Array { + T data[size]{}; + constexpr const T* begin() const { return data; } + constexpr const T* end() const { return data + size; } +}; + +int f1() { + static constexpr Array integers{1, 2, 3}; + int sum = 0; + template for (auto x : integers) sum += x; + return sum; +} + +int f2() { + static constexpr Array integers{1, 2, 3}; + int sum = 0; + template for (constexpr auto x : integers) sum += x; + return sum; +} + +int f3() { + static constexpr Array integers{}; + int sum = 0; + template for (constexpr auto x : integers) { + static_assert(false, "not expanded"); + sum += x; + } + return sum; +} + +int f4() { + static constexpr Array a{1, 2}; + static constexpr Array b{3, 4}; + int sum = 0; + + template for (auto x : a) + template for (auto y : b) + sum += x + y; + + template for (constexpr auto x : a) + template for (constexpr auto y : b) + sum += x + y; + + return sum; +} + +struct Private { + static constexpr Array integers{1, 2, 3}; + friend constexpr int friend_func(); + +private: + constexpr const int* begin() const { return integers.begin(); } + constexpr const int* end() const { return integers.end(); } + +public: + static int member_func(); +}; + +int Private::member_func() { + int sum = 0; + static constexpr Private p1; + template for (auto x : p1) sum += x; + return sum; +} + +struct CustomIterator { + struct iterator { + int n; + + constexpr iterator operator+(int m) const { + return {n + m}; + } + + constexpr int operator*() const { + return n; + } + + // FIXME: Should be '!=' once we support that properly. + friend constexpr __PTRDIFF_TYPE__ operator-(iterator a, iterator b) { + return a.n - b.n; + } + }; + + constexpr iterator begin() const { return iterator(1); } + constexpr iterator end() const { return iterator(5); } +}; + +int custom_iterator() { + static constexpr CustomIterator c; + int sum = 0; + template for (auto x : c) sum += x; + template for (constexpr auto x : c) sum += x; + return sum; +} + +// CHECK: @_ZZ2f1vE8integers = internal constant %struct.Array { [3 x i32] [i32 1, i32 2, i32 3] }, align 4 +// CHECK: @_ZZ2f2vE8integers = internal constant %struct.Array { [3 x i32] [i32 1, i32 2, i32 3] }, align 4 +// CHECK: @_ZZ2f3vE8integers = internal constant %struct.Array.0 zeroinitializer, align 4 +// CHECK: @_ZZ2f4vE1a = internal constant %struct.Array.1 { [2 x i32] [i32 1, i32 2] }, align 4 +// CHECK: @_ZZ2f4vE1b = internal constant %struct.Array.1 { [2 x i32] [i32 3, i32 4] }, align 4 +// CHECK: @_ZZN7Private11member_funcEvE2p1 = internal constant %struct.Private zeroinitializer, align 1 +// CHECK: @_ZN7Private8integersE = {{.*}} constant %struct.Array { [3 x i32] [i32 1, i32 2, i32 3] }, comdat, align 4 +// CHECK: @_ZZ15custom_iteratorvE1c = internal constant %struct.CustomIterator zeroinitializer, align 1 +// CHECK: @__const._Z15custom_iteratorv.__begin1 = private {{.*}} constant %"struct.CustomIterator::iterator" { i32 1 }, align 4 +// CHECK: @__const._Z15custom_iteratorv.__end1 = private {{.*}} constant %"struct.CustomIterator::iterator" { i32 5 }, align 4 +// CHECK: @__const._Z15custom_iteratorv.__begin1.1 = private {{.*}} constant %"struct.CustomIterator::iterator" { i32 1 }, align 4 +// CHECK: @__const._Z15custom_iteratorv.__end1.2 = private {{.*}} constant %"struct.CustomIterator::iterator" { i32 5 }, align 4 + +// CHECK-LABEL: define {{.*}} i32 @_Z2f1v() +// CHECK: entry: +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %__range1 = alloca ptr, align 8 +// CHECK-NEXT: %__begin1 = alloca ptr, align 8 +// CHECK-NEXT: %__end1 = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x4 = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: store ptr @_ZZ2f1vE8integers, ptr %__range1, align 8 +// CHECK-NEXT: store ptr @_ZZ2f1vE8integers, ptr %__begin1, align 8 +// CHECK-NEXT: store ptr getelementptr (i8, ptr @_ZZ2f1vE8integers, i64 12), ptr %__end1, align 8 +// CHECK-NEXT: %0 = load i32, ptr @_ZZ2f1vE8integers, align 4 +// CHECK-NEXT: store i32 %0, ptr %x, align 4 +// CHECK-NEXT: %1 = load i32, ptr %x, align 4 +// CHECK-NEXT: %2 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %2, %1 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: %3 = load i32, ptr getelementptr inbounds (i32, ptr @_ZZ2f1vE8integers, i64 1), align 4 +// CHECK-NEXT: store i32 %3, ptr %x1, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x1, align 4 +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add2 = add nsw i32 %5, %4 +// CHECK-NEXT: store i32 %add2, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: %6 = load i32, ptr getelementptr inbounds (i32, ptr @_ZZ2f1vE8integers, i64 2), align 4 +// CHECK-NEXT: store i32 %6, ptr %x4, align 4 +// CHECK-NEXT: %7 = load i32, ptr %x4, align 4 +// CHECK-NEXT: %8 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add5 = add nsw i32 %8, %7 +// CHECK-NEXT: store i32 %add5, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: %9 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %9 + + +// CHECK-LABEL: define {{.*}} i32 @_Z2f2v() +// CHECK: entry: +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %__range1 = alloca ptr, align 8 +// CHECK-NEXT: %__begin1 = alloca ptr, align 8 +// CHECK-NEXT: %__end1 = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x4 = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: store ptr @_ZZ2f2vE8integers, ptr %__range1, align 8 +// CHECK-NEXT: store ptr @_ZZ2f2vE8integers, ptr %__begin1, align 8 +// CHECK-NEXT: store ptr getelementptr (i8, ptr @_ZZ2f2vE8integers, i64 12), ptr %__end1, align 8 +// CHECK-NEXT: store i32 1, ptr %x, align 4 +// CHECK-NEXT: %0 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %0, 1 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: store i32 2, ptr %x1, align 4 +// CHECK-NEXT: %1 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add2 = add nsw i32 %1, 2 +// CHECK-NEXT: store i32 %add2, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: store i32 3, ptr %x4, align 4 +// CHECK-NEXT: %2 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add5 = add nsw i32 %2, 3 +// CHECK-NEXT: store i32 %add5, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: %3 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %3 + + +// CHECK-LABEL: define {{.*}} i32 @_Z2f3v() +// CHECK: entry: +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %__range1 = alloca ptr, align 8 +// CHECK-NEXT: %__begin1 = alloca ptr, align 8 +// CHECK-NEXT: %__end1 = alloca ptr, align 8 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: store ptr @_ZZ2f3vE8integers, ptr %__range1, align 8 +// CHECK-NEXT: store ptr @_ZZ2f3vE8integers, ptr %__begin1, align 8 +// CHECK-NEXT: store ptr @_ZZ2f3vE8integers, ptr %__end1, align 8 +// CHECK-NEXT: %0 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %0 + + +// CHECK-LABEL: define {{.*}} i32 @_Z2f4v() +// CHECK: entry: +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %__range1 = alloca ptr, align 8 +// CHECK-NEXT: %__begin1 = alloca ptr, align 8 +// CHECK-NEXT: %__end1 = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %__range2 = alloca ptr, align 8 +// CHECK-NEXT: %__begin2 = alloca ptr, align 8 +// CHECK-NEXT: %__end2 = alloca ptr, align 8 +// CHECK-NEXT: %y = alloca i32, align 4 +// CHECK-NEXT: %y2 = alloca i32, align 4 +// CHECK-NEXT: %x6 = alloca i32, align 4 +// CHECK-NEXT: %__range27 = alloca ptr, align 8 +// CHECK-NEXT: %__begin28 = alloca ptr, align 8 +// CHECK-NEXT: %__end29 = alloca ptr, align 8 +// CHECK-NEXT: %y10 = alloca i32, align 4 +// CHECK-NEXT: %y14 = alloca i32, align 4 +// CHECK-NEXT: %__range119 = alloca ptr, align 8 +// CHECK-NEXT: %__begin120 = alloca ptr, align 8 +// CHECK-NEXT: %__end121 = alloca ptr, align 8 +// CHECK-NEXT: %x22 = alloca i32, align 4 +// CHECK-NEXT: %__range223 = alloca ptr, align 8 +// CHECK-NEXT: %__begin224 = alloca ptr, align 8 +// CHECK-NEXT: %__end225 = alloca ptr, align 8 +// CHECK-NEXT: %y26 = alloca i32, align 4 +// CHECK-NEXT: %y29 = alloca i32, align 4 +// CHECK-NEXT: %x33 = alloca i32, align 4 +// CHECK-NEXT: %__range234 = alloca ptr, align 8 +// CHECK-NEXT: %__begin235 = alloca ptr, align 8 +// CHECK-NEXT: %__end236 = alloca ptr, align 8 +// CHECK-NEXT: %y37 = alloca i32, align 4 +// CHECK-NEXT: %y40 = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: store ptr @_ZZ2f4vE1a, ptr %__range1, align 8 +// CHECK-NEXT: store ptr @_ZZ2f4vE1a, ptr %__begin1, align 8 +// CHECK-NEXT: store ptr getelementptr (i8, ptr @_ZZ2f4vE1a, i64 8), ptr %__end1, align 8 +// CHECK-NEXT: %0 = load i32, ptr @_ZZ2f4vE1a, align 4 +// CHECK-NEXT: store i32 %0, ptr %x, align 4 +// CHECK-NEXT: store ptr @_ZZ2f4vE1b, ptr %__range2, align 8 +// CHECK-NEXT: store ptr @_ZZ2f4vE1b, ptr %__begin2, align 8 +// CHECK-NEXT: store ptr getelementptr (i8, ptr @_ZZ2f4vE1b, i64 8), ptr %__end2, align 8 +// CHECK-NEXT: %1 = load i32, ptr @_ZZ2f4vE1b, align 4 +// CHECK-NEXT: store i32 %1, ptr %y, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x, align 4 +// CHECK-NEXT: %3 = load i32, ptr %y, align 4 +// CHECK-NEXT: %add = add nsw i32 %2, %3 +// CHECK-NEXT: %4 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add1 = add nsw i32 %4, %add +// CHECK-NEXT: store i32 %add1, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: %5 = load i32, ptr getelementptr inbounds (i32, ptr @_ZZ2f4vE1b, i64 1), align 4 +// CHECK-NEXT: store i32 %5, ptr %y2, align 4 +// CHECK-NEXT: %6 = load i32, ptr %x, align 4 +// CHECK-NEXT: %7 = load i32, ptr %y2, align 4 +// CHECK-NEXT: %add3 = add nsw i32 %6, %7 +// CHECK-NEXT: %8 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add4 = add nsw i32 %8, %add3 +// CHECK-NEXT: store i32 %add4, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: br label %expand.next5 +// CHECK: expand.next5: +// CHECK-NEXT: %9 = load i32, ptr getelementptr inbounds (i32, ptr @_ZZ2f4vE1a, i64 1), align 4 +// CHECK-NEXT: store i32 %9, ptr %x6, align 4 +// CHECK-NEXT: store ptr @_ZZ2f4vE1b, ptr %__range27, align 8 +// CHECK-NEXT: store ptr @_ZZ2f4vE1b, ptr %__begin28, align 8 +// CHECK-NEXT: store ptr getelementptr (i8, ptr @_ZZ2f4vE1b, i64 8), ptr %__end29, align 8 +// CHECK-NEXT: %10 = load i32, ptr @_ZZ2f4vE1b, align 4 +// CHECK-NEXT: store i32 %10, ptr %y10, align 4 +// CHECK-NEXT: %11 = load i32, ptr %x6, align 4 +// CHECK-NEXT: %12 = load i32, ptr %y10, align 4 +// CHECK-NEXT: %add11 = add nsw i32 %11, %12 +// CHECK-NEXT: %13 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add12 = add nsw i32 %13, %add11 +// CHECK-NEXT: store i32 %add12, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next13 +// CHECK: expand.next13: +// CHECK-NEXT: %14 = load i32, ptr getelementptr inbounds (i32, ptr @_ZZ2f4vE1b, i64 1), align 4 +// CHECK-NEXT: store i32 %14, ptr %y14, align 4 +// CHECK-NEXT: %15 = load i32, ptr %x6, align 4 +// CHECK-NEXT: %16 = load i32, ptr %y14, align 4 +// CHECK-NEXT: %add15 = add nsw i32 %15, %16 +// CHECK-NEXT: %17 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add16 = add nsw i32 %17, %add15 +// CHECK-NEXT: store i32 %add16, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end17 +// CHECK: expand.end17: +// CHECK-NEXT: br label %expand.end18 +// CHECK: expand.end18: +// CHECK-NEXT: store ptr @_ZZ2f4vE1a, ptr %__range119, align 8 +// CHECK-NEXT: store ptr @_ZZ2f4vE1a, ptr %__begin120, align 8 +// CHECK-NEXT: store ptr getelementptr (i8, ptr @_ZZ2f4vE1a, i64 8), ptr %__end121, align 8 +// CHECK-NEXT: store i32 1, ptr %x22, align 4 +// CHECK-NEXT: store ptr @_ZZ2f4vE1b, ptr %__range223, align 8 +// CHECK-NEXT: store ptr @_ZZ2f4vE1b, ptr %__begin224, align 8 +// CHECK-NEXT: store ptr getelementptr (i8, ptr @_ZZ2f4vE1b, i64 8), ptr %__end225, align 8 +// CHECK-NEXT: store i32 3, ptr %y26, align 4 +// CHECK-NEXT: %18 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add27 = add nsw i32 %18, 4 +// CHECK-NEXT: store i32 %add27, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next28 +// CHECK: expand.next28: +// CHECK-NEXT: store i32 4, ptr %y29, align 4 +// CHECK-NEXT: %19 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add30 = add nsw i32 %19, 5 +// CHECK-NEXT: store i32 %add30, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end31 +// CHECK: expand.end31: +// CHECK-NEXT: br label %expand.next32 +// CHECK: expand.next32: +// CHECK-NEXT: store i32 2, ptr %x33, align 4 +// CHECK-NEXT: store ptr @_ZZ2f4vE1b, ptr %__range234, align 8 +// CHECK-NEXT: store ptr @_ZZ2f4vE1b, ptr %__begin235, align 8 +// CHECK-NEXT: store ptr getelementptr (i8, ptr @_ZZ2f4vE1b, i64 8), ptr %__end236, align 8 +// CHECK-NEXT: store i32 3, ptr %y37, align 4 +// CHECK-NEXT: %20 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add38 = add nsw i32 %20, 5 +// CHECK-NEXT: store i32 %add38, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next39 +// CHECK: expand.next39: +// CHECK-NEXT: store i32 4, ptr %y40, align 4 +// CHECK-NEXT: %21 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add41 = add nsw i32 %21, 6 +// CHECK-NEXT: store i32 %add41, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end42 +// CHECK: expand.end42: +// CHECK-NEXT: br label %expand.end43 +// CHECK: expand.end43: +// CHECK-NEXT: %22 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %22 + + +// CHECK-LABEL: define {{.*}} i32 @_ZN7Private11member_funcEv() +// CHECK: entry: +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %__range1 = alloca ptr, align 8 +// CHECK-NEXT: %__begin1 = alloca ptr, align 8 +// CHECK-NEXT: %__end1 = alloca ptr, align 8 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK-NEXT: %x1 = alloca i32, align 4 +// CHECK-NEXT: %x4 = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: store ptr @_ZZN7Private11member_funcEvE2p1, ptr %__range1, align 8 +// CHECK-NEXT: store ptr @_ZN7Private8integersE, ptr %__begin1, align 8 +// CHECK-NEXT: store ptr getelementptr (i8, ptr @_ZN7Private8integersE, i64 12), ptr %__end1, align 8 +// CHECK-NEXT: %0 = load i32, ptr @_ZN7Private8integersE, align 4 +// CHECK-NEXT: store i32 %0, ptr %x, align 4 +// CHECK-NEXT: %1 = load i32, ptr %x, align 4 +// CHECK-NEXT: %2 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %2, %1 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: %3 = load i32, ptr getelementptr inbounds (i32, ptr @_ZN7Private8integersE, i64 1), align 4 +// CHECK-NEXT: store i32 %3, ptr %x1, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x1, align 4 +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add2 = add nsw i32 %5, %4 +// CHECK-NEXT: store i32 %add2, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next3 +// CHECK: expand.next3: +// CHECK-NEXT: %6 = load i32, ptr getelementptr inbounds (i32, ptr @_ZN7Private8integersE, i64 2), align 4 +// CHECK-NEXT: store i32 %6, ptr %x4, align 4 +// CHECK-NEXT: %7 = load i32, ptr %x4, align 4 +// CHECK-NEXT: %8 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add5 = add nsw i32 %8, %7 +// CHECK-NEXT: store i32 %add5, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: %9 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %9 + + +// CHECK-LABEL: define {{.*}} i32 @_Z15custom_iteratorv() +// CHECK: entry: +// CHECK-NEXT: %sum = alloca i32, align 4 +// CHECK-NEXT: %__range1 = alloca ptr, align 8 +// CHECK: %__begin1 = alloca %"struct.CustomIterator::iterator", align 4 +// CHECK: %__end1 = alloca %"struct.CustomIterator::iterator", align 4 +// CHECK-NEXT: %x = alloca i32, align 4 +// CHECK: %ref.tmp = alloca %"struct.CustomIterator::iterator", align 4 +// CHECK-NEXT: %x2 = alloca i32, align 4 +// CHECK: %ref.tmp3 = alloca %"struct.CustomIterator::iterator", align 4 +// CHECK-NEXT: %x9 = alloca i32, align 4 +// CHECK: %ref.tmp10 = alloca %"struct.CustomIterator::iterator", align 4 +// CHECK-NEXT: %x16 = alloca i32, align 4 +// CHECK: %ref.tmp17 = alloca %"struct.CustomIterator::iterator", align 4 +// CHECK-NEXT: %__range122 = alloca ptr, align 8 +// CHECK: %__begin123 = alloca %"struct.CustomIterator::iterator", align 4 +// CHECK: %__end124 = alloca %"struct.CustomIterator::iterator", align 4 +// CHECK-NEXT: %x25 = alloca i32, align 4 +// CHECK-NEXT: %x28 = alloca i32, align 4 +// CHECK-NEXT: %x31 = alloca i32, align 4 +// CHECK-NEXT: %x34 = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr %sum, align 4 +// CHECK-NEXT: store ptr @_ZZ15custom_iteratorvE1c, ptr %__range1, align 8 +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %__begin1, ptr align 4 @__const._Z15custom_iteratorv.__begin1, i64 4, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %__end1, ptr align 4 @__const._Z15custom_iteratorv.__end1, i64 4, i1 false) +// CHECK-NEXT: %call = call i32 @_ZNK14CustomIterator8iteratorplEi(ptr {{.*}} %__begin1, i32 {{.*}} 0) +// CHECK: %coerce.dive = getelementptr inbounds nuw %"struct.CustomIterator::iterator", ptr %ref.tmp, i32 0, i32 0 +// CHECK-NEXT: store i32 %call, ptr %coerce.dive, align 4 +// CHECK-NEXT: %call1 = call {{.*}} i32 @_ZNK14CustomIterator8iteratordeEv(ptr {{.*}} %ref.tmp) +// CHECK-NEXT: store i32 %call1, ptr %x, align 4 +// CHECK-NEXT: %0 = load i32, ptr %x, align 4 +// CHECK-NEXT: %1 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add = add nsw i32 %1, %0 +// CHECK-NEXT: store i32 %add, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next +// CHECK: expand.next: +// CHECK-NEXT: %call4 = call i32 @_ZNK14CustomIterator8iteratorplEi(ptr {{.*}} %__begin1, i32 {{.*}} 1) +// CHECK: %coerce.dive5 = getelementptr inbounds nuw %"struct.CustomIterator::iterator", ptr %ref.tmp3, i32 0, i32 0 +// CHECK-NEXT: store i32 %call4, ptr %coerce.dive5, align 4 +// CHECK-NEXT: %call6 = call {{.*}} i32 @_ZNK14CustomIterator8iteratordeEv(ptr {{.*}} %ref.tmp3) +// CHECK-NEXT: store i32 %call6, ptr %x2, align 4 +// CHECK-NEXT: %2 = load i32, ptr %x2, align 4 +// CHECK-NEXT: %3 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add7 = add nsw i32 %3, %2 +// CHECK-NEXT: store i32 %add7, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next8 +// CHECK: expand.next8: +// CHECK-NEXT: %call11 = call i32 @_ZNK14CustomIterator8iteratorplEi(ptr {{.*}} %__begin1, i32 {{.*}} 2) +// CHECK: %coerce.dive12 = getelementptr inbounds nuw %"struct.CustomIterator::iterator", ptr %ref.tmp10, i32 0, i32 0 +// CHECK-NEXT: store i32 %call11, ptr %coerce.dive12, align 4 +// CHECK-NEXT: %call13 = call {{.*}} i32 @_ZNK14CustomIterator8iteratordeEv(ptr {{.*}} %ref.tmp10) +// CHECK-NEXT: store i32 %call13, ptr %x9, align 4 +// CHECK-NEXT: %4 = load i32, ptr %x9, align 4 +// CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add14 = add nsw i32 %5, %4 +// CHECK-NEXT: store i32 %add14, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next15 +// CHECK: expand.next15: +// CHECK-NEXT: %call18 = call i32 @_ZNK14CustomIterator8iteratorplEi(ptr {{.*}} %__begin1, i32 {{.*}} 3) +// CHECK: %coerce.dive19 = getelementptr inbounds nuw %"struct.CustomIterator::iterator", ptr %ref.tmp17, i32 0, i32 0 +// CHECK-NEXT: store i32 %call18, ptr %coerce.dive19, align 4 +// CHECK-NEXT: %call20 = call {{.*}} i32 @_ZNK14CustomIterator8iteratordeEv(ptr {{.*}} %ref.tmp17) +// CHECK-NEXT: store i32 %call20, ptr %x16, align 4 +// CHECK-NEXT: %6 = load i32, ptr %x16, align 4 +// CHECK-NEXT: %7 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add21 = add nsw i32 %7, %6 +// CHECK-NEXT: store i32 %add21, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end +// CHECK: expand.end: +// CHECK-NEXT: store ptr @_ZZ15custom_iteratorvE1c, ptr %__range122, align 8 +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %__begin123, ptr align 4 @__const._Z15custom_iteratorv.__begin1.1, i64 4, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %__end124, ptr align 4 @__const._Z15custom_iteratorv.__end1.2, i64 4, i1 false) +// CHECK-NEXT: store i32 1, ptr %x25, align 4 +// CHECK-NEXT: %8 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add26 = add nsw i32 %8, 1 +// CHECK-NEXT: store i32 %add26, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next27 +// CHECK: expand.next27: +// CHECK-NEXT: store i32 2, ptr %x28, align 4 +// CHECK-NEXT: %9 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add29 = add nsw i32 %9, 2 +// CHECK-NEXT: store i32 %add29, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next30 +// CHECK: expand.next30: +// CHECK-NEXT: store i32 3, ptr %x31, align 4 +// CHECK-NEXT: %10 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add32 = add nsw i32 %10, 3 +// CHECK-NEXT: store i32 %add32, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.next33 +// CHECK: expand.next33: +// CHECK-NEXT: store i32 4, ptr %x34, align 4 +// CHECK-NEXT: %11 = load i32, ptr %sum, align 4 +// CHECK-NEXT: %add35 = add nsw i32 %11, 4 +// CHECK-NEXT: store i32 %add35, ptr %sum, align 4 +// CHECK-NEXT: br label %expand.end36 +// CHECK: expand.end36: +// CHECK-NEXT: %12 = load i32, ptr %sum, align 4 +// CHECK-NEXT: ret i32 %12 From 89aec47918738f83b6c0a3f8b6e3ae6c4b5b97e6 Mon Sep 17 00:00:00 2001 From: Sirraide Date: Wed, 26 Nov 2025 19:04:08 +0100 Subject: [PATCH 2/2] Move CGDecl implementation here --- clang/lib/CodeGen/CGDecl.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 7c96e38908267..678d2e9fa743a 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -143,8 +143,12 @@ void CodeGenFunction::EmitDecl(const Decl &D, bool EvaluateConditionDecl) { // None of these decls require codegen support. return; - case Decl::CXXExpansionStmt: - llvm_unreachable("TODO"); + case Decl::CXXExpansionStmt: { + const auto *ESD = cast(&D); + assert(ESD->getInstantiations() && "expansion statement not expanded?"); + EmitStmt(ESD->getInstantiations()); + return; + } case Decl::NamespaceAlias: if (CGDebugInfo *DI = getDebugInfo())