diff --git a/clang/test/utils/update_cc_test_checks/Inputs/generated-funcs.c b/clang/test/utils/update_cc_test_checks/Inputs/generated-funcs.c new file mode 100644 --- /dev/null +++ b/clang/test/utils/update_cc_test_checks/Inputs/generated-funcs.c @@ -0,0 +1,31 @@ +// Check that the CHECK lines are generated for clang-generated functions +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fopenmp %s -emit-llvm -o - | FileCheck --check-prefix=OMP %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck --check-prefix=NOOMP %s + +const int size = 1024 * 1024 * 32; + +double A[size]; + +void foo(void); + +int main() { + int i = 0; + +#pragma omp parallel for + for (i = 0; i < size; ++i) { + A[i] = 0.0; + } + + foo(); + + return 0; +} + +void foo(void) { + int i = 0; + +#pragma omp parallel for + for (i = 0; i < size; ++i) { + A[i] = 1.0; + } +} diff --git a/clang/test/utils/update_cc_test_checks/Inputs/generated-funcs.c.generated.expected b/clang/test/utils/update_cc_test_checks/Inputs/generated-funcs.c.generated.expected new file mode 100644 --- /dev/null +++ b/clang/test/utils/update_cc_test_checks/Inputs/generated-funcs.c.generated.expected @@ -0,0 +1,229 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// Check that the CHECK lines are generated for clang-generated functions +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fopenmp %s -emit-llvm -o - | FileCheck --check-prefix=OMP %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck --check-prefix=NOOMP %s + +const int size = 1024 * 1024 * 32; + +double A[size]; + +void foo(void); + +int main() { + int i = 0; + +#pragma omp parallel for + for (i = 0; i < size; ++i) { + A[i] = 0.0; + } + + foo(); + + return 0; +} + +void foo(void) { + int i = 0; + +#pragma omp parallel for + for (i = 0; i < size; ++i) { + A[i] = 1.0; + } +} +// OMP-LABEL: @foo( +// OMP-NEXT: entry: +// OMP-NEXT: [[I:%.*]] = alloca i32, align 4 +// OMP-NEXT: store i32 0, i32* [[I]], align 4 +// OMP-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* @1, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined. to void (i32*, i32*, ...)*)) +// OMP-NEXT: ret void +// +// +// OMP-LABEL: @.omp_outlined.( +// OMP-NEXT: entry: +// OMP-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca i32*, align 8 +// OMP-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca i32*, align 8 +// OMP-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[TMP:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[I:%.*]] = alloca i32, align 4 +// OMP-NEXT: store i32* [[DOTGLOBAL_TID_:%.*]], i32** [[DOTGLOBAL_TID__ADDR]], align 8 +// OMP-NEXT: store i32* [[DOTBOUND_TID_:%.*]], i32** [[DOTBOUND_TID__ADDR]], align 8 +// OMP-NEXT: store i32 0, i32* [[DOTOMP_LB]], align 4 +// OMP-NEXT: store i32 33554431, i32* [[DOTOMP_UB]], align 4 +// OMP-NEXT: store i32 1, i32* [[DOTOMP_STRIDE]], align 4 +// OMP-NEXT: store i32 0, i32* [[DOTOMP_IS_LAST]], align 4 +// OMP-NEXT: [[TMP0:%.*]] = load i32*, i32** [[DOTGLOBAL_TID__ADDR]], align 8 +// OMP-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4 +// OMP-NEXT: call void @__kmpc_for_static_init_4(%struct.ident_t* @0, i32 [[TMP1]], i32 34, i32* [[DOTOMP_IS_LAST]], i32* [[DOTOMP_LB]], i32* [[DOTOMP_UB]], i32* [[DOTOMP_STRIDE]], i32 1, i32 1) +// OMP-NEXT: [[TMP2:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4 +// OMP-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP2]], 33554431 +// OMP-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +// OMP: cond.true: +// OMP-NEXT: br label [[COND_END:%.*]] +// OMP: cond.false: +// OMP-NEXT: [[TMP3:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4 +// OMP-NEXT: br label [[COND_END]] +// OMP: cond.end: +// OMP-NEXT: [[COND:%.*]] = phi i32 [ 33554431, [[COND_TRUE]] ], [ [[TMP3]], [[COND_FALSE]] ] +// OMP-NEXT: store i32 [[COND]], i32* [[DOTOMP_UB]], align 4 +// OMP-NEXT: [[TMP4:%.*]] = load i32, i32* [[DOTOMP_LB]], align 4 +// OMP-NEXT: store i32 [[TMP4]], i32* [[DOTOMP_IV]], align 4 +// OMP-NEXT: br label [[OMP_INNER_FOR_COND:%.*]] +// OMP: omp.inner.for.cond: +// OMP-NEXT: [[TMP5:%.*]] = load i32, i32* [[DOTOMP_IV]], align 4 +// OMP-NEXT: [[TMP6:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4 +// OMP-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]] +// OMP-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]] +// OMP: omp.inner.for.body: +// OMP-NEXT: [[TMP7:%.*]] = load i32, i32* [[DOTOMP_IV]], align 4 +// OMP-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1 +// OMP-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]] +// OMP-NEXT: store i32 [[ADD]], i32* [[I]], align 4 +// OMP-NEXT: [[TMP8:%.*]] = load i32, i32* [[I]], align 4 +// OMP-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP8]] to i64 +// OMP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [33554432 x double], [33554432 x double]* @A, i64 0, i64 [[IDXPROM]] +// OMP-NEXT: store double 1.000000e+00, double* [[ARRAYIDX]], align 8 +// OMP-NEXT: br label [[OMP_BODY_CONTINUE:%.*]] +// OMP: omp.body.continue: +// OMP-NEXT: br label [[OMP_INNER_FOR_INC:%.*]] +// OMP: omp.inner.for.inc: +// OMP-NEXT: [[TMP9:%.*]] = load i32, i32* [[DOTOMP_IV]], align 4 +// OMP-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP9]], 1 +// OMP-NEXT: store i32 [[ADD2]], i32* [[DOTOMP_IV]], align 4 +// OMP-NEXT: br label [[OMP_INNER_FOR_COND]] +// OMP: omp.inner.for.end: +// OMP-NEXT: br label [[OMP_LOOP_EXIT:%.*]] +// OMP: omp.loop.exit: +// OMP-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* @0, i32 [[TMP1]]) +// OMP-NEXT: ret void +// +// +// OMP-LABEL: @main( +// OMP-NEXT: entry: +// OMP-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[I:%.*]] = alloca i32, align 4 +// OMP-NEXT: store i32 0, i32* [[RETVAL]], align 4 +// OMP-NEXT: store i32 0, i32* [[I]], align 4 +// OMP-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* @1, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined..1 to void (i32*, i32*, ...)*)) +// OMP-NEXT: call void @foo() +// OMP-NEXT: ret i32 0 +// +// +// OMP-LABEL: @.omp_outlined..1( +// OMP-NEXT: entry: +// OMP-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca i32*, align 8 +// OMP-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca i32*, align 8 +// OMP-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[TMP:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[I:%.*]] = alloca i32, align 4 +// OMP-NEXT: store i32* [[DOTGLOBAL_TID_:%.*]], i32** [[DOTGLOBAL_TID__ADDR]], align 8 +// OMP-NEXT: store i32* [[DOTBOUND_TID_:%.*]], i32** [[DOTBOUND_TID__ADDR]], align 8 +// OMP-NEXT: store i32 0, i32* [[DOTOMP_LB]], align 4 +// OMP-NEXT: store i32 33554431, i32* [[DOTOMP_UB]], align 4 +// OMP-NEXT: store i32 1, i32* [[DOTOMP_STRIDE]], align 4 +// OMP-NEXT: store i32 0, i32* [[DOTOMP_IS_LAST]], align 4 +// OMP-NEXT: [[TMP0:%.*]] = load i32*, i32** [[DOTGLOBAL_TID__ADDR]], align 8 +// OMP-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4 +// OMP-NEXT: call void @__kmpc_for_static_init_4(%struct.ident_t* @0, i32 [[TMP1]], i32 34, i32* [[DOTOMP_IS_LAST]], i32* [[DOTOMP_LB]], i32* [[DOTOMP_UB]], i32* [[DOTOMP_STRIDE]], i32 1, i32 1) +// OMP-NEXT: [[TMP2:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4 +// OMP-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP2]], 33554431 +// OMP-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +// OMP: cond.true: +// OMP-NEXT: br label [[COND_END:%.*]] +// OMP: cond.false: +// OMP-NEXT: [[TMP3:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4 +// OMP-NEXT: br label [[COND_END]] +// OMP: cond.end: +// OMP-NEXT: [[COND:%.*]] = phi i32 [ 33554431, [[COND_TRUE]] ], [ [[TMP3]], [[COND_FALSE]] ] +// OMP-NEXT: store i32 [[COND]], i32* [[DOTOMP_UB]], align 4 +// OMP-NEXT: [[TMP4:%.*]] = load i32, i32* [[DOTOMP_LB]], align 4 +// OMP-NEXT: store i32 [[TMP4]], i32* [[DOTOMP_IV]], align 4 +// OMP-NEXT: br label [[OMP_INNER_FOR_COND:%.*]] +// OMP: omp.inner.for.cond: +// OMP-NEXT: [[TMP5:%.*]] = load i32, i32* [[DOTOMP_IV]], align 4 +// OMP-NEXT: [[TMP6:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4 +// OMP-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]] +// OMP-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]] +// OMP: omp.inner.for.body: +// OMP-NEXT: [[TMP7:%.*]] = load i32, i32* [[DOTOMP_IV]], align 4 +// OMP-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1 +// OMP-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]] +// OMP-NEXT: store i32 [[ADD]], i32* [[I]], align 4 +// OMP-NEXT: [[TMP8:%.*]] = load i32, i32* [[I]], align 4 +// OMP-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP8]] to i64 +// OMP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [33554432 x double], [33554432 x double]* @A, i64 0, i64 [[IDXPROM]] +// OMP-NEXT: store double 0.000000e+00, double* [[ARRAYIDX]], align 8 +// OMP-NEXT: br label [[OMP_BODY_CONTINUE:%.*]] +// OMP: omp.body.continue: +// OMP-NEXT: br label [[OMP_INNER_FOR_INC:%.*]] +// OMP: omp.inner.for.inc: +// OMP-NEXT: [[TMP9:%.*]] = load i32, i32* [[DOTOMP_IV]], align 4 +// OMP-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP9]], 1 +// OMP-NEXT: store i32 [[ADD2]], i32* [[DOTOMP_IV]], align 4 +// OMP-NEXT: br label [[OMP_INNER_FOR_COND]] +// OMP: omp.inner.for.end: +// OMP-NEXT: br label [[OMP_LOOP_EXIT:%.*]] +// OMP: omp.loop.exit: +// OMP-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* @0, i32 [[TMP1]]) +// OMP-NEXT: ret void +// +// +// NOOMP-LABEL: @main( +// NOOMP-NEXT: entry: +// NOOMP-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// NOOMP-NEXT: [[I:%.*]] = alloca i32, align 4 +// NOOMP-NEXT: store i32 0, i32* [[RETVAL]], align 4 +// NOOMP-NEXT: store i32 0, i32* [[I]], align 4 +// NOOMP-NEXT: store i32 0, i32* [[I]], align 4 +// NOOMP-NEXT: br label [[FOR_COND:%.*]] +// NOOMP: for.cond: +// NOOMP-NEXT: [[TMP0:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP0]], 33554432 +// NOOMP-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// NOOMP: for.body: +// NOOMP-NEXT: [[TMP1:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64 +// NOOMP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [33554432 x double], [33554432 x double]* @A, i64 0, i64 [[IDXPROM]] +// NOOMP-NEXT: store double 0.000000e+00, double* [[ARRAYIDX]], align 8 +// NOOMP-NEXT: br label [[FOR_INC:%.*]] +// NOOMP: for.inc: +// NOOMP-NEXT: [[TMP2:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[INC:%.*]] = add nsw i32 [[TMP2]], 1 +// NOOMP-NEXT: store i32 [[INC]], i32* [[I]], align 4 +// NOOMP-NEXT: br label [[FOR_COND]] +// NOOMP: for.end: +// NOOMP-NEXT: call void @foo() +// NOOMP-NEXT: ret i32 0 +// +// +// NOOMP-LABEL: @foo( +// NOOMP-NEXT: entry: +// NOOMP-NEXT: [[I:%.*]] = alloca i32, align 4 +// NOOMP-NEXT: store i32 0, i32* [[I]], align 4 +// NOOMP-NEXT: store i32 0, i32* [[I]], align 4 +// NOOMP-NEXT: br label [[FOR_COND:%.*]] +// NOOMP: for.cond: +// NOOMP-NEXT: [[TMP0:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP0]], 33554432 +// NOOMP-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// NOOMP: for.body: +// NOOMP-NEXT: [[TMP1:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64 +// NOOMP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [33554432 x double], [33554432 x double]* @A, i64 0, i64 [[IDXPROM]] +// NOOMP-NEXT: store double 1.000000e+00, double* [[ARRAYIDX]], align 8 +// NOOMP-NEXT: br label [[FOR_INC:%.*]] +// NOOMP: for.inc: +// NOOMP-NEXT: [[TMP2:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[INC:%.*]] = add nsw i32 [[TMP2]], 1 +// NOOMP-NEXT: store i32 [[INC]], i32* [[I]], align 4 +// NOOMP-NEXT: br label [[FOR_COND]] +// NOOMP: for.end: +// NOOMP-NEXT: ret void +// diff --git a/clang/test/utils/update_cc_test_checks/Inputs/generated-funcs.c.no-generated.expected b/clang/test/utils/update_cc_test_checks/Inputs/generated-funcs.c.no-generated.expected new file mode 100644 --- /dev/null +++ b/clang/test/utils/update_cc_test_checks/Inputs/generated-funcs.c.no-generated.expected @@ -0,0 +1,100 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// Check that the CHECK lines are generated for clang-generated functions +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fopenmp %s -emit-llvm -o - | FileCheck --check-prefix=OMP %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck --check-prefix=NOOMP %s + +const int size = 1024 * 1024 * 32; + +double A[size]; + +void foo(void); + +// OMP-LABEL: @main( +// OMP-NEXT: entry: +// OMP-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// OMP-NEXT: [[I:%.*]] = alloca i32, align 4 +// OMP-NEXT: store i32 0, i32* [[RETVAL]], align 4 +// OMP-NEXT: store i32 0, i32* [[I]], align 4 +// OMP-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* @1, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined..1 to void (i32*, i32*, ...)*)) +// OMP-NEXT: call void @foo() +// OMP-NEXT: ret i32 0 +// +// NOOMP-LABEL: @main( +// NOOMP-NEXT: entry: +// NOOMP-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// NOOMP-NEXT: [[I:%.*]] = alloca i32, align 4 +// NOOMP-NEXT: store i32 0, i32* [[RETVAL]], align 4 +// NOOMP-NEXT: store i32 0, i32* [[I]], align 4 +// NOOMP-NEXT: store i32 0, i32* [[I]], align 4 +// NOOMP-NEXT: br label [[FOR_COND:%.*]] +// NOOMP: for.cond: +// NOOMP-NEXT: [[TMP0:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP0]], 33554432 +// NOOMP-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// NOOMP: for.body: +// NOOMP-NEXT: [[TMP1:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64 +// NOOMP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [33554432 x double], [33554432 x double]* @A, i64 0, i64 [[IDXPROM]] +// NOOMP-NEXT: store double 0.000000e+00, double* [[ARRAYIDX]], align 8 +// NOOMP-NEXT: br label [[FOR_INC:%.*]] +// NOOMP: for.inc: +// NOOMP-NEXT: [[TMP2:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[INC:%.*]] = add nsw i32 [[TMP2]], 1 +// NOOMP-NEXT: store i32 [[INC]], i32* [[I]], align 4 +// NOOMP-NEXT: br label [[FOR_COND]] +// NOOMP: for.end: +// NOOMP-NEXT: call void @foo() +// NOOMP-NEXT: ret i32 0 +// +int main() { + int i = 0; + +#pragma omp parallel for + for (i = 0; i < size; ++i) { + A[i] = 0.0; + } + + foo(); + + return 0; +} + +// OMP-LABEL: @foo( +// OMP-NEXT: entry: +// OMP-NEXT: [[I:%.*]] = alloca i32, align 4 +// OMP-NEXT: store i32 0, i32* [[I]], align 4 +// OMP-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* @1, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined. to void (i32*, i32*, ...)*)) +// OMP-NEXT: ret void +// +// NOOMP-LABEL: @foo( +// NOOMP-NEXT: entry: +// NOOMP-NEXT: [[I:%.*]] = alloca i32, align 4 +// NOOMP-NEXT: store i32 0, i32* [[I]], align 4 +// NOOMP-NEXT: store i32 0, i32* [[I]], align 4 +// NOOMP-NEXT: br label [[FOR_COND:%.*]] +// NOOMP: for.cond: +// NOOMP-NEXT: [[TMP0:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP0]], 33554432 +// NOOMP-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// NOOMP: for.body: +// NOOMP-NEXT: [[TMP1:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64 +// NOOMP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [33554432 x double], [33554432 x double]* @A, i64 0, i64 [[IDXPROM]] +// NOOMP-NEXT: store double 1.000000e+00, double* [[ARRAYIDX]], align 8 +// NOOMP-NEXT: br label [[FOR_INC:%.*]] +// NOOMP: for.inc: +// NOOMP-NEXT: [[TMP2:%.*]] = load i32, i32* [[I]], align 4 +// NOOMP-NEXT: [[INC:%.*]] = add nsw i32 [[TMP2]], 1 +// NOOMP-NEXT: store i32 [[INC]], i32* [[I]], align 4 +// NOOMP-NEXT: br label [[FOR_COND]] +// NOOMP: for.end: +// NOOMP-NEXT: ret void +// +void foo(void) { + int i = 0; + +#pragma omp parallel for + for (i = 0; i < size; ++i) { + A[i] = 1.0; + } +} diff --git a/clang/test/utils/update_cc_test_checks/generated-funcs.test b/clang/test/utils/update_cc_test_checks/generated-funcs.test new file mode 100644 --- /dev/null +++ b/clang/test/utils/update_cc_test_checks/generated-funcs.test @@ -0,0 +1,11 @@ +## Test that CHECK lines are generated for clang-generated functions + +# RUN: cp %S/Inputs/generated-funcs.c %t-generated.c && %update_cc_test_checks --include-generated-funcs %t-generated.c +# RUN: diff -u %S/Inputs/generated-funcs.c.generated.expected %t-generated.c +# RUN: cp %S/Inputs/generated-funcs.c %t-no-generated.c && %update_cc_test_checks %t-no-generated.c +# RUN: diff -u %S/Inputs/generated-funcs.c.no-generated.expected %t-no-generated.c +## Check that re-running update_cc_test_checks doesn't change the output +# RUN: %update_cc_test_checks --include-generated-funcs %t-generated.c +# RUN: diff -u %S/Inputs/generated-funcs.c.generated.expected %t-generated.c +# RUN: %update_cc_test_checks %t-no-generated.c +# RUN: diff -u %S/Inputs/generated-funcs.c.no-generated.expected %t-no-generated.c diff --git a/llvm/utils/UpdateTestChecks/asm.py b/llvm/utils/UpdateTestChecks/asm.py --- a/llvm/utils/UpdateTestChecks/asm.py +++ b/llvm/utils/UpdateTestChecks/asm.py @@ -321,7 +321,8 @@ print("Cannot find a triple. Assume 'x86'", file=sys.stderr) return 'x86' -def build_function_body_dictionary_for_triple(args, raw_tool_output, triple, prefixes, func_dict): +def build_function_body_dictionary_for_triple(args, raw_tool_output, triple, + prefixes, func_dict, func_order): target_handlers = { 'i686': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 'x86': (scrub_asm_x86, ASM_FUNCTION_X86_RE), @@ -364,7 +365,7 @@ scrubber, function_re = handler common.build_function_body_dictionary( function_re, scrubber, [args], raw_tool_output, prefixes, - func_dict, args.verbose, False) + func_dict, func_order, args.verbose, False) ##### Generator of assembly CHECK lines diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py --- a/llvm/utils/UpdateTestChecks/common.py +++ b/llvm/utils/UpdateTestChecks/common.py @@ -17,6 +17,8 @@ _verbose = False def parse_commandline_args(parser): + parser.add_argument('--include-generated-funcs', action='store_true', + help='Output checks for functions not in source') parser.add_argument('-v', '--verbose', action='store_true', help='Show verbose output') parser.add_argument('-u', '--update-only', action='store_true', @@ -169,7 +171,7 @@ def __str__(self): return self.scrub -def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_tool_output, prefixes, func_dict, verbose, record_args): +def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_tool_output, prefixes, func_dict, func_order, verbose, record_args): for m in function_re.finditer(raw_tool_output): if not m: continue @@ -209,6 +211,7 @@ continue func_dict[prefix][func] = function_body(scrubbed_body, scrubbed_extra, args_and_sig) + func_order[prefix].append(func) ##### Generator of LLVM IR CHECK lines diff --git a/llvm/utils/update_cc_test_checks.py b/llvm/utils/update_cc_test_checks.py --- a/llvm/utils/update_cc_test_checks.py +++ b/llvm/utils/update_cc_test_checks.py @@ -168,7 +168,8 @@ return args -def get_function_body(args, filename, clang_args, extra_commands, prefixes, triple_in_cmd, func_dict): +def get_function_body(args, filename, clang_args, extra_commands, prefixes, + triple_in_cmd, func_dict, func_order): # TODO Clean up duplication of asm/common build_function_body_dictionary # Invoke external tool and extract function bodies. raw_tool_output = common.invoke_tool(args.clang, clang_args, filename) @@ -188,7 +189,8 @@ if '-emit-llvm' in clang_args: common.build_function_body_dictionary( common.OPT_FUNCTION_RE, common.scrub_body, [], - raw_tool_output, prefixes, func_dict, args.verbose, args.function_signature) + raw_tool_output, prefixes, func_dict, func_order, args.verbose, + args.function_signature) else: print('The clang command line should include -emit-llvm as asm tests ' 'are discouraged in Clang testsuite.', file=sys.stderr) @@ -267,15 +269,18 @@ # Execute clang, generate LLVM IR, and extract functions. func_dict = {} + func_order = {} for p in run_list: prefixes = p[0] for prefix in prefixes: func_dict.update({prefix: dict()}) + func_order.update({prefix: []}) for prefixes, clang_args, extra_commands, triple_in_cmd in run_list: common.debug('Extracted clang cmd: clang {}'.format(clang_args)) common.debug('Extracted FileCheck prefixes: {}'.format(prefixes)) - get_function_body(args, filename, clang_args, extra_commands, prefixes, triple_in_cmd, func_dict) + get_function_body(args, filename, clang_args, extra_commands, prefixes, + triple_in_cmd, func_dict, func_order) # Invoke clang -Xclang -ast-dump=json to get mapping from start lines to # mangled names. Forward all clang args for now. @@ -283,29 +288,81 @@ line2spell_and_mangled_list[k].append(v) output_lines = [autogenerated_note] - for idx, line in enumerate(input_lines): - # Discard any previous script advertising. - if line.startswith(ADVERT): - continue - if idx in line2spell_and_mangled_list: - added = set() - for spell, mangled in line2spell_and_mangled_list[idx]: - # One line may contain multiple function declarations. - # Skip if the mangled name has been added before. - # The line number may come from an included file, - # we simply require the spelling name to appear on the line - # to exclude functions from other files. - if mangled in added or spell not in line: - continue - if args.functions is None or any(re.search(regex, spell) for regex in args.functions): + + if args.include_generated_funcs: + # Generate the appropriate checks for each function. We need to emit + # these in the order according to the generated output so that CHECK-LABEL + # works properly. func_order provides that. + + # It turns out that when clang generates functions (for example, with + # -fopenmp), it can sometimes cause functions to be re-ordered in the + # output, even functions that exist in the source file. Therefore we + # can't insert check lines before each source function and instead have to + # put them at the end. So the first thing to do is dump out the source + # lines. + for idx, line in enumerate(input_lines): + # Discard any previous script advertising. + if line.startswith(ADVERT): + continue + output_lines.append(line.rstrip('\n')) + + # Now generate all the checks. + added = set() + for prefixes, clang_args, extra_commands, triple_in_cmd in run_list: + for prefix in prefixes: + for func in func_order[prefix]: if added: output_lines.append('//') - added.add(mangled) - common.add_ir_checks(output_lines, '//', run_list, func_dict, mangled, - False, args.function_signature) - output_lines.append(line.rstrip('\n')) - - + added.add(func) + + # The add_*_checks routines expect a run list whose items are + # tuples that have a list of prefixes as their first element and + # tool command args string as their second element. They output + # checks for each prefix in the list of prefixes. By doing so, it + # implicitly assumes that for each function every run line will + # generate something for that function. That is not the case for + # generated functions as some run lines might not generate them + # (e.g. -fopenmp vs. no -fopenmp). + # + # Therefore, pass just the prefix we're interested in. This has + # the effect of generating all of the checks for functions of a + # single prefix before moving on to the next prefix. So checks + # are ordered by prefix instead of by function as in "normal" + # mode. + if '-emit-llvm' in clang_args: + common.add_ir_checks(output_lines, '//', + [([prefix], clang_args)], + func_dict, func, False, + args.function_signature) + else: + asm.add_asm_checks(output_lines, '//', + [([prefix], clang_args)], + func_dict, func) + else: + # Normal mode. Put checks before each source function. + for idx, line in enumerate(input_lines): + # Discard any previous script advertising. + if line.startswith(ADVERT): + continue + if idx in line2spell_and_mangled_list: + added = set() + for spell, mangled in line2spell_and_mangled_list[idx]: + # One line may contain multiple function declarations. + # Skip if the mangled name has been added before. + # The line number may come from an included file, + # we simply require the spelling name to appear on the line + # to exclude functions from other files. + if mangled in added or spell not in line: + continue + if args.functions is None or any(re.search(regex, spell) for regex in args.functions): + if added: + output_lines.append('//') + added.add(mangled) + common.add_ir_checks(output_lines, '//', run_list, func_dict, + mangled, False, args.function_signature) + output_lines.append(line.rstrip('\n')) + + # Update the test file. common.debug('Writing %d lines to %s...' % (len(output_lines), filename)) with open(filename, 'wb') as f: f.writelines(['{}\n'.format(l).encode('utf-8') for l in output_lines]) diff --git a/llvm/utils/update_llc_test_checks.py b/llvm/utils/update_llc_test_checks.py --- a/llvm/utils/update_llc_test_checks.py +++ b/llvm/utils/update_llc_test_checks.py @@ -123,10 +123,12 @@ autogenerated_note = (comment_sym + ADVERT + 'utils/' + script_name) func_dict = {} + func_order = {} for p in run_list: prefixes = p[0] for prefix in prefixes: func_dict.update({prefix: dict()}) + func_order.update({prefix: []}) for prefixes, llc_args, triple_in_cmd, march_in_cmd in run_list: common.debug('Extracted LLC cmd:', llc_tool, llc_args) common.debug('Extracted FileCheck prefixes:', str(prefixes)) @@ -138,7 +140,7 @@ triple = asm.get_triple_from_march(march_in_cmd) asm.build_function_body_dictionary_for_triple(args, raw_tool_output, - triple, prefixes, func_dict) + triple, prefixes, func_dict, func_order) is_in_function = False is_in_function_start = False diff --git a/llvm/utils/update_test_checks.py b/llvm/utils/update_test_checks.py --- a/llvm/utils/update_test_checks.py +++ b/llvm/utils/update_test_checks.py @@ -137,9 +137,11 @@ prefix_list.append((check_prefixes, tool_cmd_args)) func_dict = {} + func_order = {} for prefixes, _ in prefix_list: for prefix in prefixes: func_dict.update({prefix: dict()}) + func_order.update({prefix: []}) for prefixes, opt_args in prefix_list: common.debug('Extracted opt cmd: ' + opt_basename + ' ' + opt_args) common.debug('Extracted FileCheck prefixes: ' + str(prefixes)) @@ -147,7 +149,7 @@ raw_tool_output = common.invoke_tool(args.opt_binary, opt_args, test) common.build_function_body_dictionary( common.OPT_FUNCTION_RE, common.scrub_body, [], - raw_tool_output, prefixes, func_dict, args.verbose, + raw_tool_output, prefixes, func_dict, func_order, args.verbose, args.function_signature) is_in_function = False