llvm/clang/test/OpenMP/scan_codegen.cpp

// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s

// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s
// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s
// SIMD-ONLY0-NOT: {{__kmpc|__tgt}}
//
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
void foo();
void bar();

// CHECK-LABEL: baz
void baz() {
  int a = 0;

  // CHECK: store i32 0, ptr [[A_ADDR:%.+]],
  // CHECK: store i32 0, ptr [[OMP_CNT:%.+]],
  // CHECK: br label %[[OMP_HEADER:.+]]

  // CHECK: [[OMP_HEADER]]:
  // CHECK: [[CNT_VAL:%.+]] = load i32, ptr [[OMP_CNT]],
  // CHECK: [[CMP:%.+]] = icmp slt i32 [[CNT_VAL]], 10
  // CHECK: br i1 [[CMP]], label %[[OMP_BODY:.+]], label %[[OMP_END:.+]]
#pragma omp simd reduction(inscan, + : a)
  for (int i = 0; i < 10; ++i) {
    // CHECK: [[OMP_BODY]]:

    // i = OMP_CNT*1 + 0;
    // CHECK: [[CNT_VAL:%.+]] = load i32, ptr [[OMP_CNT]],
    // CHECK: [[MUL:%.+]] = mul nsw i32 [[CNT_VAL]], 1
    // CHECK: [[ADD:%.+]] = add nsw i32 0, [[MUL]]
    // CHECK: store i32 [[ADD]], ptr [[I_ADDR:%.+]],

    // A_PRIV = 0;
    // CHECK: store i32 0, ptr [[A_PRIV_ADDR:%.+]],

    // goto DISPATCH;
    // CHECK: br label %[[DISPATCH:[^,]+]]

    // INPUT_PHASE:
    // foo();
    // goto REDUCE;
    // CHECK: [[INPUT_PHASE:.+]]:
    // CHECK: call void @{{.*}}foo{{.*}}()
    // CHECK: br label %[[REDUCE:[^,]+]]
    foo();

    // DISPATCH:
    // goto INPUT_PHASE;
    // CHECK: [[DISPATCH]]:
    // CHECK: br label %[[INPUT_PHASE]]

    // REDUCE:
    // A = A_PRIV + A;
    // A_PRIV = A;
    // goto SCAN_PHASE;
    // CHECK: [[REDUCE]]:
    // CHECK: [[A:%.+]] = load i32, ptr [[A_ADDR]],
    // CHECK: [[A_PRIV:%.+]] = load i32, ptr [[A_PRIV_ADDR]],
    // CHECK: [[SUM:%.+]] = add nsw i32 [[A]], [[A_PRIV]]
    // CHECK: store i32 [[SUM]], ptr [[A_ADDR]],
    // CHECK: [[A:%.+]] = load i32, ptr [[A_ADDR]],
    // CHECK: store i32 [[A]], ptr [[A_PRIV_ADDR]],
    // CHECK: br label %[[SCAN_PHASE:[^,]+]]
#pragma omp scan inclusive(a)

    // SCAN_PHASE:
    // bar();
    // goto CONTINUE;
    // CHECK: [[SCAN_PHASE]]:
    // CHECK: call void @{{.*}}bar{{.*}}()
    // CHECK: br label %[[CONTINUE:[^,]+]]
    bar();

    // CHECK: [[CONTINUE]]:
    // CHECK: br label %[[INC_BLOCK:[^,]+]]

    // ++OMP_CNT;
    // CHECK: [[INC_BLOCK]]:
    // CHECK: [[CNT:%.+]] = load i32, ptr [[OMP_CNT]],
    // CHECK: [[INC:%.+]] = add nsw i32 [[CNT]], 1
    // CHECK: store i32 [[INC]], ptr [[OMP_CNT]],
    // CHECK: br label %[[OMP_HEADER]]
  }
  // CHECK: [[OMP_END]]:
}

struct S {
  int a;
  S() {}
  ~S() {}
  S& operator+(const S&);
  S& operator=(const S&);
};

