25 changes: 10 additions & 15 deletions clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,17 +357,14 @@ namespace N0 {
a->A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
a->B::A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}

// FIXME: An overloaded unary 'operator*' is built for these
// even though the operand is a pointer (to a dependent type).
// Type::isOverloadableType should return false for such cases.
(*this).x4;
(*this).B::x4;
(*this).A::x4;
(*this).B::A::x4;
(*this).f4();
(*this).B::f4();
(*this).A::f4();
(*this).B::A::f4();
(*this).x4; // expected-error{{no member named 'x4' in 'B<T>'}}
(*this).B::x4; // expected-error{{no member named 'x4' in 'B<T>'}}
(*this).A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
(*this).B::A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
(*this).f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
(*this).B::f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
(*this).A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
(*this).B::A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}

b.x4; // expected-error{{no member named 'x4' in 'B<T>'}}
b.B::x4; // expected-error{{no member named 'x4' in 'B<T>'}}
Expand Down Expand Up @@ -399,15 +396,13 @@ namespace N1 {
f<0>();
this->f<0>();
a->f<0>();
// FIXME: This should not require 'template'!
(*this).f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
(*this).f<0>();
b.f<0>();

x.f<0>();
this->x.f<0>();
a->x.f<0>();
// FIXME: This should not require 'template'!
(*this).x.f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
(*this).x.f<0>();
b.x.f<0>();

// FIXME: None of these should require 'template'!
Expand Down
41 changes: 41 additions & 0 deletions clang/test/CodeGen/sparcv9-abi.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,47 @@ char f_int_4(char x) { return x; }
// CHECK-LABEL: define{{.*}} fp128 @f_ld(fp128 noundef %x)
long double f_ld(long double x) { return x; }

// Zero-sized structs reserves an argument register slot if passed directly.
struct empty {};
struct emptyarr { struct empty a[10]; };

// CHECK-LABEL: define{{.*}} i64 @f_empty(i64 %x.coerce)
struct empty f_empty(struct empty x) { return x; }

// CHECK-LABEL: define{{.*}} i64 @f_emptyarr(i64 %x.coerce)
struct empty f_emptyarr(struct emptyarr x) { return x.a[0]; }

// CHECK-LABEL: define{{.*}} i64 @f_emptyvar(i32 noundef zeroext %count, ...)
long f_emptyvar(unsigned count, ...) {
long ret;
va_list args;
va_start(args, count);

// CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %args
// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8
// CHECK-DAG: store ptr %[[NXT]], ptr %args
va_arg(args, struct empty);

// CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %args
// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8
// CHECK-DAG: store ptr %[[NXT]], ptr %args
// CHECK-DAG: load i64, ptr %[[CUR]]
ret = va_arg(args, long);
va_end(args);
return ret;
}

// If the zero-sized struct is contained in a non-zero-sized struct,
// though, it doesn't reserve any registers.
struct emptymixed { struct empty a; long b; };
struct emptyflex { unsigned count; struct empty data[10]; };

// CHECK-LABEL: define{{.*}} i64 @f_emptymixed(i64 %x.coerce)
long f_emptymixed(struct emptymixed x) { return x.b; }

// CHECK-LABEL: define{{.*}} i64 @f_emptyflex(i64 %x.coerce, i64 noundef %y)
long f_emptyflex(struct emptyflex x, long y) { return y; }

// Small structs are passed in registers.
struct small {
int *a, *b;
Expand Down
24 changes: 24 additions & 0 deletions clang/test/CodeGen/sparcv9-class-return.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | FileCheck %s

class Empty {
};

class Long : public Empty {
public:
long l;
};

// CHECK: define{{.*}} i64 @_Z4foo15Empty(i64 %e.coerce)
Empty foo1(Empty e) {
return e;
}

// CHECK: define{{.*}} %class.Long @_Z4foo24Long(i64 %l.coerce)
Long foo2(Long l) {
return l;
}

// CHECK: define{{.*}} i64 @_Z4foo34Long(i64 %l.coerce)
long foo3(Long l) {
return l.l;
}
4 changes: 2 additions & 2 deletions clang/test/CodeGenCoroutines/coro-await.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,8 @@ extern "C" void TestTailcall() {
// ---------------------------
// Call coro.await.suspend
// ---------------------------
// CHECK-NEXT: %[[RESUMED:.+]] = call ptr @llvm.coro.await.suspend.handle(ptr %[[AWAITABLE]], ptr %[[FRAME]], ptr @TestTailcall.__await_suspend_wrapper__await)
// CHECK-NEXT: call void @llvm.coro.resume(ptr %[[RESUMED]])
// Note: The call must not be nounwind since the resumed function could throw.
// CHECK-NEXT: call void @llvm.coro.await.suspend.handle(ptr %[[AWAITABLE]], ptr %[[FRAME]], ptr @TestTailcall.__await_suspend_wrapper__await){{$}}
// CHECK-NEXT: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
// CHECK-NEXT: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
// CHECK-NEXT: i8 0, label %[[READY_BB]]
Expand Down
54 changes: 0 additions & 54 deletions clang/test/CodeGenCoroutines/coro-symmetric-transfer-01.cpp

This file was deleted.

6 changes: 2 additions & 4 deletions clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ Task bar() {
// CHECK: br i1 %{{.+}}, label %[[CASE1_AWAIT_READY:.+]], label %[[CASE1_AWAIT_SUSPEND:.+]]
// CHECK: [[CASE1_AWAIT_SUSPEND]]:
// CHECK-NEXT: %{{.+}} = call token @llvm.coro.save(ptr null)
// CHECK-NEXT: %[[HANDLE1_PTR:.+]] = call ptr @llvm.coro.await.suspend.handle
// CHECK-NEXT: call void @llvm.coro.resume(ptr %[[HANDLE1_PTR]])
// CHECK-NEXT: call void @llvm.coro.await.suspend.handle
// CHECK-NEXT: %{{.+}} = call i8 @llvm.coro.suspend
// CHECK-NEXT: switch i8 %{{.+}}, label %coro.ret [
// CHECK-NEXT: i8 0, label %[[CASE1_AWAIT_READY]]
Expand All @@ -104,8 +103,7 @@ Task bar() {
// CHECK: br i1 %{{.+}}, label %[[CASE2_AWAIT_READY:.+]], label %[[CASE2_AWAIT_SUSPEND:.+]]
// CHECK: [[CASE2_AWAIT_SUSPEND]]:
// CHECK-NEXT: %{{.+}} = call token @llvm.coro.save(ptr null)
// CHECK-NEXT: %[[HANDLE2_PTR:.+]] = call ptr @llvm.coro.await.suspend.handle
// CHECK-NEXT: call void @llvm.coro.resume(ptr %[[HANDLE2_PTR]])
// CHECK-NEXT: call void @llvm.coro.await.suspend.handle
// CHECK-NEXT: %{{.+}} = call i8 @llvm.coro.suspend
// CHECK-NEXT: switch i8 %{{.+}}, label %coro.ret [
// CHECK-NEXT: i8 0, label %[[CASE2_AWAIT_READY]]
Expand Down
19 changes: 19 additions & 0 deletions clang/test/CoverageMapping/coroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct std::coroutine_traits<int, int> {
suspend_always final_suspend() noexcept;
void unhandled_exception() noexcept;
void return_value(int);
suspend_always yield_value(int);
};
};

Expand All @@ -45,3 +46,21 @@ int f1(int x) { // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+8]]:2 = #0
} // CHECK-NEXT: File 0, [[@LINE-2]]:10 -> [[@LINE]]:4 = (#0 - #1)
co_return x; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = #1
} // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:14 = #1

// CHECK-LABEL: _Z2f2i:
// CHECK-NEXT: File 0, [[@LINE+1]]:15 -> [[@LINE+15]]:2 = #0
int f2(int x) {
// CHECK-NEXT: File 0, [[@LINE+5]]:13 -> [[@LINE+5]]:18 = #0
// CHECK-NEXT: Branch,File 0, [[@LINE+4]]:13 -> [[@LINE+4]]:18 = #1, (#0 - #1)
// CHECK-NEXT: Gap,File 0, [[@LINE+3]]:20 -> [[@LINE+3]]:21 = #1
// CHECK-NEXT: File 0, [[@LINE+2]]:21 -> [[@LINE+2]]:37 = #1
// CHECK-NEXT: File 0, [[@LINE+1]]:40 -> [[@LINE+1]]:56 = (#0 - #1)
co_await (x > 0 ? suspend_always{} : suspend_always{});
// CHECK-NEXT: File 0, [[@LINE+5]]:12 -> [[@LINE+5]]:17 = #0
// CHECK-NEXT: Branch,File 0, [[@LINE+4]]:12 -> [[@LINE+4]]:17 = #2, (#0 - #2)
// CHECK-NEXT: Gap,File 0, [[@LINE+3]]:19 -> [[@LINE+3]]:20 = #2
// CHECK-NEXT: File 0, [[@LINE+2]]:20 -> [[@LINE+2]]:21 = #2
// CHECK-NEXT: File 0, [[@LINE+1]]:24 -> [[@LINE+1]]:25 = (#0 - #2)
co_yield x > 0 ? 1 : 2;
co_return 0;
}
15 changes: 15 additions & 0 deletions clang/test/CoverageMapping/decomposition.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -triple %itanium_abi_triple -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s | FileCheck %s

// CHECK-LABEL: _Z19array_decompositioni:
// CHECK-NEXT: File 0, [[@LINE+6]]:32 -> {{[0-9]+}}:2 = #0
// CHECK-NEXT: File 0, [[@LINE+8]]:20 -> [[@LINE+8]]:25 = #0
// CHECK-NEXT: Branch,File 0, [[@LINE+7]]:20 -> [[@LINE+7]]:25 = #1, (#0 - #1)
// CHECK-NEXT: Gap,File 0, [[@LINE+6]]:27 -> [[@LINE+6]]:28 = #1
// CHECK-NEXT: File 0, [[@LINE+5]]:28 -> [[@LINE+5]]:29 = #1
// CHECK-NEXT: File 0, [[@LINE+4]]:32 -> [[@LINE+4]]:33 = (#0 - #1)
int array_decomposition(int i) {
int a[] = {1, 2, 3};
int b[] = {4, 5, 6};
auto [x, y, z] = i > 0 ? a : b;
return x + y + z;
}
4 changes: 3 additions & 1 deletion clang/test/Driver/frelaxed-template-template-args.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// RUN: %clang -fsyntax-only -### %s 2>&1 | FileCheck --check-prefix=CHECK-DEF %s
// RUN: %clang -fsyntax-only -frelaxed-template-template-args %s 2>&1 | FileCheck --check-prefix=CHECK-ON %s
// RUN: %clang -fsyntax-only -fno-relaxed-template-template-args %s 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
// RUN: %clang -fsyntax-only -fno-relaxed-template-template-args -Wno-deprecated-no-relaxed-template-template-args %s 2>&1 | FileCheck --check-prefix=CHECK-DIS --allow-empty %s

// CHECK-DEF-NOT: "-cc1"{{.*}} "-fno-relaxed-template-template-args"
// CHECK-ON: warning: argument '-frelaxed-template-template-args' is deprecated [-Wdeprecated]
// CHECK-OFF: warning: argument '-fno-relaxed-template-template-args' is deprecated [-Wdeprecated]
// CHECK-OFF: warning: argument '-fno-relaxed-template-template-args' is deprecated [-Wdeprecated-no-relaxed-template-template-args]
// CHECK-DIS-NOT: warning: argument '-fno-relaxed-template-template-args' is deprecated
10 changes: 7 additions & 3 deletions clang/test/Driver/riscv-profiles.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
// RVA22S64: "-target-feature" "+svinval"
// RVA22S64: "-target-feature" "+svpbmt"

// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rva23u64 \
// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rva23u64 -menable-experimental-extensions \
// RUN: | FileCheck -check-prefix=RVA23U64 %s
// RVA23U64: "-target-feature" "+m"
// RVA23U64: "-target-feature" "+a"
Expand Down Expand Up @@ -207,7 +207,7 @@
// RVA23S64: "-target-feature" "+svnapot"
// RVA23S64: "-target-feature" "+svpbmt"

// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rvb23u64 \
// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rvb23u64 -menable-experimental-extensions \
// RUN: | FileCheck -check-prefix=RVB23U64 %s
// RVB23U64: "-target-feature" "+m"
// RVB23U64: "-target-feature" "+a"
Expand Down Expand Up @@ -284,7 +284,7 @@
// RVB23S64: "-target-feature" "+svnapot"
// RVB23S64: "-target-feature" "+svpbmt"

// RUN: %clang --target=riscv32 -### -c %s 2>&1 -march=rvm23u32 \
// RUN: %clang --target=riscv32 -### -c %s 2>&1 -march=rvm23u32 -menable-experimental-extensions \
// RUN: | FileCheck -check-prefix=RVM23U32 %s
// RVM23U32: "-target-feature" "+m"
// RVM23U32: "-target-feature" "+zicbop"
Expand Down Expand Up @@ -322,3 +322,7 @@

// RUN: not %clang --target=riscv64 -### -c %s 2>&1 -march=rva22u64zfa | FileCheck -check-prefix=INVALID-ADDITIONAL %s
// INVALID-ADDITIONAL: error: invalid arch name 'rva22u64zfa', additional extensions must be after separator '_'

// RUN: not %clang --target=riscv64 -### -c %s 2>&1 -march=rva23u64 | FileCheck -check-prefix=EXPERIMENTAL-NOFLAG %s
// EXPERIMENTAL-NOFLAG: error: invalid arch name 'rva23u64'
// EXPERIMENTAL-NOFLAG: requires '-menable-experimental-extensions' for profile 'rva23u64'
4 changes: 2 additions & 2 deletions clang/test/Frontend/noderef_templates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
#define NODEREF __attribute__((noderef))

template <typename T>
int func(T NODEREF *a) { // expected-note 2 {{a declared here}}
return *a + 1; // expected-warning 2 {{dereferencing a; was declared with a 'noderef' type}}
int func(T NODEREF *a) { // expected-note 3 {{a declared here}}
return *a + 1; // expected-warning 3 {{dereferencing a; was declared with a 'noderef' type}}
}

void func() {
Expand Down
150 changes: 150 additions & 0 deletions clang/test/OpenMP/target_map_both_pointer_pointee_codegen.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs --replace-value-regex "__omp_offloading_[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" "pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _
// RUN: %clang_cc1 -verify -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s

// expected-no-diagnostics
#ifndef HEADER
#define HEADER

extern void *malloc (int __size) throw () __attribute__ ((__malloc__));

void foo() {
int *ptr = (int *) malloc(3 * sizeof(int));

#pragma omp target map(ptr, ptr[0:2])
{
ptr[1] = 6;
}
#pragma omp target map(ptr, ptr[2])
{
ptr[2] = 8;
}
}
#endif
// CHECK-LABEL: define {{[^@]+}}@_Z3foov
// CHECK-SAME: () #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[PTR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: [[DOTOFFLOAD_BASEPTRS:%.*]] = alloca [1 x ptr], align 8
// CHECK-NEXT: [[DOTOFFLOAD_PTRS:%.*]] = alloca [1 x ptr], align 8
// CHECK-NEXT: [[DOTOFFLOAD_MAPPERS:%.*]] = alloca [1 x ptr], align 8
// CHECK-NEXT: [[KERNEL_ARGS:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS:%.*]], align 8
// CHECK-NEXT: [[DOTOFFLOAD_BASEPTRS2:%.*]] = alloca [1 x ptr], align 8
// CHECK-NEXT: [[DOTOFFLOAD_PTRS3:%.*]] = alloca [1 x ptr], align 8
// CHECK-NEXT: [[DOTOFFLOAD_MAPPERS4:%.*]] = alloca [1 x ptr], align 8
// CHECK-NEXT: [[KERNEL_ARGS5:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8
// CHECK-NEXT: [[CALL:%.*]] = call noalias noundef ptr @_Z6malloci(i32 noundef signext 12) #[[ATTR3:[0-9]+]]
// CHECK-NEXT: store ptr [[CALL]], ptr [[PTR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[PTR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 0
// CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS]], i32 0, i32 0
// CHECK-NEXT: store ptr [[PTR]], ptr [[TMP2]], align 8
// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS]], i32 0, i32 0
// CHECK-NEXT: store ptr [[ARRAYIDX]], ptr [[TMP3]], align 8
// CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS]], i64 0, i64 0
// CHECK-NEXT: store ptr null, ptr [[TMP4]], align 8
// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS]], i32 0, i32 0
// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS]], i32 0, i32 0
// CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
// CHECK-NEXT: store i32 3, ptr [[TMP7]], align 4
// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 1
// CHECK-NEXT: store i32 1, ptr [[TMP8]], align 4
// CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 2
// CHECK-NEXT: store ptr [[TMP5]], ptr [[TMP9]], align 8
// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 3
// CHECK-NEXT: store ptr [[TMP6]], ptr [[TMP10]], align 8
// CHECK-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4
// CHECK-NEXT: store ptr @.offload_sizes, ptr [[TMP11]], align 8
// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5
// CHECK-NEXT: store ptr @.offload_maptypes, ptr [[TMP12]], align 8
// CHECK-NEXT: [[TMP13:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6
// CHECK-NEXT: store ptr null, ptr [[TMP13]], align 8
// CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7
// CHECK-NEXT: store ptr null, ptr [[TMP14]], align 8
// CHECK-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 8
// CHECK-NEXT: store i64 0, ptr [[TMP15]], align 8
// CHECK-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 9
// CHECK-NEXT: store i64 0, ptr [[TMP16]], align 8
// CHECK-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 10
// CHECK-NEXT: store [3 x i32] [i32 -1, i32 0, i32 0], ptr [[TMP17]], align 4
// CHECK-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 11
// CHECK-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP18]], align 4
// CHECK-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK-NEXT: store i32 0, ptr [[TMP19]], align 4
// CHECK-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1:[0-9]+]], i64 -1, i32 -1, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l15.region_id, ptr [[KERNEL_ARGS]])
// CHECK-NEXT: [[TMP21:%.*]] = icmp ne i32 [[TMP20]], 0
// CHECK-NEXT: br i1 [[TMP21]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK: omp_offload.failed:
// CHECK-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l15(ptr [[TMP0]]) #[[ATTR3]]
// CHECK-NEXT: br label [[OMP_OFFLOAD_CONT]]
// CHECK: omp_offload.cont:
// CHECK-NEXT: [[TMP22:%.*]] = load ptr, ptr [[PTR]], align 8
// CHECK-NEXT: [[TMP23:%.*]] = load ptr, ptr [[PTR]], align 8
// CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, ptr [[TMP23]], i64 2
// CHECK-NEXT: [[TMP24:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS2]], i32 0, i32 0
// CHECK-NEXT: store ptr [[PTR]], ptr [[TMP24]], align 8
// CHECK-NEXT: [[TMP25:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS3]], i32 0, i32 0
// CHECK-NEXT: store ptr [[ARRAYIDX1]], ptr [[TMP25]], align 8
// CHECK-NEXT: [[TMP26:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS4]], i64 0, i64 0
// CHECK-NEXT: store ptr null, ptr [[TMP26]], align 8
// CHECK-NEXT: [[TMP27:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS2]], i32 0, i32 0
// CHECK-NEXT: [[TMP28:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS3]], i32 0, i32 0
// CHECK-NEXT: [[TMP29:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 0
// CHECK-NEXT: store i32 3, ptr [[TMP29]], align 4
// CHECK-NEXT: [[TMP30:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 1
// CHECK-NEXT: store i32 1, ptr [[TMP30]], align 4
// CHECK-NEXT: [[TMP31:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 2
// CHECK-NEXT: store ptr [[TMP27]], ptr [[TMP31]], align 8
// CHECK-NEXT: [[TMP32:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 3
// CHECK-NEXT: store ptr [[TMP28]], ptr [[TMP32]], align 8
// CHECK-NEXT: [[TMP33:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 4
// CHECK-NEXT: store ptr @.offload_sizes.1, ptr [[TMP33]], align 8
// CHECK-NEXT: [[TMP34:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 5
// CHECK-NEXT: store ptr @.offload_maptypes.2, ptr [[TMP34]], align 8
// CHECK-NEXT: [[TMP35:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 6
// CHECK-NEXT: store ptr null, ptr [[TMP35]], align 8
// CHECK-NEXT: [[TMP36:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 7
// CHECK-NEXT: store ptr null, ptr [[TMP36]], align 8
// CHECK-NEXT: [[TMP37:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 8
// CHECK-NEXT: store i64 0, ptr [[TMP37]], align 8
// CHECK-NEXT: [[TMP38:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 9
// CHECK-NEXT: store i64 0, ptr [[TMP38]], align 8
// CHECK-NEXT: [[TMP39:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 10
// CHECK-NEXT: store [3 x i32] [i32 -1, i32 0, i32 0], ptr [[TMP39]], align 4
// CHECK-NEXT: [[TMP40:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 11
// CHECK-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP40]], align 4
// CHECK-NEXT: [[TMP41:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 12
// CHECK-NEXT: store i32 0, ptr [[TMP41]], align 4
// CHECK-NEXT: [[TMP42:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 -1, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l19.region_id, ptr [[KERNEL_ARGS5]])
// CHECK-NEXT: [[TMP43:%.*]] = icmp ne i32 [[TMP42]], 0
// CHECK-NEXT: br i1 [[TMP43]], label [[OMP_OFFLOAD_FAILED6:%.*]], label [[OMP_OFFLOAD_CONT7:%.*]]
// CHECK: omp_offload.failed6:
// CHECK-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l19(ptr [[TMP22]]) #[[ATTR3]]
// CHECK-NEXT: br label [[OMP_OFFLOAD_CONT7]]
// CHECK: omp_offload.cont7:
// CHECK-NEXT: ret void
//
//
// CHECK-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l15
// CHECK-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR2:[0-9]+]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 1
// CHECK-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
// CHECK-NEXT: ret void
//
//
// CHECK-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l19
// CHECK-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR2]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 2
// CHECK-NEXT: store i32 8, ptr [[ARRAYIDX]], align 4
// CHECK-NEXT: ret void
//
6 changes: 6 additions & 0 deletions clang/test/PCH/optnone.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %clang_cc1 -emit-pch -x c++-header %s -o %t.pch
// RUN: %clang_cc1 -emit-llvm -DMAIN -include-pch %t.pch %s -o /dev/null

#ifndef MAIN
__attribute__((optnone)) void foo() {}
#endif
13 changes: 12 additions & 1 deletion clang/test/Sema/compound-literal.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ int main(int argc, char **argv) {
struct Incomplete; // expected-note{{forward declaration of 'struct Incomplete'}}
struct Incomplete* I1 = &(struct Incomplete){1, 2, 3}; // expected-error {{variable has incomplete type}}
void IncompleteFunc(unsigned x) {
struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{variable-sized object may not be initialized}}
struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{compound literal cannot be of variable-length array type}}
(void){1,2,3}; // expected-error {{variable has incomplete type}}
(void(void)) { 0 }; // expected-error{{illegal initializer type 'void (void)'}}
}
Expand All @@ -42,3 +42,14 @@ int (^block)(int) = ^(int i) {
int *array = (int[]) {i, i + 2, i + 4};
return array[i];
};

// C99 6.5.2.5 Compound literals constraint 1: The type name shall specify an object type or an array of unknown size, but not a variable length array type.
// So check that VLA type compound literals are rejected (see https://github.com/llvm/llvm-project/issues/89835).
void vla(int n) {
int size = 5;
(void)(int[size]){}; // expected-warning {{use of an empty initializer is a C23 extension}}
// expected-error@-1 {{compound literal cannot be of variable-length array type}}
(void)(int[size]){1}; // expected-error {{compound literal cannot be of variable-length array type}}
(void)(int[size]){1,2,3}; // expected-error {{compound literal cannot be of variable-length array type}}
(void)(int[size]){1,2,3,4,5}; // expected-error {{compound literal cannot be of variable-length array type}}
}
6 changes: 2 additions & 4 deletions clang/test/SemaCXX/cxx2b-deducing-this.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct S {
// new and delete are implicitly static
void *operator new(this unsigned long); // expected-error{{an explicit object parameter cannot appear in a static function}}
void operator delete(this void*); // expected-error{{an explicit object parameter cannot appear in a static function}}

void g(this auto) const; // expected-error{{explicit object member function cannot have 'const' qualifier}}
void h(this auto) &; // expected-error{{explicit object member function cannot have '&' qualifier}}
void i(this auto) &&; // expected-error{{explicit object member function cannot have '&&' qualifier}}
Expand Down Expand Up @@ -198,9 +198,7 @@ void func(int i) {
void TestMutationInLambda() {
[i = 0](this auto &&){ i++; }();
[i = 0](this auto){ i++; }();
[i = 0](this const auto&){ i++; }();
// expected-error@-1 {{cannot assign to a variable captured by copy in a non-mutable lambda}}
// expected-note@-2 {{in instantiation of}}
[i = 0](this const auto&){ i++; }(); // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}}

int x;
const auto l1 = [x](this auto&) { x = 42; }; // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}}
Expand Down
12 changes: 6 additions & 6 deletions clang/test/SemaTemplate/class-template-spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ int test_specs(A<float, float> *a1, A<float, int> *a2) {
return a1->x + a2->y;
}

int test_incomplete_specs(A<double, double> *a1,
int test_incomplete_specs(A<double, double> *a1,
A<double> *a2)
{
(void)a1->x; // expected-error{{member access into incomplete type}}
Expand All @@ -39,7 +39,7 @@ template <> struct X<int, int> { int foo(); }; // #1
template <> struct X<float> { int bar(); }; // #2

typedef int int_type;
void testme(X<int_type> *x1, X<float, int> *x2) {
void testme(X<int_type> *x1, X<float, int> *x2) {
(void)x1->foo(); // okay: refers to #1
(void)x2->bar(); // okay: refers to #2
}
Expand All @@ -53,7 +53,7 @@ struct A<char> {
A<char>::A() { }

// Make sure we can see specializations defined before the primary template.
namespace N{
namespace N{
template<typename T> struct A0;
}

Expand Down Expand Up @@ -97,7 +97,7 @@ namespace M {
template<> struct ::A<long double>; // expected-error{{must occur at global scope}}
}

template<> struct N::B<char> {
template<> struct N::B<char> {
int testf(int x) { return f(x); }
};

Expand Down Expand Up @@ -138,9 +138,9 @@ namespace PR18009 {

template <typename T> struct C {
template <int N, int M> struct S;
template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // expected-error {{depends on a template parameter of the partial specialization}}
template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // ok
};
C<int> c; // expected-note {{in instantiation of}}
C<int> c;

template<int A> struct outer {
template<int B, int C> struct inner {};
Expand Down
58 changes: 58 additions & 0 deletions clang/test/SemaTemplate/cwg2398.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,61 @@ namespace ttp_defaults {
// old-error@-2 {{template template argument has different template parameters}}
// old-error@-3 {{explicit instantiation of 'f' does not refer to a function template}}
} // namespace ttp_defaults

namespace ttp_only {
template <template <class... > class TT1> struct A { static constexpr int V = 0; };
// new-note@-1 2{{template is declared here}}
template <template <class > class TT2> struct A<TT2> { static constexpr int V = 1; };
// new-error@-1 {{not more specialized than the primary template}}
// new-note@-2 {{partial specialization matches}}
template <template <class, class> class TT3> struct A<TT3> { static constexpr int V = 2; };
// new-error@-1 {{not more specialized than the primary template}}
// new-note@-2 {{partial specialization matches}}

template <class ... > struct B;
template <class > struct C;
template <class, class > struct D;
template <class, class, class> struct E;

static_assert(A<B>::V == 0); // new-error {{ambiguous partial specializations}}
static_assert(A<C>::V == 1);
static_assert(A<D>::V == 2);
static_assert(A<E>::V == 0);
} // namespace ttp_only

namespace consistency {
template<class T> struct nondeduced { using type = T; };
template<class T8, class T9 = float> struct B;

namespace t1 {
template<class T1, class T2, class T3> struct A;

template<template<class, class> class TT1,
class T1, class T2, class T3, class T4>
struct A<TT1<T1, T2>, TT1<T3, T4>, typename nondeduced<TT1<T1, T2>>::type> {};

template<template<class> class UU1,
template<class> class UU2,
class U1, class U2>
struct A<UU1<U1>, UU2<U2>, typename nondeduced<UU1<U1>>::type>;

template struct A<B<int>, B<int>, B<int>>;
} // namespace t1
namespace t2 {
template<class T1, class T2, class T3> struct A;

template<template<class, class> class TT1,
class T1, class T2, class T3, class T4>
struct A<TT1<T1, T2>, TT1<T3, T4>, typename nondeduced<TT1<T1, T4>>::type> {};
// new-note@-1 {{partial specialization matches}}

template<template<class> class UU1,
template<class> class UU2,
class U1, class U2>
struct A<UU1<U1>, UU2<U2>, typename nondeduced<UU1<U1>>::type>;
// new-note@-1 {{partial specialization matches}}

template struct A<B<int>, B<int>, B<int>>;
// new-error@-1 {{ambiguous partial specializations}}
} // namespace t1
} // namespace consistency
3 changes: 2 additions & 1 deletion clang/tools/clang-format/ClangFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,8 @@ static void outputReplacementXML(StringRef Text) {

static void outputReplacementsXML(const Replacements &Replaces) {
for (const auto &R : Replaces) {
outs() << "<replacement " << "offset='" << R.getOffset() << "' "
outs() << "<replacement "
<< "offset='" << R.getOffset() << "' "
<< "length='" << R.getLength() << "'>";
outputReplacementXML(R.getReplacementText());
outs() << "</replacement>\n";
Expand Down
6 changes: 3 additions & 3 deletions clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1572,9 +1572,9 @@ TEST_P(ASTMatchersTest, IsArrow_MatchesMemberVariablesViaArrow) {
EXPECT_TRUE(
matches("template <class T> class Y { void x() { this->m; } int m; };",
memberExpr(isArrow())));
EXPECT_TRUE(
notMatches("template <class T> class Y { void x() { (*this).m; } };",
cxxDependentScopeMemberExpr(isArrow())));
EXPECT_TRUE(notMatches(
"template <class T> class Y { void x() { (*this).m; } int m; };",
memberExpr(isArrow())));
}

TEST_P(ASTMatchersTest, IsArrow_MatchesStaticMemberVariablesViaArrow) {
Expand Down
33 changes: 33 additions & 0 deletions clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "TestingSupport.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Stmt.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
Expand Down Expand Up @@ -403,4 +405,35 @@ TEST_F(EnvironmentTest,
Contains(Member));
}

TEST_F(EnvironmentTest, Stmt) {
using namespace ast_matchers;

std::string Code = R"cc(
struct S { int i; };
void foo() {
S AnS = S{1};
}
)cc";
auto Unit =
tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
auto &Context = Unit->getASTContext();

ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);

auto *DeclStatement = const_cast<DeclStmt *>(selectFirst<DeclStmt>(
"d", match(declStmt(hasSingleDecl(varDecl(hasName("AnS")))).bind("d"),
Context)));
ASSERT_THAT(DeclStatement, NotNull());
auto *Init = (cast<VarDecl>(*DeclStatement->decl_begin()))->getInit();
ASSERT_THAT(Init, NotNull());

// Verify that we can retrieve the result object location for the initializer
// expression when we analyze the DeclStmt for `AnS`.
Environment Env(DAContext, *DeclStatement);
// Don't crash when initializing.
Env.initialize();
// And don't crash when retrieving the result object location.
Env.getResultObjectLocation(*Init);
}

} // namespace
4 changes: 2 additions & 2 deletions clang/unittests/Analysis/FlowSensitive/TestingSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,8 @@ checkDataflow(AnalysisInputs<AnalysisT> AI,
auto SetupTest = [&StmtToAnnotations,
PrevSetupTest = std::move(AI.SetupTest)](
AnalysisOutputs &AO) -> llvm::Error {
auto MaybeStmtToAnnotations = buildStatementToAnnotationMapping(
cast<FunctionDecl>(AO.InitEnv.getDeclCtx()), AO.Code);
auto MaybeStmtToAnnotations =
buildStatementToAnnotationMapping(AO.InitEnv.getCurrentFunc(), AO.Code);
if (!MaybeStmtToAnnotations) {
return MaybeStmtToAnnotations.takeError();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,38 @@ TEST_F(DataflowAnalysisTest, DiagnoseFunctionDiagnoserCalledOnEachElement) {
" (Lifetime ends)\n")));
}

TEST_F(DataflowAnalysisTest, CanAnalyzeStmt) {
std::string Code = R"cc(
struct S { bool b; };
void foo() {
S AnS = S{true};
}
)cc";
AST = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++11"});
const auto &DeclStatement =
matchNode<DeclStmt>(declStmt(hasSingleDecl(varDecl(hasName("AnS")))));
const auto &Func = matchNode<FunctionDecl>(functionDecl(hasName("foo")));

ACFG = std::make_unique<AdornedCFG>(llvm::cantFail(AdornedCFG::build(
Func, const_cast<DeclStmt &>(DeclStatement), AST->getASTContext())));

NoopAnalysis Analysis = NoopAnalysis(AST->getASTContext());
DACtx = std::make_unique<DataflowAnalysisContext>(
std::make_unique<WatchedLiteralsSolver>());
Environment Env(*DACtx, const_cast<DeclStmt &>(DeclStatement));

llvm::Expected<std::vector<std::optional<DataflowAnalysisState<NoopLattice>>>>
Results = runDataflowAnalysis(*ACFG, Analysis, Env);

ASSERT_THAT_ERROR(Results.takeError(), llvm::Succeeded());
const Environment &ExitBlockEnv = Results->front()->Env;
BoolValue *BoolFieldValue = cast<BoolValue>(
getFieldValue(ExitBlockEnv.get<RecordStorageLocation>(
*cast<VarDecl>((*DeclStatement.decl_begin()))),
"b", AST->getASTContext(), ExitBlockEnv));
EXPECT_TRUE(Env.proves(BoolFieldValue->formula()));
}

// Tests for the statement-to-block map.
using StmtToBlockTest = DataflowAnalysisTest;

Expand Down
46 changes: 29 additions & 17 deletions clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -5388,7 +5388,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/930.html">930</a></td>
<td>CD2</td>
<td><TT>alignof</TT> with incomplete array type</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.7</td>
</tr>
<tr id="931">
<td><a href="https://cplusplus.github.io/CWG/issues/931.html">931</a></td>
Expand Down Expand Up @@ -6468,7 +6468,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/1110.html">1110</a></td>
<td>NAD</td>
<td>Incomplete return type should be allowed in <TT>decltype</TT> operand</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 3.1</td>
</tr>
<tr id="1111">
<td><a href="https://cplusplus.github.io/CWG/issues/1111.html">1111</a></td>
Expand Down Expand Up @@ -7848,7 +7848,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/1340.html">1340</a></td>
<td>CD3</td>
<td>Complete type in member pointer expressions</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.9</td>
</tr>
<tr id="1341">
<td><a href="https://cplusplus.github.io/CWG/issues/1341.html">1341</a></td>
Expand Down Expand Up @@ -7920,7 +7920,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/1352.html">1352</a></td>
<td>CD3</td>
<td>Inconsistent class scope and completeness rules</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 3.0</td>
</tr>
<tr id="1353">
<td><a href="https://cplusplus.github.io/CWG/issues/1353.html">1353</a></td>
Expand Down Expand Up @@ -8556,7 +8556,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/1458.html">1458</a></td>
<td>CD3</td>
<td>Address of incomplete type vs <TT>operator&amp;()</TT></td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 3.1</td>
</tr>
<tr class="open" id="1459">
<td><a href="https://cplusplus.github.io/CWG/issues/1459.html">1459</a></td>
Expand Down Expand Up @@ -10752,7 +10752,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/1824.html">1824</a></td>
<td>CD4</td>
<td>Completeness of return type vs point of instantiation</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.7</td>
</tr>
<tr id="1825">
<td><a href="https://cplusplus.github.io/CWG/issues/1825.html">1825</a></td>
Expand Down Expand Up @@ -10800,7 +10800,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/1832.html">1832</a></td>
<td>CD4</td>
<td>Casting to incomplete enumeration</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 3.0</td>
</tr>
<tr id="1833">
<td><a href="https://cplusplus.github.io/CWG/issues/1833.html">1833</a></td>
Expand Down Expand Up @@ -13632,7 +13632,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2304.html">2304</a></td>
<td>NAD</td>
<td>Incomplete type vs overload resolution</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.8</td>
</tr>
<tr id="2305">
<td><a href="https://cplusplus.github.io/CWG/issues/2305.html">2305</a></td>
Expand Down Expand Up @@ -13668,7 +13668,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2310.html">2310</a></td>
<td>CD5</td>
<td>Type completeness and derived-to-base pointer conversions</td>
<td class="unknown" align="center">Unknown</td>
<td class="partial" align="center">Partial</td>
</tr>
<tr class="open" id="2311">
<td><a href="https://cplusplus.github.io/CWG/issues/2311.html">2311</a></td>
Expand Down Expand Up @@ -14388,7 +14388,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2430.html">2430</a></td>
<td>C++20</td>
<td>Completeness of return and parameter types of member functions</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.7</td>
</tr>
<tr id="2431">
<td><a href="https://cplusplus.github.io/CWG/issues/2431.html">2431</a></td>
Expand Down Expand Up @@ -14880,7 +14880,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2512.html">2512</a></td>
<td>NAD</td>
<td><TT>typeid</TT> and incomplete class types</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.7</td>
</tr>
<tr class="open" id="2513">
<td><a href="https://cplusplus.github.io/CWG/issues/2513.html">2513</a></td>
Expand Down Expand Up @@ -15588,7 +15588,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2630.html">2630</a></td>
<td>C++23</td>
<td>Syntactic specification of class completeness</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 9</td>
</tr>
<tr id="2631">
<td><a href="https://cplusplus.github.io/CWG/issues/2631.html">2631</a></td>
Expand Down Expand Up @@ -16116,7 +16116,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2718.html">2718</a></td>
<td>DRWP</td>
<td>Type completeness for derived-to-base conversions</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.7</td>
</tr>
<tr id="2719">
<td><a href="https://cplusplus.github.io/CWG/issues/2719.html">2719</a></td>
Expand Down Expand Up @@ -16951,7 +16951,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2857.html">2857</a></td>
<td>DR</td>
<td>Argument-dependent lookup with incomplete class types</td>
<td class="unknown" align="center">Unknown</td>
<td class="none" align="center">No</td>
</tr>
<tr class="open" id="2858">
<td><a href="https://cplusplus.github.io/CWG/issues/2858.html">2858</a></td>
Expand Down Expand Up @@ -16985,7 +16985,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
</tr>
<tr class="open" id="2863">
<td><a href="https://cplusplus.github.io/CWG/issues/2863.html">2863</a></td>
<td>tentatively ready</td>
<td>drafting</td>
<td>Unclear synchronization requirements for object lifetime rules</td>
<td align="center">Not resolved</td>
</tr>
Expand Down Expand Up @@ -17021,13 +17021,13 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
</tr>
<tr class="open" id="2869">
<td><a href="https://cplusplus.github.io/CWG/issues/2869.html">2869</a></td>
<td>open</td>
<td>review</td>
<td><TT>this</TT> in local classes</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="2870">
<td><a href="https://cplusplus.github.io/CWG/issues/2870.html">2870</a></td>
<td>open</td>
<td>review</td>
<td>Combining absent <I>encoding-prefix</I>es</td>
<td align="center">Not resolved</td>
</tr>
Expand Down Expand Up @@ -17138,6 +17138,18 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td>open</td>
<td>Missing cases for reference and array types for argument-dependent lookup</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="2889">
<td><a href="https://cplusplus.github.io/CWG/issues/2889.html">2889</a></td>
<td>open</td>
<td>Requiring an accessible destructor for destroying operator delete</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="2890">
<td><a href="https://cplusplus.github.io/CWG/issues/2890.html">2890</a></td>
<td>open</td>
<td>Defining members of local classes</td>
<td align="center">Not resolved</td>
</tr></table>

</div>
Expand Down
371 changes: 221 additions & 150 deletions compiler-rt/lib/scudo/standalone/combined.h

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

class DexExpectStepOrder(CommandBase):
"""Expect the line every `DexExpectStepOrder` is found on to be stepped on
in `order`. Each instance must have a set of unique ascending indicies.
in `order`. Each instance must have a set of unique ascending indices.
DexExpectStepOrder(*order)
Expand Down
2 changes: 1 addition & 1 deletion flang/docs/HighLevelFIR.md
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ Syntax:

Note that %indices are not operands, they are the elemental region block
arguments, representing the array iteration space in a one based fashion.
The choice of using one based indicies is to match Fortran default for
The choice of using one based indices is to match Fortran default for
array variables, so that there is no need to generate bound adjustments
when working with one based array variables in an expression.

Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ class DebugUnparseWithSymbolsAction : public PrescanAndSemaAction {
void executeAction() override;
};

class DebugUnparseWithModulesAction : public PrescanAndSemaAction {
void executeAction() override;
};

class DebugUnparseAction : public PrescanAndSemaAction {
void executeAction() override;
};
Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ enum ActionKind {
/// Fortran source file
DebugUnparseWithSymbols,

/// Parse, run semantics, and output a Fortran source file preceded
/// by all the necessary modules (transitively)
DebugUnparseWithModules,

/// Parse, run semantics and then output symbols from semantics
DebugDumpSymbols,

Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Lower/LoweringOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ ENUM_LOWERINGOPT(NoPPCNativeVecElemOrder, unsigned, 1, 0)
/// On by default.
ENUM_LOWERINGOPT(Underscoring, unsigned, 1, 1)

/// If true, add nsw flags to loop variable increments.
/// Off by default.
ENUM_LOWERINGOPT(NSWOnLoopVarInc, unsigned, 1, 0)

#undef LOWERINGOPT
#undef ENUM_LOWERINGOPT
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef OPTIMIZER_CODEGEN_CGOPS_H
#define OPTIMIZER_CODEGEN_CGOPS_H

#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"

Expand Down
34 changes: 34 additions & 0 deletions flang/include/flang/Optimizer/CodeGen/CGOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

include "mlir/IR/SymbolInterfaces.td"
include "flang/Optimizer/Dialect/FIRTypes.td"
include "flang/Optimizer/Dialect/FIRAttr.td"
include "mlir/IR/BuiltinAttributes.td"

def fircg_Dialect : Dialect {
let name = "fircg";
Expand Down Expand Up @@ -202,4 +204,36 @@ def fircg_XArrayCoorOp : fircg_Op<"ext_array_coor", [AttrSizedOperandSegments]>
}];
}

// Extended Declare operation.
def fircg_XDeclareOp : fircg_Op<"ext_declare", [AttrSizedOperandSegments]> {
let summary = "for internal conversion only";

let description = [{
Prior to lowering to LLVM IR dialect, a DeclareOp will
be converted to an extended DeclareOp.
}];

let arguments = (ins
AnyRefOrBox:$memref,
Variadic<AnyIntegerType>:$shape,
Variadic<AnyIntegerType>:$shift,
Variadic<AnyIntegerType>:$typeparams,
Optional<fir_DummyScopeType>:$dummy_scope,
Builtin_StringAttr:$uniq_name
);
let results = (outs AnyRefOrBox);

let assemblyFormat = [{
$memref (`(` $shape^ `)`)? (`origin` $shift^)? (`typeparams` $typeparams^)?
(`dummy_scope` $dummy_scope^)?
attr-dict `:` functional-type(operands, results)
}];

let extraClassDeclaration = [{
// Shape is optional, but if it exists, it will be at offset 1.
unsigned shapeOffset() { return 1; }
unsigned shiftOffset() { return shapeOffset() + getShape().size(); }
}];
}

#endif
4 changes: 4 additions & 0 deletions flang/include/flang/Optimizer/CodeGen/CGPasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ def CodeGenRewrite : Pass<"cg-rewrite", "mlir::ModuleOp"> {
let dependentDialects = [
"fir::FIROpsDialect", "fir::FIRCodeGenDialect"
];
let options = [
Option<"preserveDeclare", "preserve-declare", "bool", /*default=*/"false",
"Preserve DeclareOp during pre codegen re-write.">
];
let statistics = [
Statistic<"numDCE", "num-dce'd", "Number of operations eliminated">
];
Expand Down
6 changes: 4 additions & 2 deletions flang/include/flang/Optimizer/CodeGen/CodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ struct NameUniquer;

/// Prerequiste pass for code gen. Perform intermediate rewrites to perform
/// the code gen (to LLVM-IR dialect) conversion.
std::unique_ptr<mlir::Pass> createFirCodeGenRewritePass();
std::unique_ptr<mlir::Pass> createFirCodeGenRewritePass(
CodeGenRewriteOptions Options = CodeGenRewriteOptions{});

/// FirTargetRewritePass options.
struct TargetRewriteOptions {
Expand Down Expand Up @@ -88,7 +89,8 @@ void populateFIRToLLVMConversionPatterns(fir::LLVMTypeConverter &converter,
fir::FIRToLLVMPassOptions &options);

/// Populate the pattern set with the PreCGRewrite patterns.
void populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns);
void populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns,
bool preserveDeclare);

// declarative passes
#define GEN_PASS_REGISTRATION
Expand Down
4 changes: 3 additions & 1 deletion flang/include/flang/Optimizer/Transforms/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ namespace fir {
std::unique_ptr<mlir::Pass> createAffineDemotionPass();
std::unique_ptr<mlir::Pass>
createArrayValueCopyPass(fir::ArrayValueCopyOptions options = {});
std::unique_ptr<mlir::Pass> createCFGConversionPassWithNSW();
std::unique_ptr<mlir::Pass> createExternalNameConversionPass();
std::unique_ptr<mlir::Pass>
createExternalNameConversionPass(bool appendUnderscore);
Expand Down Expand Up @@ -89,7 +90,8 @@ createFunctionAttrPass(FunctionAttrTypes &functionAttr, bool noInfsFPMath,
bool noSignedZerosFPMath, bool unsafeFPMath);

void populateCfgConversionRewrites(mlir::RewritePatternSet &patterns,
bool forceLoopToExecuteOnce = false);
bool forceLoopToExecuteOnce = false,
bool setNSW = false);

// declarative passes
#define GEN_PASS_REGISTRATION
Expand Down
5 changes: 4 additions & 1 deletion flang/include/flang/Optimizer/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ def CFGConversion : Pass<"cfg-conversion"> {
let options = [
Option<"forceLoopToExecuteOnce", "always-execute-loop-body", "bool",
/*default=*/"false",
"force the body of a loop to execute at least once">
"force the body of a loop to execute at least once">,
Option<"setNSW", "set-nsw", "bool",
/*default=*/"false",
"set nsw on loop variable increment">
];
}

Expand Down
1 change: 1 addition & 0 deletions flang/include/flang/Parser/dump-parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ class ParseTreeDumper {
NODE(parser, CUFKernelDoConstruct)
NODE(CUFKernelDoConstruct, StarOrExpr)
NODE(CUFKernelDoConstruct, Directive)
NODE(parser, CUFReduction)
NODE(parser, CycleStmt)
NODE(parser, DataComponentDefStmt)
NODE(parser, DataIDoObject)
Expand Down
18 changes: 15 additions & 3 deletions flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -4303,20 +4303,32 @@ struct OpenACCConstruct {
};

// CUF-kernel-do-construct ->
// !$CUF KERNEL DO [ (scalar-int-constant-expr) ] <<< grid, block [, stream]
// >>> do-construct
// !$CUF KERNEL DO [ (scalar-int-constant-expr) ]
// <<< grid, block [, stream] >>>
// [ cuf-reduction... ]
// do-construct
// star-or-expr -> * | scalar-int-expr
// grid -> * | scalar-int-expr | ( star-or-expr-list )
// block -> * | scalar-int-expr | ( star-or-expr-list )
// stream -> 0, scalar-int-expr | STREAM = scalar-int-expr
// cuf-reduction -> [ REDUCE | REDUCTION ] (
// acc-reduction-op : scalar-variable-list )

struct CUFReduction {
TUPLE_CLASS_BOILERPLATE(CUFReduction);
using Operator = AccReductionOperator;
std::tuple<Operator, std::list<Scalar<Variable>>> t;
};

struct CUFKernelDoConstruct {
TUPLE_CLASS_BOILERPLATE(CUFKernelDoConstruct);
WRAPPER_CLASS(StarOrExpr, std::optional<ScalarIntExpr>);
struct Directive {
TUPLE_CLASS_BOILERPLATE(Directive);
CharBlock source;
std::tuple<std::optional<ScalarIntConstantExpr>, std::list<StarOrExpr>,
std::list<StarOrExpr>, std::optional<ScalarIntExpr>>
std::list<StarOrExpr>, std::optional<ScalarIntExpr>,
std::list<CUFReduction>>
t;
};
std::tuple<Directive, std::optional<DoConstruct>> t;
Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Semantics/unparse-with-symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ struct Program;
}

namespace Fortran::semantics {
class SemanticsContext;
void UnparseWithSymbols(llvm::raw_ostream &, const parser::Program &,
parser::Encoding encoding = parser::Encoding::UTF_8);
void UnparseWithModules(llvm::raw_ostream &, SemanticsContext &,
const parser::Program &,
parser::Encoding encoding = parser::Encoding::UTF_8);
}

#endif // FORTRAN_SEMANTICS_UNPARSE_WITH_SYMBOLS_H_
24 changes: 16 additions & 8 deletions flang/include/flang/Tools/CLOptions.inc
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,14 @@ static void addCanonicalizerPassWithoutRegionSimplification(
pm.addPass(mlir::createCanonicalizerPass(config));
}

inline void addCfgConversionPass(mlir::PassManager &pm) {
addNestedPassToAllTopLevelOperationsConditionally(
pm, disableCfgConversion, fir::createCFGConversion);
inline void addCfgConversionPass(
mlir::PassManager &pm, const MLIRToLLVMPassPipelineConfig &config) {
if (config.NSWOnLoopVarInc)
addNestedPassToAllTopLevelOperationsConditionally(
pm, disableCfgConversion, fir::createCFGConversionPassWithNSW);
else
addNestedPassToAllTopLevelOperationsConditionally(
pm, disableCfgConversion, fir::createCFGConversion);
}

inline void addAVC(
Expand All @@ -169,9 +174,11 @@ inline void addMemoryAllocationOpt(mlir::PassManager &pm) {
}

#if !defined(FLANG_EXCLUDE_CODEGEN)
inline void addCodeGenRewritePass(mlir::PassManager &pm) {
addPassConditionally(
pm, disableCodeGenRewrite, fir::createFirCodeGenRewritePass);
inline void addCodeGenRewritePass(mlir::PassManager &pm, bool preserveDeclare) {
fir::CodeGenRewriteOptions options;
options.preserveDeclare = preserveDeclare;
addPassConditionally(pm, disableCodeGenRewrite,
[&]() { return fir::createFirCodeGenRewritePass(options); });
}

inline void addTargetRewritePass(mlir::PassManager &pm) {
Expand Down Expand Up @@ -290,7 +297,7 @@ inline void createDefaultFIROptimizerPassPipeline(
pm.addPass(fir::createAliasTagsPass());

// convert control flow to CFG form
fir::addCfgConversionPass(pm);
fir::addCfgConversionPass(pm, pc);
pm.addPass(mlir::createConvertSCFToCFPass());

pm.addPass(mlir::createCanonicalizerPass(config));
Expand Down Expand Up @@ -353,7 +360,8 @@ inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
MLIRToLLVMPassPipelineConfig config, llvm::StringRef inputFilename = {}) {
fir::addBoxedProcedurePass(pm);
addNestedPassToAllTopLevelOperations(pm, fir::createAbstractResultOpt);
fir::addCodeGenRewritePass(pm);
fir::addCodeGenRewritePass(
pm, (config.DebugInfo != llvm::codegenoptions::NoDebugInfo));
fir::addTargetRewritePass(pm);
fir::addExternalNameConversionPass(pm, config.Underscoring);
fir::createDebugPasses(pm, config.DebugInfo, config.OptLevel, inputFilename);
Expand Down
1 change: 1 addition & 0 deletions flang/include/flang/Tools/CrossToolHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
bool NoSignedZerosFPMath =
false; ///< Set no-signed-zeros-fp-math attribute for functions.
bool UnsafeFPMath = false; ///< Set unsafe-fp-math attribute for functions.
bool NSWOnLoopVarInc = false; ///< Add nsw flag to loop variable increments.
};

struct OffloadModuleOpts {
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Evaluate/fold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ std::optional<Expr<SomeType>> FoldTransfer(
}
}
if (sourceBytes && IsActuallyConstant(*source) && moldType && extents &&
!moldType->IsPolymorphic() &&
(moldLength || moldType->category() != TypeCategory::Character)) {
std::size_t elements{
extents->empty() ? 1 : static_cast<std::size_t>((*extents)[0])};
Expand Down
9 changes: 9 additions & 0 deletions flang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,9 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
case clang::driver::options::OPT_fdebug_unparse_with_symbols:
opts.programAction = DebugUnparseWithSymbols;
break;
case clang::driver::options::OPT_fdebug_unparse_with_modules:
opts.programAction = DebugUnparseWithModules;
break;
case clang::driver::options::OPT_fdebug_dump_symbols:
opts.programAction = DebugDumpSymbols;
break;
Expand Down Expand Up @@ -1203,6 +1206,12 @@ bool CompilerInvocation::createFromArgs(
invoc.loweringOpts.setNoPPCNativeVecElemOrder(true);
}

// -flang-experimental-integer-overflow
if (args.hasArg(
clang::driver::options::OPT_flang_experimental_integer_overflow)) {
invoc.loweringOpts.setNSWOnLoopVarInc(true);
}

// Preserve all the remark options requested, i.e. -Rpass, -Rpass-missed or
// -Rpass-analysis. This will be used later when processing and outputting the
// remarks generated by LLVM in ExecuteCompilerInvocation.cpp.
Expand Down
12 changes: 12 additions & 0 deletions flang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,15 @@ void DebugUnparseWithSymbolsAction::executeAction() {
reportFatalSemanticErrors();
}

void DebugUnparseWithModulesAction::executeAction() {
auto &parseTree{*getInstance().getParsing().parseTree()};
CompilerInstance &ci{getInstance()};
Fortran::semantics::UnparseWithModules(
llvm::outs(), ci.getSemantics().context(), parseTree,
/*encoding=*/Fortran::parser::Encoding::UTF_8);
reportFatalSemanticErrors();
}

void DebugDumpSymbolsAction::executeAction() {
CompilerInstance &ci = this->getInstance();

Expand Down Expand Up @@ -809,6 +818,9 @@ void CodeGenAction::generateLLVMIR() {
config.VScaleMax = vsr->second;
}

if (ci.getInvocation().getLoweringOpts().getNSWOnLoopVarInc())
config.NSWOnLoopVarInc = true;

// Create the pass pipeline
fir::createMLIRToLLVMPassPipeline(pm, config, getCurrentFile());
(void)mlir::applyPassManagerCLOptions(pm);
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ createFrontendAction(CompilerInstance &ci) {
return std::make_unique<DebugUnparseNoSemaAction>();
case DebugUnparseWithSymbols:
return std::make_unique<DebugUnparseWithSymbolsAction>();
case DebugUnparseWithModules:
return std::make_unique<DebugUnparseWithModulesAction>();
case DebugDumpSymbols:
return std::make_unique<DebugDumpSymbolsAction>();
case DebugDumpParseTree:
Expand Down
12 changes: 9 additions & 3 deletions flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2007,6 +2007,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
void genFIRIncrementLoopEnd(IncrementLoopNestInfo &incrementLoopNestInfo) {
assert(!incrementLoopNestInfo.empty() && "empty loop nest");
mlir::Location loc = toLocation();
mlir::arith::IntegerOverflowFlags flags{};
if (getLoweringOptions().getNSWOnLoopVarInc())
flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(
builder->getContext(), flags);
for (auto it = incrementLoopNestInfo.rbegin(),
rend = incrementLoopNestInfo.rend();
it != rend; ++it) {
Expand All @@ -2021,15 +2026,16 @@ class FirConverter : public Fortran::lower::AbstractConverter {
builder->setInsertionPointToEnd(info.doLoop.getBody());
llvm::SmallVector<mlir::Value, 2> results;
results.push_back(builder->create<mlir::arith::AddIOp>(
loc, info.doLoop.getInductionVar(), info.doLoop.getStep()));
loc, info.doLoop.getInductionVar(), info.doLoop.getStep(),
iofAttr));
// Step loopVariable to help optimizations such as vectorization.
// Induction variable elimination will clean up as necessary.
mlir::Value step = builder->createConvert(
loc, info.getLoopVariableType(), info.doLoop.getStep());
mlir::Value loopVar =
builder->create<fir::LoadOp>(loc, info.loopVariable);
results.push_back(
builder->create<mlir::arith::AddIOp>(loc, loopVar, step));
builder->create<mlir::arith::AddIOp>(loc, loopVar, step, iofAttr));
builder->create<fir::ResultOp>(loc, results);
builder->setInsertionPointAfter(info.doLoop);
// The loop control variable may be used after the loop.
Expand All @@ -2054,7 +2060,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
if (info.hasRealControl)
value = builder->create<mlir::arith::AddFOp>(loc, value, step);
else
value = builder->create<mlir::arith::AddIOp>(loc, value, step);
value = builder->create<mlir::arith::AddIOp>(loc, value, step, iofAttr);
builder->create<fir::StoreOp>(loc, value, info.loopVariable);

genBranch(info.headerBlock);
Expand Down
9 changes: 7 additions & 2 deletions flang/lib/Lower/IO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,11 @@ static void genIoLoop(Fortran::lower::AbstractConverter &converter,
Fortran::lower::StatementContext stmtCtx;
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
mlir::Location loc = converter.getCurrentLocation();
mlir::arith::IntegerOverflowFlags flags{};
if (converter.getLoweringOptions().getNSWOnLoopVarInc())
flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
auto iofAttr =
mlir::arith::IntegerOverflowFlagsAttr::get(builder.getContext(), flags);
makeNextConditionalOn(builder, loc, checkResult, ok, inLoop);
const auto &itemList = std::get<0>(ioImpliedDo.t);
const auto &control = std::get<1>(ioImpliedDo.t);
Expand Down Expand Up @@ -965,7 +970,7 @@ static void genIoLoop(Fortran::lower::AbstractConverter &converter,
genItemList(ioImpliedDo);
builder.setInsertionPointToEnd(doLoopOp.getBody());
mlir::Value result = builder.create<mlir::arith::AddIOp>(
loc, doLoopOp.getInductionVar(), doLoopOp.getStep());
loc, doLoopOp.getInductionVar(), doLoopOp.getStep(), iofAttr);
builder.create<fir::ResultOp>(loc, result);
builder.setInsertionPointAfter(doLoopOp);
// The loop control variable may be used after the loop.
Expand Down Expand Up @@ -1007,7 +1012,7 @@ static void genIoLoop(Fortran::lower::AbstractConverter &converter,
mlir::OpResult iterateResult = builder.getBlock()->back().getResult(0);
mlir::Value inductionResult0 = iterWhileOp.getInductionVar();
auto inductionResult1 = builder.create<mlir::arith::AddIOp>(
loc, inductionResult0, iterWhileOp.getStep());
loc, inductionResult0, iterWhileOp.getStep(), iofAttr);
auto inductionResult = builder.create<mlir::arith::SelectOp>(
loc, iterateResult, inductionResult1, inductionResult0);
llvm::SmallVector<mlir::Value> results = {inductionResult, iterateResult};
Expand Down
232 changes: 103 additions & 129 deletions flang/lib/Lower/OpenMP/OpenMP.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion flang/lib/Optimizer/CodeGen/CGOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "CGOps.h"
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
Expand Down
50 changes: 36 additions & 14 deletions flang/lib/Optimizer/CodeGen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#include "flang/Optimizer/CodeGen/CodeGen.h"

#include "CGOps.h"
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/CodeGen/CodeGenOpenMP.h"
#include "flang/Optimizer/CodeGen/FIROpPatterns.h"
#include "flang/Optimizer/CodeGen/TypeConverter.h"
Expand Down Expand Up @@ -170,6 +170,28 @@ genAllocationScaleSize(OP op, mlir::Type ity,
return nullptr;
}

namespace {
struct DeclareOpConversion : public fir::FIROpConversion<fir::cg::XDeclareOp> {
public:
using FIROpConversion::FIROpConversion;
mlir::LogicalResult
matchAndRewrite(fir::cg::XDeclareOp declareOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
auto memRef = adaptor.getOperands()[0];
if (auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(declareOp.getLoc())) {
if (auto varAttr =
mlir::dyn_cast_or_null<mlir::LLVM::DILocalVariableAttr>(
fusedLoc.getMetadata())) {
rewriter.create<mlir::LLVM::DbgDeclareOp>(memRef.getLoc(), memRef,
varAttr, nullptr);
}
}
rewriter.replaceOp(declareOp, memRef);
return mlir::success();
}
};
} // namespace

namespace {
/// convert to LLVM IR dialect `alloca`
struct AllocaOpConversion : public fir::FIROpConversion<fir::AllocaOp> {
Expand Down Expand Up @@ -3714,19 +3736,19 @@ void fir::populateFIRToLLVMConversionPatterns(
BoxOffsetOpConversion, BoxProcHostOpConversion, BoxRankOpConversion,
BoxTypeCodeOpConversion, BoxTypeDescOpConversion, CallOpConversion,
CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
CoordinateOpConversion, DTEntryOpConversion, DivcOpConversion,
EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
FreeMemOpConversion, GlobalLenOpConversion, GlobalOpConversion,
HasValueOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion,
MulcOpConversion, NegcOpConversion, NoReassocOpConversion,
SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion,
ShiftOpConversion, SliceOpConversion, StoreOpConversion,
StringLitOpConversion, SubcOpConversion, TypeDescOpConversion,
TypeInfoOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
UndefOpConversion, UnreachableOpConversion,
CoordinateOpConversion, DTEntryOpConversion, DeclareOpConversion,
DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion,
FirEndOpConversion, FreeMemOpConversion, GlobalLenOpConversion,
GlobalOpConversion, HasValueOpConversion, InsertOnRangeOpConversion,
InsertValueOpConversion, IsPresentOpConversion, LenParamIndexOpConversion,
LoadOpConversion, MulcOpConversion, NegcOpConversion,
NoReassocOpConversion, SelectCaseOpConversion, SelectOpConversion,
SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion,
ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion,
StoreOpConversion, StringLitOpConversion, SubcOpConversion,
TypeDescOpConversion, TypeInfoOpConversion, UnboxCharOpConversion,
UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion,
UnrealizedConversionCastOpConversion, XArrayCoorOpConversion,
XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(converter,
options);
Expand Down
49 changes: 41 additions & 8 deletions flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

#include "flang/Optimizer/CodeGen/CodeGen.h"

#include "CGOps.h"
#include "flang/Optimizer/Builder/Todo.h" // remove when TODO's are done
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
Expand Down Expand Up @@ -270,13 +270,43 @@ class ArrayCoorConversion : public mlir::OpRewritePattern<fir::ArrayCoorOp> {
};

class DeclareOpConversion : public mlir::OpRewritePattern<fir::DeclareOp> {
bool preserveDeclare;

public:
using OpRewritePattern::OpRewritePattern;
DeclareOpConversion(mlir::MLIRContext *ctx, bool preserveDecl)
: OpRewritePattern(ctx), preserveDeclare(preserveDecl) {}

mlir::LogicalResult
matchAndRewrite(fir::DeclareOp declareOp,
mlir::PatternRewriter &rewriter) const override {
rewriter.replaceOp(declareOp, declareOp.getMemref());
if (!preserveDeclare) {
rewriter.replaceOp(declareOp, declareOp.getMemref());
return mlir::success();
}
auto loc = declareOp.getLoc();
llvm::SmallVector<mlir::Value> shapeOpers;
llvm::SmallVector<mlir::Value> shiftOpers;
if (auto shapeVal = declareOp.getShape()) {
if (auto shapeOp = mlir::dyn_cast<fir::ShapeOp>(shapeVal.getDefiningOp()))
populateShape(shapeOpers, shapeOp);
else if (auto shiftOp =
mlir::dyn_cast<fir::ShapeShiftOp>(shapeVal.getDefiningOp()))
populateShapeAndShift(shapeOpers, shiftOpers, shiftOp);
else if (auto shiftOp =
mlir::dyn_cast<fir::ShiftOp>(shapeVal.getDefiningOp()))
populateShift(shiftOpers, shiftOp);
else
return mlir::failure();
}
// FIXME: Add FortranAttrs and CudaAttrs
auto xDeclOp = rewriter.create<fir::cg::XDeclareOp>(
loc, declareOp.getType(), declareOp.getMemref(), shapeOpers, shiftOpers,
declareOp.getTypeparams(), declareOp.getDummyScope(),
declareOp.getUniqName());
LLVM_DEBUG(llvm::dbgs()
<< "rewriting " << declareOp << " to " << xDeclOp << '\n');
rewriter.replaceOp(declareOp, xDeclOp.getOperation()->getResults());
return mlir::success();
}
};
Expand All @@ -297,6 +327,7 @@ class DummyScopeOpConversion

class CodeGenRewrite : public fir::impl::CodeGenRewriteBase<CodeGenRewrite> {
public:
CodeGenRewrite(fir::CodeGenRewriteOptions opts) : Base(opts) {}
void runOnOperation() override final {
mlir::ModuleOp mod = getOperation();

Expand All @@ -314,7 +345,7 @@ class CodeGenRewrite : public fir::impl::CodeGenRewriteBase<CodeGenRewrite> {
mlir::cast<fir::BaseBoxType>(embox.getType()).getEleTy()));
});
mlir::RewritePatternSet patterns(&context);
fir::populatePreCGRewritePatterns(patterns);
fir::populatePreCGRewritePatterns(patterns, preserveDeclare);
if (mlir::failed(
mlir::applyPartialConversion(mod, target, std::move(patterns)))) {
mlir::emitError(mlir::UnknownLoc::get(&context),
Expand All @@ -330,12 +361,14 @@ class CodeGenRewrite : public fir::impl::CodeGenRewriteBase<CodeGenRewrite> {

} // namespace

std::unique_ptr<mlir::Pass> fir::createFirCodeGenRewritePass() {
return std::make_unique<CodeGenRewrite>();
std::unique_ptr<mlir::Pass>
fir::createFirCodeGenRewritePass(fir::CodeGenRewriteOptions Options) {
return std::make_unique<CodeGenRewrite>(Options);
}

void fir::populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns) {
void fir::populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns,
bool preserveDeclare) {
patterns.insert<EmboxConversion, ArrayCoorConversion, ReboxConversion,
DeclareOpConversion, DummyScopeOpConversion>(
patterns.getContext());
DummyScopeOpConversion>(patterns.getContext());
patterns.add<DeclareOpConversion>(patterns.getContext(), preserveDeclare);
}
60 changes: 56 additions & 4 deletions flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "flang/Common/Version.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
Expand Down Expand Up @@ -45,13 +46,59 @@ namespace fir {
namespace {

class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
void handleDeclareOp(fir::cg::XDeclareOp declOp,
mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scopeAttr,
fir::DebugTypeGenerator &typeGen);

public:
AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {}
void runOnOperation() override;
};

static uint32_t getLineFromLoc(mlir::Location loc) {
uint32_t line = 1;
if (auto fileLoc = mlir::dyn_cast<mlir::FileLineColLoc>(loc))
line = fileLoc.getLine();
return line;
}

} // namespace

void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp,
mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scopeAttr,
fir::DebugTypeGenerator &typeGen) {
mlir::MLIRContext *context = &getContext();
mlir::OpBuilder builder(context);
auto result = fir::NameUniquer::deconstruct(declOp.getUniqName());

if (result.first != fir::NameUniquer::NameKind::VARIABLE)
return;

// Only accept local variables.
if (result.second.procs.empty())
return;

// FIXME: There may be cases where an argument is processed a bit before
// DeclareOp is generated. In that case, DeclareOp may point to an
// intermediate op and not to BlockArgument. We need to find those cases and
// walk the chain to get to the actual argument.

unsigned argNo = 0;
if (auto Arg = llvm::dyn_cast<mlir::BlockArgument>(declOp.getMemref()))
argNo = Arg.getArgNumber() + 1;

auto tyAttr = typeGen.convertType(fir::unwrapRefType(declOp.getType()),
fileAttr, scopeAttr, declOp.getLoc());

auto localVarAttr = mlir::LLVM::DILocalVariableAttr::get(
context, scopeAttr, mlir::StringAttr::get(context, result.second.name),
fileAttr, getLineFromLoc(declOp.getLoc()), argNo, /* alignInBits*/ 0,
tyAttr);
declOp->setLoc(builder.getFusedLoc({declOp->getLoc()}, localVarAttr));
}

void AddDebugInfoPass::runOnOperation() {
mlir::ModuleOp module = getOperation();
mlir::MLIRContext *context = &getContext();
Expand Down Expand Up @@ -144,14 +191,19 @@ void AddDebugInfoPass::runOnOperation() {
subprogramFlags =
subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
}
unsigned line = 1;
if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l))
line = funcLoc.getLine();

unsigned line = getLineFromLoc(l);
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
context, id, compilationUnit, fileAttr, funcName, fullName,
funcFileAttr, line, line, subprogramFlags, subTypeAttr);
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));

// Don't process variables if user asked for line tables only.
if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly)
return;

funcOp.walk([&](fir::cg::XDeclareOp declOp) {
handleDeclareOp(declOp, fileAttr, spAttr, typeGen);
});
});
}

Expand Down
44 changes: 34 additions & 10 deletions flang/lib/Optimizer/Transforms/ControlFlowConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,19 @@ class CfgLoopConv : public mlir::OpRewritePattern<fir::DoLoopOp> {
public:
using OpRewritePattern::OpRewritePattern;

CfgLoopConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce)
CfgLoopConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce, bool setNSW)
: mlir::OpRewritePattern<fir::DoLoopOp>(ctx),
forceLoopToExecuteOnce(forceLoopToExecuteOnce) {}
forceLoopToExecuteOnce(forceLoopToExecuteOnce), setNSW(setNSW) {}

mlir::LogicalResult
matchAndRewrite(DoLoopOp loop,
mlir::PatternRewriter &rewriter) const override {
auto loc = loop.getLoc();
mlir::arith::IntegerOverflowFlags flags{};
if (setNSW)
flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(
rewriter.getContext(), flags);

// Create the start and end blocks that will wrap the DoLoopOp with an
// initalizer and an end point
Expand Down Expand Up @@ -104,7 +109,7 @@ class CfgLoopConv : public mlir::OpRewritePattern<fir::DoLoopOp> {
rewriter.setInsertionPointToEnd(lastBlock);
auto iv = conditionalBlock->getArgument(0);
mlir::Value steppedIndex =
rewriter.create<mlir::arith::AddIOp>(loc, iv, step);
rewriter.create<mlir::arith::AddIOp>(loc, iv, step, iofAttr);
assert(steppedIndex && "must be a Value");
auto lastArg = conditionalBlock->getNumArguments() - 1;
auto itersLeft = conditionalBlock->getArgument(lastArg);
Expand Down Expand Up @@ -142,14 +147,15 @@ class CfgLoopConv : public mlir::OpRewritePattern<fir::DoLoopOp> {

private:
bool forceLoopToExecuteOnce;
bool setNSW;
};

/// Convert `fir.if` to control-flow
class CfgIfConv : public mlir::OpRewritePattern<fir::IfOp> {
public:
using OpRewritePattern::OpRewritePattern;

CfgIfConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce)
CfgIfConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce, bool setNSW)
: mlir::OpRewritePattern<fir::IfOp>(ctx) {}

mlir::LogicalResult
Expand Down Expand Up @@ -214,13 +220,19 @@ class CfgIterWhileConv : public mlir::OpRewritePattern<fir::IterWhileOp> {
public:
using OpRewritePattern::OpRewritePattern;

CfgIterWhileConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce)
: mlir::OpRewritePattern<fir::IterWhileOp>(ctx) {}
CfgIterWhileConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce,
bool setNSW)
: mlir::OpRewritePattern<fir::IterWhileOp>(ctx), setNSW(setNSW) {}

mlir::LogicalResult
matchAndRewrite(fir::IterWhileOp whileOp,
mlir::PatternRewriter &rewriter) const override {
auto loc = whileOp.getLoc();
mlir::arith::IntegerOverflowFlags flags{};
if (setNSW)
flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(
rewriter.getContext(), flags);

// Start by splitting the block containing the 'fir.do_loop' into two parts.
// The part before will get the init code, the part after will be the end
Expand Down Expand Up @@ -248,7 +260,8 @@ class CfgIterWhileConv : public mlir::OpRewritePattern<fir::IterWhileOp> {
auto *terminator = lastBodyBlock->getTerminator();
rewriter.setInsertionPointToEnd(lastBodyBlock);
auto step = whileOp.getStep();
mlir::Value stepped = rewriter.create<mlir::arith::AddIOp>(loc, iv, step);
mlir::Value stepped =
rewriter.create<mlir::arith::AddIOp>(loc, iv, step, iofAttr);
assert(stepped && "must be a Value");

llvm::SmallVector<mlir::Value> loopCarried;
Expand Down Expand Up @@ -305,17 +318,23 @@ class CfgIterWhileConv : public mlir::OpRewritePattern<fir::IterWhileOp> {
rewriter.replaceOp(whileOp, args);
return success();
}

private:
bool setNSW;
};

/// Convert FIR structured control flow ops to CFG ops.
class CfgConversion : public fir::impl::CFGConversionBase<CfgConversion> {
public:
using CFGConversionBase<CfgConversion>::CFGConversionBase;

CfgConversion(bool setNSW) { this->setNSW = setNSW; }

void runOnOperation() override {
auto *context = &this->getContext();
mlir::RewritePatternSet patterns(context);
fir::populateCfgConversionRewrites(patterns, this->forceLoopToExecuteOnce);
fir::populateCfgConversionRewrites(patterns, this->forceLoopToExecuteOnce,
this->setNSW);
mlir::ConversionTarget target(*context);
target.addLegalDialect<mlir::affine::AffineDialect,
mlir::cf::ControlFlowDialect, FIROpsDialect,
Expand All @@ -337,7 +356,12 @@ class CfgConversion : public fir::impl::CFGConversionBase<CfgConversion> {

/// Expose conversion rewriters to other passes
void fir::populateCfgConversionRewrites(mlir::RewritePatternSet &patterns,
bool forceLoopToExecuteOnce) {
bool forceLoopToExecuteOnce,
bool setNSW) {
patterns.insert<CfgLoopConv, CfgIfConv, CfgIterWhileConv>(
patterns.getContext(), forceLoopToExecuteOnce);
patterns.getContext(), forceLoopToExecuteOnce, setNSW);
}

std::unique_ptr<mlir::Pass> fir::createCFGConversionPassWithNSW() {
return std::make_unique<CfgConversion>(true);
}
10 changes: 5 additions & 5 deletions flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m)
LLVM_DEBUG(llvm::dbgs() << "DITypeAttr generator\n");
}

static mlir::LLVM::DITypeAttr genPlaceholderType(mlir::MLIRContext *context) {
return mlir::LLVM::DIBasicTypeAttr::get(
context, llvm::dwarf::DW_TAG_base_type, "void", 32, 1);
}

static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
mlir::StringAttr name,
unsigned bitSize,
Expand All @@ -37,6 +32,11 @@ static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
context, llvm::dwarf::DW_TAG_base_type, name, bitSize, decoding);
}

static mlir::LLVM::DITypeAttr genPlaceholderType(mlir::MLIRContext *context) {
return genBasicType(context, mlir::StringAttr::get(context, "integer"), 32,
llvm::dwarf::DW_ATE_signed);
}

mlir::LLVM::DITypeAttr
DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scope,
Expand Down
23 changes: 16 additions & 7 deletions flang/lib/Parser/executable-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,25 +538,34 @@ TYPE_CONTEXT_PARSER("UNLOCK statement"_en_US,
construct<UnlockStmt>("UNLOCK (" >> lockVariable,
defaulted("," >> nonemptyList(statOrErrmsg)) / ")"))

// CUF-kernel-do-construct -> CUF-kernel-do-directive do-construct
// CUF-kernel-do-directive ->
// !$CUF KERNEL DO [ (scalar-int-constant-expr) ] <<< grid, block [, stream]
// >>> do-construct
// CUF-kernel-do-construct ->
// !$CUF KERNEL DO [ (scalar-int-constant-expr) ]
// <<< grid, block [, stream] >>>
// [ cuf-reduction... ]
// do-construct
// star-or-expr -> * | scalar-int-expr
// grid -> * | scalar-int-expr | ( star-or-expr-list )
// block -> * | scalar-int-expr | ( star-or-expr-list )
// stream -> ( 0, | STREAM = ) scalar-int-expr
// stream -> 0, scalar-int-expr | STREAM = scalar-int-expr
// cuf-reduction -> [ REDUCTION | REDUCE ] (
// acc-reduction-op : scalar-variable-list )

constexpr auto starOrExpr{construct<CUFKernelDoConstruct::StarOrExpr>(
"*" >> pure<std::optional<ScalarIntExpr>>() ||
applyFunction(presentOptional<ScalarIntExpr>, scalarIntExpr))};
constexpr auto gridOrBlock{parenthesized(nonemptyList(starOrExpr)) ||
applyFunction(singletonList<CUFKernelDoConstruct::StarOrExpr>, starOrExpr)};

TYPE_PARSER(("REDUCTION"_tok || "REDUCE"_tok) >>
parenthesized(construct<CUFReduction>(Parser<CUFReduction::Operator>{},
":" >> nonemptyList(scalar(variable)))))

TYPE_PARSER(sourced(beginDirective >> "$CUF KERNEL DO"_tok >>
construct<CUFKernelDoConstruct::Directive>(
maybe(parenthesized(scalarIntConstantExpr)), "<<<" >> gridOrBlock,
"," >> gridOrBlock,
maybe((", 0 ,"_tok || ", STREAM ="_tok) >> scalarIntExpr) / ">>>" /
endDirective)))
maybe((", 0 ,"_tok || ", STREAM ="_tok) >> scalarIntExpr) / ">>>",
many(Parser<CUFReduction>{}) / endDirective)))
TYPE_CONTEXT_PARSER("!$CUF KERNEL DO construct"_en_US,
extension<LanguageFeature::CUDA>(construct<CUFKernelDoConstruct>(
Parser<CUFKernelDoConstruct::Directive>{},
Expand Down
6 changes: 3 additions & 3 deletions flang/lib/Parser/openacc-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
// OpenACC Directives and Clauses
namespace Fortran::parser {

constexpr auto startAccLine = skipStuffBeforeStatement >>
("!$ACC "_sptok || "C$ACC "_sptok || "*$ACC "_sptok);
constexpr auto endAccLine = space >> endOfLine;
constexpr auto startAccLine{skipStuffBeforeStatement >>
("!$ACC "_sptok || "C$ACC "_sptok || "*$ACC "_sptok)};
constexpr auto endAccLine{space >> endOfLine};

// Autogenerated clauses parser. Information is taken from ACC.td and the
// parser is generated by tablegen.
Expand Down
36 changes: 33 additions & 3 deletions flang/lib/Parser/unparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2705,7 +2705,6 @@ class UnparseVisitor {
void Unparse(const CLASS::ENUM &x) { Word(CLASS::EnumToString(x)); }
WALK_NESTED_ENUM(AccDataModifier, Modifier)
WALK_NESTED_ENUM(AccessSpec, Kind) // R807
WALK_NESTED_ENUM(AccReductionOperator, Operator)
WALK_NESTED_ENUM(common, TypeParamAttr) // R734
WALK_NESTED_ENUM(common, CUDADataAttr) // CUDA
WALK_NESTED_ENUM(common, CUDASubprogramAttrs) // CUDA
Expand Down Expand Up @@ -2736,6 +2735,31 @@ class UnparseVisitor {
WALK_NESTED_ENUM(OmpOrderClause, Type) // OMP order-type
WALK_NESTED_ENUM(OmpOrderModifier, Kind) // OMP order-modifier
#undef WALK_NESTED_ENUM
void Unparse(const AccReductionOperator::Operator x) {
switch (x) {
case AccReductionOperator::Operator::Plus:
Word("+");
break;
case AccReductionOperator::Operator::Multiply:
Word("*");
break;
case AccReductionOperator::Operator::And:
Word(".AND.");
break;
case AccReductionOperator::Operator::Or:
Word(".OR.");
break;
case AccReductionOperator::Operator::Eqv:
Word(".EQV.");
break;
case AccReductionOperator::Operator::Neqv:
Word(".NEQV.");
break;
default:
Word(AccReductionOperator::EnumToString(x));
break;
}
}

void Unparse(const CUFKernelDoConstruct::StarOrExpr &x) {
if (x.v) {
Expand Down Expand Up @@ -2768,13 +2792,19 @@ class UnparseVisitor {
if (const auto &stream{std::get<3>(x.t)}) {
Word(",STREAM="), Walk(*stream);
}
Word(">>>\n");
Word(">>>");
Walk(" ", std::get<std::list<CUFReduction>>(x.t), " ");
Word("\n");
}

void Unparse(const CUFKernelDoConstruct &x) {
Walk(std::get<CUFKernelDoConstruct::Directive>(x.t));
Walk(std::get<std::optional<DoConstruct>>(x.t));
}
void Unparse(const CUFReduction &x) {
Word("REDUCE(");
Walk(std::get<CUFReduction::Operator>(x.t));
Walk(":", std::get<std::list<Scalar<Variable>>>(x.t), ",", ")");
}

void Done() const { CHECK(indent_ == 0); }

Expand Down
44 changes: 44 additions & 0 deletions flang/lib/Semantics/check-cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,46 @@ static int DoConstructTightNesting(
return 1;
}

static void CheckReduce(
SemanticsContext &context, const parser::CUFReduction &reduce) {
auto op{std::get<parser::CUFReduction::Operator>(reduce.t).v};
for (const auto &var :
std::get<std::list<parser::Scalar<parser::Variable>>>(reduce.t)) {
if (const auto &typedExprPtr{var.thing.typedExpr};
typedExprPtr && typedExprPtr->v) {
const auto &expr{*typedExprPtr->v};
if (auto type{expr.GetType()}) {
auto cat{type->category()};
bool isOk{false};
switch (op) {
case parser::AccReductionOperator::Operator::Plus:
case parser::AccReductionOperator::Operator::Multiply:
case parser::AccReductionOperator::Operator::Max:
case parser::AccReductionOperator::Operator::Min:
isOk = cat == TypeCategory::Integer || cat == TypeCategory::Real;
break;
case parser::AccReductionOperator::Operator::Iand:
case parser::AccReductionOperator::Operator::Ior:
case parser::AccReductionOperator::Operator::Ieor:
isOk = cat == TypeCategory::Integer;
break;
case parser::AccReductionOperator::Operator::And:
case parser::AccReductionOperator::Operator::Or:
case parser::AccReductionOperator::Operator::Eqv:
case parser::AccReductionOperator::Operator::Neqv:
isOk = cat == TypeCategory::Logical;
break;
}
if (!isOk) {
context.Say(var.thing.GetSource(),
"!$CUF KERNEL DO REDUCE operation is not acceptable for a variable with type %s"_err_en_US,
type->AsFortran());
}
}
}
}
}

void CUDAChecker::Enter(const parser::CUFKernelDoConstruct &x) {
auto source{std::get<parser::CUFKernelDoConstruct::Directive>(x.t).source};
const auto &directive{std::get<parser::CUFKernelDoConstruct::Directive>(x.t)};
Expand All @@ -489,6 +529,10 @@ void CUDAChecker::Enter(const parser::CUFKernelDoConstruct &x) {
if (innerBlock) {
DeviceContextChecker<true>{context_}.Check(*innerBlock);
}
for (const auto &reduce :
std::get<std::list<parser::CUFReduction>>(directive.t)) {
CheckReduce(context_, reduce);
}
}

void CUDAChecker::Enter(const parser::AssignmentStmt &x) {
Expand Down
25 changes: 20 additions & 5 deletions flang/lib/Semantics/check-declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1357,6 +1357,15 @@ bool CheckHelper::IsResultOkToDiffer(const FunctionResult &result) {

void CheckHelper::CheckSubprogram(
const Symbol &symbol, const SubprogramDetails &details) {
// Evaluate a procedure definition's characteristics to flush out
// any errors that analysis might expose, in case this subprogram hasn't
// had any calls in this compilation unit that would have validated them.
if (!context_.HasError(symbol) && !details.isDummy() &&
!details.isInterface() && !details.stmtFunction()) {
if (!Procedure::Characterize(symbol, foldingContext_)) {
context_.SetError(symbol);
}
}
if (const Symbol *iface{FindSeparateModuleSubprogramInterface(&symbol)}) {
SubprogramMatchHelper{*this}.Check(symbol, *iface);
}
Expand Down Expand Up @@ -2882,7 +2891,8 @@ parser::Messages CheckHelper::WhyNotInteroperableDerivedType(
} else {
bool interoperableParent{true};
if (parent->symbol()) {
auto bad{WhyNotInteroperableDerivedType(*parent->symbol(), false)};
auto bad{WhyNotInteroperableDerivedType(
*parent->symbol(), /*isError=*/false)};
if (bad.AnyFatalError()) {
auto &msg{msgs.Say(symbol.name(),
"The parent of an interoperable type is not interoperable"_err_en_US)};
Expand Down Expand Up @@ -2972,6 +2982,9 @@ parser::Messages CheckHelper::WhyNotInteroperableDerivedType(
}
}
}
if (msgs.AnyFatalError()) {
examinedByWhyNotInteroperableDerivedType_.erase(symbol);
}
return msgs;
}

Expand Down Expand Up @@ -3059,16 +3072,18 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
}
context_.SetError(symbol);
} else if (auto bad{WhyNotInteroperableDerivedType(
derived->typeSymbol(), false)};
!bad.empty()) {
derived->typeSymbol(), /*isError=*/false)};
bad.AnyFatalError()) {
if (auto *msg{messages_.Say(symbol.name(),
"The derived type of an interoperable object must be interoperable, but is not"_err_en_US)}) {
msg->Attach(
derived->typeSymbol().name(), "Non-interoperable type"_en_US);
bad.AttachTo(*msg, parser::Severity::None);
}
context_.SetError(symbol);
} else {
} else if (context_.ShouldWarn(
common::LanguageFeature::NonBindCInteroperability) &&
!InModuleFile()) {
if (auto *msg{messages_.Say(symbol.name(),
"The derived type of an interoperable object should be BIND(C)"_warn_en_US)}) {
msg->Attach(derived->typeSymbol().name(), "Non-BIND(C) type"_en_US);
Expand Down Expand Up @@ -3142,7 +3157,7 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
}
}
} else if (symbol.has<DerivedTypeDetails>()) {
if (auto msgs{WhyNotInteroperableDerivedType(symbol, false)};
if (auto msgs{WhyNotInteroperableDerivedType(symbol, /*isError=*/false)};
!msgs.empty()) {
bool anyFatal{msgs.AnyFatalError()};
if (msgs.AnyFatalError() ||
Expand Down
10 changes: 7 additions & 3 deletions flang/lib/Semantics/check-purity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,16 @@ bool PurityChecker::InPureSubprogram() const {

bool PurityChecker::HasPurePrefix(
const std::list<parser::PrefixSpec> &prefixes) const {
bool result{false};
for (const parser::PrefixSpec &prefix : prefixes) {
if (std::holds_alternative<parser::PrefixSpec::Pure>(prefix.u)) {
return true;
if (std::holds_alternative<parser::PrefixSpec::Impure>(prefix.u)) {
return false;
} else if (std::holds_alternative<parser::PrefixSpec::Pure>(prefix.u) ||
std::holds_alternative<parser::PrefixSpec::Elemental>(prefix.u)) {
result = true;
}
}
return false;
return result;
}

void PurityChecker::Entered(
Expand Down
20 changes: 18 additions & 2 deletions flang/lib/Semantics/mod-file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ static std::string ModFileName(const SourceName &name,

// Write the module file for symbol, which must be a module or submodule.
void ModFileWriter::Write(const Symbol &symbol) {
auto &module{symbol.get<ModuleDetails>()};
const auto &module{symbol.get<ModuleDetails>()};
if (module.moduleFileHash()) {
return; // already written
}
auto *ancestor{module.ancestor()};
const auto *ancestor{module.ancestor()};
isSubmodule_ = ancestor != nullptr;
auto ancestorName{ancestor ? ancestor->GetName().value().ToString() : ""s};
auto path{context_.moduleDirectory() + '/' +
Expand All @@ -151,6 +151,21 @@ void ModFileWriter::Write(const Symbol &symbol) {
const_cast<ModuleDetails &>(module).set_moduleFileHash(checkSum);
}

void ModFileWriter::WriteClosure(llvm::raw_ostream &out, const Symbol &symbol,
UnorderedSymbolSet &nonIntrinsicModulesWritten) {
if (!symbol.has<ModuleDetails>() || symbol.owner().IsIntrinsicModules() ||
!nonIntrinsicModulesWritten.insert(symbol).second) {
return;
}
PutSymbols(DEREF(symbol.scope()));
needsBuf_.clear(); // omit module checksums
auto str{GetAsString(symbol)};
for (auto depRef : std::move(usedNonIntrinsicModules_)) {
WriteClosure(out, *depRef, nonIntrinsicModulesWritten);
}
out << std::move(str);
}

// Return the entire body of the module file
// and clear saved uses, decls, and contains.
std::string ModFileWriter::GetAsString(const Symbol &symbol) {
Expand Down Expand Up @@ -710,6 +725,7 @@ void ModFileWriter::PutUse(const Symbol &symbol) {
uses_ << "use,intrinsic::";
} else {
uses_ << "use ";
usedNonIntrinsicModules_.insert(module);
}
uses_ << module.name() << ",only:";
PutGenericName(uses_, symbol);
Expand Down
3 changes: 3 additions & 0 deletions flang/lib/Semantics/mod-file.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class ModFileWriter {
public:
explicit ModFileWriter(SemanticsContext &context) : context_{context} {}
bool WriteAll();
void WriteClosure(llvm::raw_ostream &, const Symbol &,
UnorderedSymbolSet &nonIntrinsicModulesWritten);

private:
SemanticsContext &context_;
Expand All @@ -46,6 +48,7 @@ class ModFileWriter {
std::string containsBuf_;
// Tracks nested DEC structures and fields of that type
UnorderedSymbolSet emittedDECStructures_, emittedDECFields_;
UnorderedSymbolSet usedNonIntrinsicModules_;

llvm::raw_string_ostream needs_{needsBuf_};
llvm::raw_string_ostream uses_{usesBuf_};
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Semantics/resolve-directives.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class SemanticsContext;

// Name resolution for OpenACC and OpenMP directives
void ResolveAccParts(
SemanticsContext &, const parser::ProgramUnit &, Scope *topScope = {});
SemanticsContext &, const parser::ProgramUnit &, Scope *topScope);
void ResolveOmpParts(SemanticsContext &, const parser::ProgramUnit &);
void ResolveOmpTopLevelParts(SemanticsContext &, const parser::Program &);

Expand Down
5 changes: 2 additions & 3 deletions flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5013,8 +5013,7 @@ bool DeclarationVisitor::HasCycle(
if (procsInCycle.count(*interface) > 0) {
for (const auto &procInCycle : procsInCycle) {
Say(procInCycle->name(),
"The interface for procedure '%s' is recursively "
"defined"_err_en_US,
"The interface for procedure '%s' is recursively defined"_err_en_US,
procInCycle->name());
context().SetError(*procInCycle);
}
Expand Down Expand Up @@ -8941,7 +8940,7 @@ bool ResolveNamesVisitor::Pre(const parser::ProgramUnit &x) {
FinishSpecificationParts(root);
ResolveExecutionParts(root);
FinishExecutionParts(root);
ResolveAccParts(context(), x);
ResolveAccParts(context(), x, /*topScope=*/nullptr);
ResolveOmpParts(context(), x);
return false;
}
Expand Down
38 changes: 38 additions & 0 deletions flang/lib/Semantics/unparse-with-symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "flang/Semantics/unparse-with-symbols.h"
#include "mod-file.h"
#include "flang/Parser/parse-tree-visitor.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Parser/unparse.h"
Expand Down Expand Up @@ -98,4 +99,41 @@ void UnparseWithSymbols(llvm::raw_ostream &out, const parser::Program &program,
int indent) { visitor.PrintSymbols(location, out, indent); }};
parser::Unparse(out, program, encoding, false, true, &preStatement);
}

// UnparseWithModules()

class UsedModuleVisitor {
public:
UnorderedSymbolSet &modulesUsed() { return modulesUsed_; }
UnorderedSymbolSet &modulesDefined() { return modulesDefined_; }
template <typename T> bool Pre(const T &) { return true; }
template <typename T> void Post(const T &) {}
void Post(const parser::ModuleStmt &module) {
if (module.v.symbol) {
modulesDefined_.insert(*module.v.symbol);
}
}
void Post(const parser::UseStmt &use) {
if (use.moduleName.symbol) {
modulesUsed_.insert(*use.moduleName.symbol);
}
}

private:
UnorderedSymbolSet modulesUsed_;
UnorderedSymbolSet modulesDefined_;
};

void UnparseWithModules(llvm::raw_ostream &out, SemanticsContext &context,
const parser::Program &program, parser::Encoding encoding) {
UsedModuleVisitor visitor;
parser::Walk(program, visitor);
UnorderedSymbolSet nonIntrinsicModulesWritten{
std::move(visitor.modulesDefined())};
ModFileWriter writer{context};
for (SymbolRef moduleRef : visitor.modulesUsed()) {
writer.WriteClosure(out, *moduleRef, nonIntrinsicModulesWritten);
}
parser::Unparse(out, program, encoding, false, true);
}
} // namespace Fortran::semantics
2 changes: 2 additions & 0 deletions flang/test/Driver/frontend-forwarding.f90
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
! RUN: -fversion-loops-for-stride \
! RUN: -flang-experimental-hlfir \
! RUN: -flang-deprecated-no-hlfir \
! RUN: -flang-experimental-integer-overflow \
! RUN: -fno-ppc-native-vector-element-order \
! RUN: -fppc-native-vector-element-order \
! RUN: -mllvm -print-before-all \
Expand Down Expand Up @@ -50,6 +51,7 @@
! CHECK: "-fversion-loops-for-stride"
! CHECK: "-flang-experimental-hlfir"
! CHECK: "-flang-deprecated-no-hlfir"
! CHECK: "-flang-experimental-integer-overflow"
! CHECK: "-fno-ppc-native-vector-element-order"
! CHECK: "-fppc-native-vector-element-order"
! CHECK: "-Rpass"
Expand Down
34 changes: 34 additions & 0 deletions flang/test/Driver/unparse-with-modules.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
! RUN: %flang_fc1 -I %S/Inputs/module-dir -fdebug-unparse-with-modules %s | FileCheck %s
module m1
use iso_fortran_env
use BasicTestModuleTwo
implicit none
type(t2) y
real(real32) x
end

program test
use m1
use BasicTestModuleTwo
implicit none
x = 123.
y = t2()
end

!CHECK-NOT: module iso_fortran_env
!CHECK: module basictestmoduletwo
!CHECK: type::t2
!CHECK: end type
!CHECK: end
!CHECK: module m1
!CHECK: use :: iso_fortran_env
!CHECK: implicit none
!CHECK: real(kind=real32) x
!CHECK: end module
!CHECK: program test
!CHECK: use :: m1
!CHECK: use :: basictestmoduletwo
!CHECK: implicit none
!CHECK: x = 123.
!CHECK: y = t2()
!CHECK: end program
22 changes: 16 additions & 6 deletions flang/test/Fir/declare-codegen.fir
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Test rewrite of fir.declare. The result is replaced by the memref operand.
// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s
// RUN: fir-opt --cg-rewrite="preserve-declare=true" %s -o - | FileCheck %s --check-prefixes DECL
// RUN: fir-opt --cg-rewrite="preserve-declare=false" %s -o - | FileCheck %s --check-prefixes NODECL
// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s --check-prefixes NODECL


func.func @test(%arg0: !fir.ref<!fir.array<12x23xi32>>) {
Expand All @@ -15,9 +17,14 @@ func.func @test(%arg0: !fir.ref<!fir.array<12x23xi32>>) {
func.func private @bar(%arg0: !fir.ref<!fir.array<12x23xi32>>)


// CHECK-LABEL: func.func @test(
// CHECK-SAME: %[[arg0:.*]]: !fir.ref<!fir.array<12x23xi32>>) {
// CHECK-NEXT: fir.call @bar(%[[arg0]]) : (!fir.ref<!fir.array<12x23xi32>>) -> ()
// NODECL-LABEL: func.func @test(
// NODECL-SAME: %[[arg0:.*]]: !fir.ref<!fir.array<12x23xi32>>) {
// NODECL-NEXT: fir.call @bar(%[[arg0]]) : (!fir.ref<!fir.array<12x23xi32>>) -> ()

// DECL-LABEL: func.func @test(
// DECL-SAME: %[[arg0:.*]]: !fir.ref<!fir.array<12x23xi32>>) {
// DECL: fircg.ext_declare


func.func @useless_shape_with_duplicate_extent_operand(%arg0: !fir.ref<!fir.array<3x3xf32>>) {
%c3 = arith.constant 3 : index
Expand All @@ -26,5 +33,8 @@ func.func @useless_shape_with_duplicate_extent_operand(%arg0: !fir.ref<!fir.arra
return
}

// CHECK-LABEL: func.func @useless_shape_with_duplicate_extent_operand(
// CHECK-NEXT: return
// NODECL-LABEL: func.func @useless_shape_with_duplicate_extent_operand(
// NODECL-NEXT: return

// DECL-LABEL: func.func @useless_shape_with_duplicate_extent_operand(
// DECL: fircg.ext_declare
11 changes: 8 additions & 3 deletions flang/test/Fir/dummy-scope-codegen.fir
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s
// RUN: fir-opt --cg-rewrite="preserve-declare=true" %s -o - | FileCheck %s --check-prefixes DECL
// RUN: fir-opt --cg-rewrite="preserve-declare=false" %s -o - | FileCheck %s --check-prefixes NODECL
// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s --check-prefixes NODECL

func.func @dummy_scope(%arg0: !fir.ref<f32>) {
%scope = fir.dummy_scope : !fir.dscope
%0 = fir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
return
}
// CHECK-LABEL: func.func @dummy_scope(
// CHECK-NEXT: return
// DECL-LABEL: func.func @dummy_scope(
// DECL: fircg.ext_declare

// NODECL-LABEL: func.func @dummy_scope(
// NODECL-NEXT: return
Loading