// CHECK-LABEL: xyz
void xyz() {
  S s[2];

  // CHECK: [[S_BEGIN:%.+]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ADDR:%.+]], i{{.+}} 0, i{{.+}} 0
  // CHECK: [[S_END:%.+]] = getelementptr {{.*}}%struct.S, ptr [[S_BEGIN]], i{{.+}} 2
  // CHECK: br label %[[ARRAY_INIT:.+]]
  // CHECK: [[ARRAY_INIT]]:
  // CHECK: [[S_CUR:%.+]] = phi ptr [ [[S_BEGIN]], %{{.+}} ], [ [[S_NEXT:%.+]], %[[ARRAY_INIT]] ]
  // CHECK: call void [[CONSTR:@.+]](ptr {{[^,]*}} [[S_CUR]])
  // CHECK: [[S_NEXT]] = getelementptr inbounds %struct.S, ptr [[S_CUR]], i{{.+}} 1
  // CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[S_NEXT]], [[S_END]]
  // CHECK: br i1 [[IS_DONE]], label %[[DONE:.+]], label %[[ARRAY_INIT]]
  // CHECK: [[DONE]]:
  // CHECK: store i32 0, ptr [[OMP_CNT:%.+]],
  // CHECK: br label %[[OMP_HEADER:.+]]

  // CHECK: [[OMP_HEADER]]:
  // CHECK: [[CNT_VAL:%.+]] = load i32, ptr [[OMP_CNT]],
  // CHECK: [[CMP:%.+]] = icmp slt i32 [[CNT_VAL]], 10
  // CHECK: br i1 [[CMP]], label %[[OMP_BODY:.+]], label %[[OMP_END:.+]]
#pragma omp simd reduction(inscan, + : s)
  for (int i = 0; i < 10; ++i) {
    // CHECK: [[OMP_BODY]]:

    // i = OMP_CNT*1 + 0;
    // CHECK: [[CNT_VAL:%.+]] = load i32, ptr [[OMP_CNT]],
    // CHECK: [[MUL:%.+]] = mul nsw i32 [[CNT_VAL]], 1
    // CHECK: [[ADD:%.+]] = add nsw i32 0, [[MUL]]
    // CHECK: store i32 [[ADD]], ptr [[I_ADDR:%.+]],

    // S S_PRIV[2];
    // CHECK: [[S_BEGIN:%.+]] = getelementptr inbounds [2 x %struct.S], ptr [[S_PRIV_ADDR:%.+]], i{{.+}} 0, i{{.+}} 0
    // CHECK: [[S_END:%.+]] = getelementptr {{.*}}%struct.S, ptr [[S_BEGIN]], i{{.+}} 2
    // CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[S_BEGIN]], [[S_END]]
    // CHECK: br i1 [[IS_DONE]], label %[[DONE:.+]], label %[[ARRAY_INIT:[^,]+]]
    // CHECK: [[ARRAY_INIT]]:
    // CHECK: [[S_CUR:%.+]] = phi ptr [ [[S_BEGIN]], %[[OMP_BODY]] ], [ [[S_NEXT:%.+]], %[[ARRAY_INIT]] ]
    // CHECK: call void [[CONSTR]](ptr {{[^,]*}} [[S_CUR]])
    // CHECK: [[S_NEXT]] = getelementptr {{.*}}%struct.S, ptr [[S_CUR]], i{{.+}} 1
    // CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[S_NEXT]], [[S_END]]
    // CHECK: br i1 [[IS_DONE]], label %[[DONE:.+]], label %[[ARRAY_INIT]]
    // CHECK: [[DONE]]:

    // goto DISPATCH;
    // CHECK: br label %[[DISPATCH:[^,]+]]

    // SCAN_PHASE:
    // foo();
    // goto CONTINUE;
    // CHECK: [[SCAN_PHASE:.+]]:
    // CHECK: call void @{{.*}}foo{{.*}}()
    // CHECK: br label %[[CONTINUE:[^,]+]]
    foo();

    // DISPATCH:
    // goto INPUT_PHASE;
    // CHECK: [[DISPATCH]]:
    // CHECK: br label %[[INPUT_PHASE:[^,]+]]

    // REDUCE:
    // TEMP = S;
    // S = S_PRIV + S;
    // S_PRIV = TEMP;
    // goto SCAN_PHASE;
    // CHECK: [[REDUCE:.+]]:

    // S TEMP[2];
    // CHECK: [[TEMP_ARR_BEG:%.+]] = getelementptr inbounds [2 x %struct.S], ptr [[TEMP_ARR:%.+]], i32 0, i32 0
    // CHECK: [[TEMP_ARR_END:%.+]] = getelementptr inbounds %struct.S, ptr [[TEMP_ARR_BEG]], i64 2
    // CHECK: br label %[[BODY:[^,]+]]
    // CHECK: [[BODY]]:
    // CHECK: [[CUR:%.+]] = phi ptr [ [[TEMP_ARR_BEG]], %[[REDUCE]] ], [ [[NEXT:%.+]], %[[BODY]] ]
    // CHECK: call void [[CONSTR]](ptr {{[^,]*}} [[CUR]])
    // CHECK: [[NEXT]] = getelementptr inbounds %struct.S, ptr [[CUR]], i64 1
    // CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[NEXT]], [[TEMP_ARR_END]]
    // CHECK: br i1 [[IS_DONE]], label %[[EXIT:[^,]+]], label %[[BODY]]
    // CHECK: [[EXIT]]:

    // TEMP = S;
    // CHECK: [[TEMP_ARR_BEG:%.+]] = getelementptr inbounds [2 x %struct.S], ptr [[TEMP_ARR]], i32 0, i32 0
    // CHECK: [[TEMP_ARR_END:%.+]] = getelementptr inbounds %struct.S, ptr [[TEMP_ARR_BEG]], i64 2
    // CHECK: [[IS_EMPTY:%.+]] = icmp eq ptr [[TEMP_ARR_BEG]], [[TEMP_ARR_END]]
    // CHECK: br i1 [[IS_EMPTY]], label %[[EXIT:[^,]+]], label %[[BODY:[^,]+]]
    // CHECK: [[BODY]]:
    // CHECK: [[CUR_SRC:%.+]] = phi ptr [ [[S_ADDR]], %{{.+}} ], [ [[SRC_NEXT:%.+]], %[[BODY]] ]
    // CHECK: [[CUR_DEST:%.+]] = phi ptr [ [[TEMP_ARR_BEG]], %{{.+}} ], [ [[DEST_NEXT:%.+]], %[[BODY]] ]
    // CHECK: call {{.*}}ptr [[S_COPY:@.+]](ptr {{[^,]*}} [[CUR_DEST]], ptr {{.*}}[[CUR_SRC]])
    // CHECK: [[DEST_NEXT:%.+]] = getelementptr %struct.S, ptr [[CUR_DEST]], i32 1
    // CHECK: [[SRC_NEXT:%.+]] = getelementptr %struct.S, ptr [[CUR_SRC]], i32 1
    // CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[DEST_NEXT]], [[TEMP_ARR_END]]
    // CHECK: br i1 [[IS_DONE]], label %[[EXIT]], label %[[BODY]]
    // CHECK: [[EXIT]]:

    // S = S_PRIV + S;
    // CHECK: [[LHS_END:%.+]] = getelementptr {{.*}}%struct.S, ptr [[S_ADDR]], i{{.+}} 2
    // CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[S_ADDR]], [[LHS_END]]
    // CHECK: br i1 [[IS_DONE]], label %[[DONE:.+]], label %[[ARRAY_REDUCE_COPY:[^,]+]]
    // CHECK: [[ARRAY_REDUCE_COPY]]:
    // CHECK: [[SRC_CUR:%.+]] = phi ptr [ [[S_PRIV_ADDR]], %[[EXIT]] ], [ [[SRC_NEXT:%.+]], %[[ARRAY_REDUCE_COPY]] ]
    // CHECK: [[DEST_CUR:%.+]] = phi ptr [ [[S_ADDR]], %[[EXIT]] ], [ [[DEST_NEXT:%.+]], %[[ARRAY_REDUCE_COPY]] ]
    // CHECK: [[SUM:%.+]] = call {{.*}}ptr @{{.+}}(ptr {{[^,]*}} [[DEST_CUR]], ptr {{.*}}[[SRC_CUR]])
    // CHECK: call {{.*}}ptr [[S_COPY]](ptr {{[^,]*}} [[DEST_CUR]], ptr {{.*}}[[SUM]])
    // CHECK: [[DEST_NEXT]] = getelementptr {{.*}}%struct.S, ptr [[DEST_CUR]], i{{.+}} 1
    // CHECK: [[SRC_NEXT]] = getelementptr {{.*}}%struct.S, ptr [[SRC_CUR]], i{{.+}} 1
    // CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[DEST_NEXT]], [[LHS_END]]
    // CHECK: br i1 [[IS_DONE]], label %[[DONE:.+]], label %[[ARRAY_REDUCE_COPY]]
    // CHECK: [[DONE]]:

    // S_PRIV = TEMP;
    // CHECK: [[RHS_END:%.+]] = getelementptr inbounds %struct.S, ptr [[S_PRIV_ADDR]], i64 2
    // CHECK: [[IS_EMPTY:%.+]] = icmp eq ptr [[S_PRIV_ADDR]], [[RHS_END]]
    // CHECK: br i1 [[IS_EMPTY]], label %[[EXIT:[^,]+]], label %[[BODY:[^,]+]]
    // CHECK: [[BODY]]:
    // CHECK: [[CUR_SRC:%.+]] = phi ptr [ [[TEMP_ARR]], %[[DONE]] ], [ [[SRC_NEXT:%.+]], %[[BODY]] ]
    // CHECK: [[CUR_DEST:%.+]] = phi ptr [ [[S_PRIV_ADDR]], %[[DONE]] ], [ [[DEST_NEXT:%.+]], %[[BODY]] ]
    // CHECK: call {{.*}}ptr [[S_COPY]](ptr {{[^,]*}} [[CUR_DEST]], ptr {{.*}}[[CUR_SRC]])
    // CHECK: [[DEST_NEXT]] = getelementptr %struct.S, ptr [[CUR_DEST]], i32 1
    // CHECK: [[SRC_NEXT]] = getelementptr %struct.S, ptr [[CUR_SRC]], i32 1
    // CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[DEST_NEXT]], [[RHS_END]]
    // CHECK: br i1 [[IS_DONE]], label %[[DONE:[^,]+]], label %[[BODY]]
    // CHECK: [[DONE]]:

    // TEMP.~S()
    // CHECK: [[TEMP_ARR_BEG:%.+]] = getelementptr inbounds [2 x %struct.S], ptr [[TEMP_ARR]], i32 0, i32 0
    // CHECK: [[TEMP_ARR_END:%.+]] = getelementptr inbounds %struct.S, ptr [[TEMP_ARR_BEG]], i64 2
    // CHECK: br label %[[BODY:[^,]+]]
    // CHECK: [[BODY]]:
    // CHECK: [[CUR:%.+]] = phi ptr [ [[TEMP_ARR_END]], %[[DONE]] ], [ [[PREV:%.+]], %[[BODY]] ]
    // CHECK: [[PREV]] = getelementptr inbounds %struct.S, ptr [[CUR]], i64 -1
    // CHECK: call void [[DESTR:@.+]](ptr {{[^,]*}} [[PREV]])
    // CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[PREV]], [[TEMP_ARR_BEG]]
    // CHECK: br i1 [[IS_DONE]], label %[[EXIT:[^,]+]], label %[[BODY]]
    // CHECK: [[EXIT]]:

    // goto SCAN_PHASE;
    // CHECK: br label %[[SCAN_PHASE]]
#pragma omp scan exclusive(s)

    // INPUT_PHASE:
    // bar();
    // goto REDUCE;
    // CHECK: [[INPUT_PHASE]]:
    // CHECK: call void @{{.*}}bar{{.*}}()
    // CHECK: br label %[[REDUCE]]
    bar();

    // CHECK: [[CONTINUE]]:

    // S_PRIV[2].~S();
    // CHECK: [[S_BEGIN:%.+]] = getelementptr inbounds [2 x %struct.S], ptr [[S_PRIV_ADDR]], i{{.+}} 0, i{{.+}} 0
    // CHECK: [[S_END:%.+]] = getelementptr {{.*}}%struct.S, ptr [[S_BEGIN]], i{{.+}} 2
    // CHECK: br label %[[ARRAY_DESTR:[^,]+]]
    // CHECK: [[ARRAY_DESTR]]:
    // CHECK: [[S_CUR:%.+]] = phi ptr [ [[S_END]], %[[CONTINUE]] ], [ [[S_PREV:%.+]], %[[ARRAY_DESTR]] ]
    // CHECK: [[S_PREV]] = getelementptr {{.*}}%struct.S, ptr [[S_CUR]], i{{.+}} -1
    // CHECK: call void [[DESTR]](ptr {{[^,]*}} [[S_PREV]])
    // CHECK: [[IS_DONE:%.+]] = icmp eq ptr [[S_PREV]], [[S_BEGIN]]
    // CHECK: br i1 [[IS_DONE]], label %[[DONE:.+]], label %[[ARRAY_DESTR]]
    // CHECK: [[DONE]]:
    // CHECK: br label %[[INC_BLOCK:[^,]+]]

    // ++OMP_CNT;
    // CHECK: [[INC_BLOCK]]:
    // CHECK: [[CNT:%.+]] = load i32, ptr [[OMP_CNT]],
    // CHECK: [[INC:%.+]] = add nsw i32 [[CNT]], 1
    // CHECK: store i32 [[INC]], ptr [[OMP_CNT]],
    // CHECK: br label %[[OMP_HEADER]]
  }
  // CHECK: [[OMP_END]]:
}

// CHECK-NOT: !{!"llvm.loop.parallel_accesses"

#endif // HEADER