96 changes: 60 additions & 36 deletions clang/test/CodeGenHLSL/builtins/lerp.hlsl
Original file line number Diff line number Diff line change
@@ -1,78 +1,102 @@
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
// RUN: --check-prefixes=CHECK,NATIVE_HALF
// RUN: --check-prefixes=CHECK,DXIL_CHECK,DXIL_NATIVE_HALF,NATIVE_HALF
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF
// RUN: -o - | FileCheck %s --check-prefixes=CHECK,DXIL_CHECK,NO_HALF,DXIL_NO_HALF
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
// RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
// RUN: --check-prefixes=CHECK,NATIVE_HALF,SPIR_NATIVE_HALF,SPIR_CHECK
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
// RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \
// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF,SPIR_NO_HALF,SPIR_CHECK


// NATIVE_HALF: %dx.lerp = call half @llvm.dx.lerp.f16(half %0, half %1, half %2)
// NATIVE_HALF: ret half %dx.lerp
// NO_HALF: %dx.lerp = call float @llvm.dx.lerp.f32(float %0, float %1, float %2)
// NO_HALF: ret float %dx.lerp
// DXIL_NATIVE_HALF: %hlsl.lerp = call half @llvm.dx.lerp.f16(half %0, half %1, half %2)
// SPIR_NATIVE_HALF: %hlsl.lerp = call half @llvm.spv.lerp.f16(half %0, half %1, half %2)
// NATIVE_HALF: ret half %hlsl.lerp
// DXIL_NO_HALF: %hlsl.lerp = call float @llvm.dx.lerp.f32(float %0, float %1, float %2)
// SPIR_NO_HALF: %hlsl.lerp = call float @llvm.spv.lerp.f32(float %0, float %1, float %2)
// NO_HALF: ret float %hlsl.lerp
half test_lerp_half(half p0) { return lerp(p0, p0, p0); }

// NATIVE_HALF: %dx.lerp = call <2 x half> @llvm.dx.lerp.v2f16(<2 x half> %0, <2 x half> %1, <2 x half> %2)
// NATIVE_HALF: ret <2 x half> %dx.lerp
// NO_HALF: %dx.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %2)
// NO_HALF: ret <2 x float> %dx.lerp
// DXIL_NATIVE_HALF: %hlsl.lerp = call <2 x half> @llvm.dx.lerp.v2f16(<2 x half> %0, <2 x half> %1, <2 x half> %2)
// SPIR_NATIVE_HALF: %hlsl.lerp = call <2 x half> @llvm.spv.lerp.v2f16(<2 x half> %0, <2 x half> %1, <2 x half> %2)
// NATIVE_HALF: ret <2 x half> %hlsl.lerp
// DXIL_NO_HALF: %hlsl.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %2)
// SPIR_NO_HALF: %hlsl.lerp = call <2 x float> @llvm.spv.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %2)
// NO_HALF: ret <2 x float> %hlsl.lerp
half2 test_lerp_half2(half2 p0) { return lerp(p0, p0, p0); }

// NATIVE_HALF: %dx.lerp = call <3 x half> @llvm.dx.lerp.v3f16(<3 x half> %0, <3 x half> %1, <3 x half> %2)
// NATIVE_HALF: ret <3 x half> %dx.lerp
// NO_HALF: %dx.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %2)
// NO_HALF: ret <3 x float> %dx.lerp
// DXIL_NATIVE_HALF: %hlsl.lerp = call <3 x half> @llvm.dx.lerp.v3f16(<3 x half> %0, <3 x half> %1, <3 x half> %2)
// SPIR_NATIVE_HALF: %hlsl.lerp = call <3 x half> @llvm.spv.lerp.v3f16(<3 x half> %0, <3 x half> %1, <3 x half> %2)
// NATIVE_HALF: ret <3 x half> %hlsl.lerp
// DXIL_NO_HALF: %hlsl.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %2)
// SPIR_NO_HALF: %hlsl.lerp = call <3 x float> @llvm.spv.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %2)
// NO_HALF: ret <3 x float> %hlsl.lerp
half3 test_lerp_half3(half3 p0) { return lerp(p0, p0, p0); }

// NATIVE_HALF: %dx.lerp = call <4 x half> @llvm.dx.lerp.v4f16(<4 x half> %0, <4 x half> %1, <4 x half> %2)
// NATIVE_HALF: ret <4 x half> %dx.lerp
// NO_HALF: %dx.lerp = call <4 x float> @llvm.dx.lerp.v4f32(<4 x float> %0, <4 x float> %1, <4 x float> %2)
// NO_HALF: ret <4 x float> %dx.lerp
// DXIL_NATIVE_HALF: %hlsl.lerp = call <4 x half> @llvm.dx.lerp.v4f16(<4 x half> %0, <4 x half> %1, <4 x half> %2)
// SPIR_NATIVE_HALF: %hlsl.lerp = call <4 x half> @llvm.spv.lerp.v4f16(<4 x half> %0, <4 x half> %1, <4 x half> %2)
// NATIVE_HALF: ret <4 x half> %hlsl.lerp
// DXIL_NO_HALF: %hlsl.lerp = call <4 x float> @llvm.dx.lerp.v4f32(<4 x float> %0, <4 x float> %1, <4 x float> %2)
// SPIR_NO_HALF: %hlsl.lerp = call <4 x float> @llvm.spv.lerp.v4f32(<4 x float> %0, <4 x float> %1, <4 x float> %2)
// NO_HALF: ret <4 x float> %hlsl.lerp
half4 test_lerp_half4(half4 p0) { return lerp(p0, p0, p0); }

// CHECK: %dx.lerp = call float @llvm.dx.lerp.f32(float %0, float %1, float %2)
// CHECK: ret float %dx.lerp
// DXIL_CHECK: %hlsl.lerp = call float @llvm.dx.lerp.f32(float %0, float %1, float %2)
// SPIR_CHECK: %hlsl.lerp = call float @llvm.spv.lerp.f32(float %0, float %1, float %2)
// CHECK: ret float %hlsl.lerp
float test_lerp_float(float p0) { return lerp(p0, p0, p0); }

// CHECK: %dx.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %2)
// CHECK: ret <2 x float> %dx.lerp
// DXIL_CHECK: %hlsl.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %2)
// SPIR_CHECK: %hlsl.lerp = call <2 x float> @llvm.spv.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %2)
// CHECK: ret <2 x float> %hlsl.lerp
float2 test_lerp_float2(float2 p0) { return lerp(p0, p0, p0); }

// CHECK: %dx.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %2)
// CHECK: ret <3 x float> %dx.lerp
// DXIL_CHECK: %hlsl.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %2)
// SPIR_CHECK: %hlsl.lerp = call <3 x float> @llvm.spv.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %2)
// CHECK: ret <3 x float> %hlsl.lerp
float3 test_lerp_float3(float3 p0) { return lerp(p0, p0, p0); }

// CHECK: %dx.lerp = call <4 x float> @llvm.dx.lerp.v4f32(<4 x float> %0, <4 x float> %1, <4 x float> %2)
// CHECK: ret <4 x float> %dx.lerp
// DXIL_CHECK: %hlsl.lerp = call <4 x float> @llvm.dx.lerp.v4f32(<4 x float> %0, <4 x float> %1, <4 x float> %2)
// SPIR_CHECK: %hlsl.lerp = call <4 x float> @llvm.spv.lerp.v4f32(<4 x float> %0, <4 x float> %1, <4 x float> %2)
// CHECK: ret <4 x float> %hlsl.lerp
float4 test_lerp_float4(float4 p0) { return lerp(p0, p0, p0); }

// CHECK: %dx.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %splat.splat, <2 x float> %1, <2 x float> %2)
// CHECK: ret <2 x float> %dx.lerp
// DXIL_CHECK: %hlsl.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %splat.splat, <2 x float> %1, <2 x float> %2)
// SPIR_CHECK: %hlsl.lerp = call <2 x float> @llvm.spv.lerp.v2f32(<2 x float> %splat.splat, <2 x float> %1, <2 x float> %2)
// CHECK: ret <2 x float> %hlsl.lerp
float2 test_lerp_float2_splat(float p0, float2 p1) { return lerp(p0, p1, p1); }

// CHECK: %dx.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %splat.splat, <3 x float> %1, <3 x float> %2)
// CHECK: ret <3 x float> %dx.lerp
// DXIL_CHECK: %hlsl.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %splat.splat, <3 x float> %1, <3 x float> %2)
// SPIR_CHECK: %hlsl.lerp = call <3 x float> @llvm.spv.lerp.v3f32(<3 x float> %splat.splat, <3 x float> %1, <3 x float> %2)
// CHECK: ret <3 x float> %hlsl.lerp
float3 test_lerp_float3_splat(float p0, float3 p1) { return lerp(p0, p1, p1); }

// CHECK: %dx.lerp = call <4 x float> @llvm.dx.lerp.v4f32(<4 x float> %splat.splat, <4 x float> %1, <4 x float> %2)
// CHECK: ret <4 x float> %dx.lerp
// DXIL_CHECK: %hlsl.lerp = call <4 x float> @llvm.dx.lerp.v4f32(<4 x float> %splat.splat, <4 x float> %1, <4 x float> %2)
// SPIR_CHECK: %hlsl.lerp = call <4 x float> @llvm.spv.lerp.v4f32(<4 x float> %splat.splat, <4 x float> %1, <4 x float> %2)
// CHECK: ret <4 x float> %hlsl.lerp
float4 test_lerp_float4_splat(float p0, float4 p1) { return lerp(p0, p1, p1); }

// CHECK: %conv = sitofp i32 %2 to float
// CHECK: %splat.splatinsert = insertelement <2 x float> poison, float %conv, i64 0
// CHECK: %splat.splat = shufflevector <2 x float> %splat.splatinsert, <2 x float> poison, <2 x i32> zeroinitializer
// CHECK: %dx.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %splat.splat)
// CHECK: ret <2 x float> %dx.lerp
// DXIL_CHECK: %hlsl.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %splat.splat)
// SPIR_CHECK: %hlsl.lerp = call <2 x float> @llvm.spv.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %splat.splat)
// CHECK: ret <2 x float> %hlsl.lerp
float2 test_lerp_float2_int_splat(float2 p0, int p1) {
return lerp(p0, p0, p1);
}

// CHECK: %conv = sitofp i32 %2 to float
// CHECK: %splat.splatinsert = insertelement <3 x float> poison, float %conv, i64 0
// CHECK: %splat.splat = shufflevector <3 x float> %splat.splatinsert, <3 x float> poison, <3 x i32> zeroinitializer
// CHECK: %dx.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %splat.splat)
// CHECK: ret <3 x float> %dx.lerp
// DXIL_CHECK: %hlsl.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %splat.splat)
// SPIR_CHECK: %hlsl.lerp = call <3 x float> @llvm.spv.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %splat.splat)
// CHECK: ret <3 x float> %hlsl.lerp
float3 test_lerp_float3_int_splat(float3 p0, int p1) {
return lerp(p0, p0, p1);
}
36 changes: 36 additions & 0 deletions clang/test/CoverageMapping/statement-expression.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name statement-expression.c %s

// No crash for the following examples, where GNU Statement Expression extension
// could introduce region terminators (break, goto etc) before implicit
// initializers in a struct or an array.
// See https://github.com/llvm/llvm-project/pull/89564

struct Foo {
int field1;
int field2;
};

void f1(void) {
struct Foo foo = {
.field1 = ({
switch (0) {
case 0:
break; // A region terminator
}
0;
}),
// ImplicitValueInitExpr introduced here for .field2
};
}

void f2(void) {
int arr[3] = {
[0] = ({
goto L0; // A region terminator
L0:
0;
}),
// ImplicitValueInitExpr introduced here for subscript [1]
[2] = 0,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
// RUN: %clang -target powerpc64-unknown-aix -maix-small-local-exec-tls -S -emit-llvm \
// RUN: %s -o - | FileCheck %s --check-prefix=CHECK-AIX_SMALL_LOCALEXEC_TLS

// RUN: %clang -target powerpc64-unknown-aix -maix-small-local-dynamic-tls -S -emit-llvm \
// RUN: %s -o - | FileCheck %s --check-prefix=CHECK-AIX_SMALL_LOCALDYNAMIC_TLS

// RUN: not %clang -target powerpc-unknown-aix -maix-small-local-exec-tls \
// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-AIX32 %s
// RUN: not %clang -target powerpc64le-unknown-linux-gnu -maix-small-local-exec-tls \
Expand All @@ -19,19 +22,35 @@
// RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s

// RUN: not %clang -target powerpc-unknown-aix -maix-small-local-dynamic-tls \
// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-AIX32 %s
// RUN: not %clang -target powerpc64le-unknown-linux-gnu -maix-small-local-dynamic-tls \
// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-LINUX %s
// RUN: not %clang -target powerpc64-unknown-linux-gnu -maix-small-local-dynamic-tls \
// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-LINUX %s
// RUN: not %clang -target powerpc64-unknown-aix -maix-small-local-dynamic-tls \
// RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s
// RUN: not %clang -target powerpc64-unknown-linux-gnu -maix-small-local-dynamic-tls \
// RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s

int test(void) {
return 0;
}

// CHECK: test() #0 {
// CHECK: attributes #0 = {
// CHECK-SAME: -aix-small-local-exec-tls
// CHECK-SAME: {{-aix-small-local-exec-tls,.*-aix-small-local-dynamic-tls|-aix-small-local-dynamic-tls,.*-aix-small-local-exec-tls}}

// CHECK-UNSUPPORTED-AIX32: option '-maix-small-local-exec-tls' cannot be specified on this target
// CHECK-UNSUPPORTED-LINUX: option '-maix-small-local-exec-tls' cannot be specified on this target
// CHECK-UNSUPPORTED-NO-DATASEC: invalid argument '-maix-small-local-exec-tls' only allowed with '-fdata-sections'
// CHECK-UNSUPPORTED-AIX32: option '-maix-small-local-[exec|dynamic]-tls' cannot be specified on this target
// CHECK-UNSUPPORTED-LINUX: option '-maix-small-local-[exec|dynamic]-tls' cannot be specified on this target
// CHECK-UNSUPPORTED-NO-DATASEC: invalid argument '-maix-small-local-[exec|dynamic]-tls' only allowed with '-fdata-sections'

// CHECK-AIX_SMALL_LOCALEXEC_TLS: test() #0 {
// CHECK-AIX_SMALL_LOCALEXEC_TLS: attributes #0 = {
// CHECK-AIX_SMALL_LOCALEXEC_TLS-SAME: +aix-small-local-exec-tls

// CHECK-AIX_SMALL_LOCALDYNAMIC_TLS: test() #0 {
// CHECK-AIX_SMALL_LOCALDYNAMIC_TLS: attributes #0 = {
// CHECK-AIX_SMALL_LOCALDYNAMIC_TLS-SAME: +aix-small-local-dynamic-tls
8 changes: 7 additions & 1 deletion clang/test/Driver/integrated-as.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
// XFAIL: target={{.*}}-aix{{.*}}

// RUN: %clang -### -c -save-temps -integrated-as %s 2>&1 | FileCheck %s
// RUN: %clang -### -c -save-temps -integrated-as --target=x86_64 %s 2>&1 | FileCheck %s

// CHECK: cc1as
// CHECK: -mrelax-all

// RISC-V does not enable -mrelax-all
// RUN: %clang -### -c -save-temps -integrated-as --target=riscv64 %s 2>&1 | FileCheck %s -check-prefix=RISCV-RELAX

// RISCV-RELAX: cc1as
// RISCV-RELAX-NOT: -mrelax-all

// RUN: %clang -### -fintegrated-as -c -save-temps %s 2>&1 | FileCheck %s -check-prefix FIAS

// FIAS: cc1as
Expand Down
529 changes: 92 additions & 437 deletions clang/test/ExtractAPI/availability.c

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions clang/test/FixIt/format-darwin-enum-class.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -verify -Wformat %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -fdiagnostics-parseable-fixits -Wformat %s 2>&1 | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -verify -Wformat-pedantic %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -fdiagnostics-parseable-fixits -Wformat-pedantic %s 2>&1 | FileCheck %s

extern "C" int printf(const char * restrict, ...);

Expand Down
6 changes: 4 additions & 2 deletions clang/test/FixIt/format.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat %s
// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -Wformat %s 2>&1 | FileCheck %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-pedantic %s
// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -Wformat-pedantic %s 2>&1 | FileCheck %s
// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -Wformat %s -verify=okay
// okay-no-diagnostics

extern "C" int printf(const char *, ...);
#define LOG(...) printf(__VA_ARGS__)
Expand Down
11 changes: 10 additions & 1 deletion clang/test/Lexer/bitint-constants-compat.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
// RUN: %clang_cc1 -std=c17 -fsyntax-only -verify=ext -Wno-unused %s
// RUN: %clang_cc1 -std=c2x -fsyntax-only -verify=compat -Wpre-c2x-compat -Wno-unused %s
// RUN: %clang_cc1 -fsyntax-only -verify=cpp -Wno-unused -x c++ %s
// RUN: %clang_cc1 -fsyntax-only -verify=cpp -Wbit-int-extension -Wno-unused -x c++ %s

#if 18446744073709551615uwb // ext-warning {{'_BitInt' suffix for literals is a C23 extension}} \
compat-warning {{'_BitInt' suffix for literals is incompatible with C standards before C23}} \
cpp-error {{invalid suffix 'uwb' on integer constant}}
#endif

#if 18446744073709551615__uwb // ext-error {{invalid suffix '__uwb' on integer constant}} \
compat-error {{invalid suffix '__uwb' on integer constant}} \
cpp-warning {{'_BitInt' suffix for literals is a Clang extension}}
#endif

void func(void) {
18446744073709551615wb; // ext-warning {{'_BitInt' suffix for literals is a C23 extension}} \
compat-warning {{'_BitInt' suffix for literals is incompatible with C standards before C23}} \
cpp-error {{invalid suffix 'wb' on integer constant}}

18446744073709551615__wb; // ext-error {{invalid suffix '__wb' on integer constant}} \
compat-error {{invalid suffix '__wb' on integer constant}} \
cpp-warning {{'_BitInt' suffix for literals is a Clang extension}}
}
178 changes: 178 additions & 0 deletions clang/test/Lexer/bitint-constants.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// RUN: %clang_cc1 -triple aarch64-unknown-unknown -fsyntax-only -verify -Wno-unused %s

// Test that the preprocessor behavior makes sense.
#if 1__wb != 1
#error "wb suffix must be recognized by preprocessor"
#endif
#if 1__uwb != 1
#error "uwb suffix must be recognized by preprocessor"
#endif
#if !(-1__wb < 0)
#error "wb suffix must be interpreted as signed"
#endif
#if !(-1__uwb > 0)
#error "uwb suffix must be interpreted as unsigned"
#endif

#if 18446744073709551615__uwb != 18446744073709551615ULL
#error "expected the max value for uintmax_t to compare equal"
#endif

// Test that the preprocessor gives appropriate diagnostics when the
// literal value is larger than what can be stored in a [u]intmax_t.
#if 18446744073709551616__wb != 0ULL // expected-error {{integer literal is too large to be represented in any integer type}}
#error "never expected to get here due to error"
#endif
#if 18446744073709551616__uwb != 0ULL // expected-error {{integer literal is too large to be represented in any integer type}}
#error "never expected to get here due to error"
#endif

// Despite using a bit-precise integer, this is expected to overflow
// because all preprocessor arithmetic is done in [u]intmax_t, so this
// should result in the value 0.
#if 18446744073709551615__uwb + 1 != 0ULL
#error "expected modulo arithmetic with uintmax_t width"
#endif

// Because this bit-precise integer is signed, it will also overflow,
// but Clang handles that by converting to uintmax_t instead of
// intmax_t.
#if 18446744073709551615__wb + 1 != 0LL // expected-warning {{integer literal is too large to be represented in a signed integer type, interpreting as unsigned}}
#error "expected modulo arithmetic with uintmax_t width"
#endif

// Test that just because the preprocessor can't figure out the bit
// width doesn't mean we can't form the constant, it just means we
// can't use the value in a preprocessor conditional.
unsigned _BitInt(65) Val = 18446744073709551616__uwb;
// UDL test to make sure underscore parsing is correct
unsigned operator ""_(const char *);

void ValidSuffix(void) {
// Decimal literals.
1__wb;
1__WB;
-1__wb;
_Static_assert((int)1__wb == 1, "not 1?");
_Static_assert((int)-1__wb == -1, "not -1?");

1__uwb;
1__uWB;
1__Uwb;
1__UWB;
1u__wb;
1__WBu;
1U__WB;
_Static_assert((unsigned int)1__uwb == 1u, "not 1?");

1'2__wb;
1'2__uwb;
_Static_assert((int)1'2__wb == 12, "not 12?");
_Static_assert((unsigned int)1'2__uwb == 12u, "not 12?");

// Hexadecimal literals.
0x1__wb;
0x1__uwb;
0x0'1'2'3__wb;
0xA'B'c'd__uwb;
_Static_assert((int)0x0'1'2'3__wb == 0x0123, "not 0x0123");
_Static_assert((unsigned int)0xA'B'c'd__uwb == 0xABCDu, "not 0xABCD");

// Binary literals.
0b1__wb;
0b1__uwb;
0b1'0'1'0'0'1__wb;
0b0'1'0'1'1'0__uwb;
_Static_assert((int)0b1__wb == 1, "not 1?");
_Static_assert((unsigned int)0b1__uwb == 1u, "not 1?");

// Octal literals.
01__wb;
01__uwb;
0'6'0__wb;
0'0'1__uwb;
0__wbu;
0__WBu;
0U__wb;
0U__WB;
0__wb;
_Static_assert((int)0__wb == 0, "not 0?");
_Static_assert((unsigned int)0__wbu == 0u, "not 0?");

// Imaginary or Complex. These are allowed because _Complex can work with any
// integer type, and that includes _BitInt.
1__wbi;
1i__wb;
1__wbj;

//UDL test as single underscore
unsigned i = 1.0_;
}

void InvalidSuffix(void) {
// Can't mix the case of wb or WB, and can't rearrange the letters.
0__wB; // expected-error {{invalid suffix '__wB' on integer constant}}
0__Wb; // expected-error {{invalid suffix '__Wb' on integer constant}}
0__bw; // expected-error {{invalid suffix '__bw' on integer constant}}
0__BW; // expected-error {{invalid suffix '__BW' on integer constant}}

// Trailing digit separators should still diagnose.
1'2'__wb; // expected-error {{digit separator cannot appear at end of digit sequence}}
1'2'__uwb; // expected-error {{digit separator cannot appear at end of digit sequence}}

// Long.
1l__wb; // expected-error {{invalid suffix}}
1__wbl; // expected-error {{invalid suffix}}
1l__uwb; // expected-error {{invalid suffix}}
1__l; // expected-error {{invalid suffix}}
1ul__wb; // expected-error {{invalid suffix}}

// Long long.
1ll__wb; // expected-error {{invalid suffix}}
1__uwbll; // expected-error {{invalid suffix}}

// Floating point.
0.1__wb; // expected-error {{invalid suffix}}
0.1f__wb; // expected-error {{invalid suffix}}

// Repetitive suffix.
1__wb__wb; // expected-error {{invalid suffix}}
1__uwbuwb; // expected-error {{invalid suffix}}
1__wbuwb; // expected-error {{invalid suffix}}
1__uwbwb; // expected-error {{invalid suffix}}

// Missing or extra characters in suffix.
1__; // expected-error {{invalid suffix}}
1__u; // expected-error {{invalid suffix}}
1___; // expected-error {{invalid suffix}}
1___WB; // expected-error {{invalid suffix}}
1__wb__; // expected-error {{invalid suffix}}
1__w; // expected-error {{invalid suffix}}
1__b; // expected-error {{invalid suffix}}
}

void ValidSuffixInvalidValue(void) {
// This is a valid suffix, but the value is larger than one that fits within
// the width of BITINT_MAXWIDTH. When this value changes in the future, the
// test cases should pick a new value that can't be represented by a _BitInt,
// but also add a test case that a 129-bit literal still behaves as-expected.
_Static_assert(__BITINT_MAXWIDTH__ <= 128,
"Need to pick a bigger constant for the test case below.");
0xFFFF'FFFF'FFFF'FFFF'FFFF'FFFF'FFFF'FFFF'1__wb; // expected-error {{integer literal is too large to be represented in any signed integer type}}
0xFFFF'FFFF'FFFF'FFFF'FFFF'FFFF'FFFF'FFFF'1__uwb; // expected-error {{integer literal is too large to be represented in any integer type}}
}

void TestTypes(void) {
// 2 value bits, one sign bit
_Static_assert(__is_same(decltype(3__wb), _BitInt(3)));
// 2 value bits, one sign bit
_Static_assert(__is_same(decltype(-3__wb), _BitInt(3)));
// 2 value bits, no sign bit
_Static_assert(__is_same(decltype(3__uwb), unsigned _BitInt(2)));
// 4 value bits, one sign bit
_Static_assert(__is_same(decltype(0xF__wb), _BitInt(5)));
// 4 value bits, one sign bit
_Static_assert(__is_same(decltype(-0xF__wb), _BitInt(5)));
// 4 value bits, no sign bit
_Static_assert(__is_same(decltype(0xF__uwb), unsigned _BitInt(4)));
}
20 changes: 19 additions & 1 deletion clang/test/Parser/cxx2a-constrained-template-param.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,22 @@ namespace temp
template<C1 TT, C1 UU = test1> // expected-error{{use of class template 'test1' requires template arguments}}
// expected-error@-1 2{{concept named in type constraint is not a type concept}}
using A = TT<int>; // expected-error{{expected ';' after alias declaration}}
}
}

namespace PR67235 {

template <class T>
concept C = true;

template <auto D>
struct S {};

// Don't destroy annotation 'C' at the end of the lambda; else we'll run into a
// use-after-free bug while constructing the type constraint 'C' on 'Default'.
template <typename Ret, C Default = decltype([] { return Ret(); })>
void func() {}

template <typename Ret, C Default = S<[] { return Ret(); }>>
void func2() {}

}
4 changes: 0 additions & 4 deletions clang/test/ParserOpenACC/parse-clauses.c
Original file line number Diff line number Diff line change
Expand Up @@ -911,16 +911,12 @@ void IntExprParsing() {
#pragma acc parallel num_gangs(invalid)
{}

// expected-error@+2{{expected ')'}}
// expected-note@+1{{to match this '('}}
#pragma acc parallel num_gangs(5, 4)
{}

// expected-warning@+1{{OpenACC clause 'num_gangs' not yet implemented, clause ignored}}
#pragma acc parallel num_gangs(5)
{}

// expected-warning@+1{{OpenACC clause 'num_gangs' not yet implemented, clause ignored}}
#pragma acc parallel num_gangs(returns_int())
{}

Expand Down
54 changes: 54 additions & 0 deletions clang/test/Sema/bitint-bitfield-promote.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 %s

// GH87641 noticed that integer promotion of a bit-field of bit-precise integer
// type was promoting to int rather than the type of the bit-field.
struct S {
unsigned _BitInt(7) x : 2;
unsigned _BitInt(2) y : 2;
unsigned _BitInt(72) z : 28;
_BitInt(31) a : 12;
_BitInt(33) b : 33;
};

// We don't have to worry about promotion cases where the bit-precise type is
// smaller than the width of the bit-field; that can't happen.
struct T {
unsigned _BitInt(28) oh_no : 72; // expected-error {{width of bit-field 'oh_no' (72 bits) exceeds the width of its type (28 bits)}}
};

static_assert(
_Generic(+(struct S){}.x,
int : 0,
unsigned _BitInt(7) : 1,
unsigned _BitInt(2) : 2
) == 1);

static_assert(
_Generic(+(struct S){}.y,
int : 0,
unsigned _BitInt(7) : 1,
unsigned _BitInt(2) : 2
) == 2);

static_assert(
_Generic(+(struct S){}.z,
int : 0,
unsigned _BitInt(72) : 1,
unsigned _BitInt(28) : 2
) == 1);

static_assert(
_Generic(+(struct S){}.a,
int : 0,
_BitInt(31) : 1,
_BitInt(12) : 2,
unsigned _BitInt(31) : 3
) == 1);

static_assert(
_Generic(+(struct S){}.b,
int : 0,
long long : 1,
_BitInt(33) : 2,
unsigned _BitInt(33) : 3
) == 2);
32 changes: 32 additions & 0 deletions clang/test/SemaCXX/PR41441.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// RUN: %clang --target=x86_64-pc-linux -S -fno-discard-value-names -emit-llvm -o - %s | FileCheck %s

namespace std {
using size_t = decltype(sizeof(int));
};
void* operator new[](std::size_t, void*) noexcept;

// CHECK: call void @llvm.memset.p0.i64(ptr align 1 %x, i8 0, i64 8, i1 false)
// CHECK: call void @llvm.memset.p0.i64(ptr align 16 %x, i8 0, i64 32, i1 false)
template <typename TYPE>
void f()
{
typedef TYPE TArray[8];

TArray x;
new(&x) TArray();
}

template <typename T>
void f1() {
int (*x)[1] = new int[1][1];
}
template void f1<char>();
void f2() {
int (*x)[1] = new int[1][1];
}

int main()
{
f<char>();
f<int>();
}
4 changes: 2 additions & 2 deletions clang/test/SemaCXX/format-strings.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -Wformat-pedantic -fblocks %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks -std=c++11 %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -Wformat-pedantic -fblocks -std=c++11 %s

#include <stdarg.h>

Expand Down
74 changes: 74 additions & 0 deletions clang/test/SemaCXX/static-assert-cxx26.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,77 @@ struct Callable {
} data;
};
static_assert(false, Callable{}); // expected-error {{static assertion failed: hello}}

namespace GH89407 {
struct A {
constexpr __SIZE_TYPE__ size() const { return -1; }
constexpr const char* data() const { return ""; }
};

struct B {
constexpr long long size() const { return 18446744073709551615U; }
constexpr const char* data() const { return ""; }
};

struct C {
constexpr __int128 size() const { return -1; }
constexpr const char* data() const { return ""; }
};

struct D {
constexpr unsigned __int128 size() const { return -1; }
constexpr const char* data() const { return ""; }
};

struct E {
constexpr __SIZE_TYPE__ size() const { return 18446744073709551615U; }
constexpr const char* data() const { return ""; }
};

static_assert(true, A{}); // expected-error {{the message in this static assertion is not a constant expression}}
// expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
static_assert(true, B{}); // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
// expected-error@-1 {{the message in this static assertion is not a constant expression}}
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
static_assert(true, C{}); // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
// expected-error@-1 {{the message in this static assertion is not a constant expression}}
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
static_assert(true, D{}); // expected-error {{call to 'size()' evaluates to 340282366920938463463374607431768211455, which cannot be narrowed to type 'unsigned long'}}
// expected-error@-1 {{the message in this static assertion is not a constant expression}}
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
static_assert(true, E{}); // expected-error {{the message in this static assertion is not a constant expression}}
// expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}

static_assert(
false, // expected-error {{static assertion failed}}
A{} // expected-error {{the message in a static assertion must be produced by a constant expression}}
// expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
);

static_assert(
false, // expected-error {{static assertion failed}}
B{} // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
// expected-error@-1 {{the message in a static assertion must be produced by a constant expression}}
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
);

static_assert(
false, // expected-error {{static assertion failed}}
C{} // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
// expected-error@-1 {{the message in a static assertion must be produced by a constant expression}}
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
);

static_assert(
false, // expected-error {{static assertion failed}}
D{} // expected-error {{call to 'size()' evaluates to 340282366920938463463374607431768211455, which cannot be narrowed to type 'unsigned long'}}
// expected-error@-1 {{the message in a static assertion must be produced by a constant expression}}
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
);

static_assert(
false, // expected-error {{static assertion failed}}
E{} // expected-error {{the message in a static assertion must be produced by a constant expression}}
// expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
);
}
79 changes: 79 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-intexpr-clause-ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,34 @@ void NormalUses() {
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel num_gangs(some_int(), some_long(), some_short())
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_gangs clause
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: CallExpr{{.*}}'long'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()'
// CHECK-NEXT: CallExpr{{.*}}'short'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'short (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'short ()' lvalue Function{{.*}} 'some_short' 'short ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc kernels num_gangs(some_int())
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_gangs clause
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
}

template<typename T, typename U>
Expand Down Expand Up @@ -187,6 +215,31 @@ void TemplUses(T t, U u) {
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc kernels num_gangs(u)
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_gangs clause
// CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel num_gangs(u, U::value)
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_gangs clause
// CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U'
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'U'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt


// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}}EndMarker
int EndMarker;

// Check the instantiated versions of the above.
// CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (CorrectConvert, HasInt)' implicit_instantiation
// CHECK-NEXT: TemplateArgument type 'CorrectConvert'
Expand Down Expand Up @@ -288,6 +341,32 @@ void TemplUses(T t, U u) {
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_gangs clause
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_gangs clause
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}}EndMarker
}

struct HasInt {
Expand Down
54 changes: 54 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-num_gangs-clause.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// RUN: %clang_cc1 %s -fopenacc -verify

short getS();
void Test() {
#pragma acc kernels num_gangs(1)
while(1);

// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(1)
while(1);

#pragma acc parallel num_gangs(1)
while(1);

// expected-error@+2{{OpenACC 'num_gangs' clause cannot appear more than once on a 'kernels' directive}}
// expected-note@+1{{previous clause is here}}
#pragma acc kernels num_gangs(1) num_gangs(2)
while(1);

// expected-error@+2{{OpenACC 'num_gangs' clause cannot appear more than once on a 'parallel' directive}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel num_gangs(1) num_gangs(2)
while(1);

// expected-error@+1{{too many integer expression arguments provided to OpenACC 'num_gangs' clause: 'kernels' directive expects maximum of 1, 2 were provided}}
#pragma acc kernels num_gangs(1, getS())
while(1);

// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(1, getS())
while(1);
#pragma acc parallel num_gangs(1, getS())
while(1);

struct NotConvertible{} NC;
// expected-error@+1{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel num_gangs(NC)
while(1);

// expected-error@+1{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel num_gangs(1, NC)
while(1);

// expected-error@+1{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel num_gangs(NC, 1)
while(1);

#pragma acc parallel num_gangs(getS(), 1, getS())
while(1);

// expected-error@+1{{too many integer expression arguments provided to OpenACC 'num_gangs' clause: 'parallel' directive expects maximum of 3, 4 were provided}}
#pragma acc parallel num_gangs(getS(), 1, getS(), 1)
while(1);
}
160 changes: 160 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct NotConvertible{} NC;
struct Incomplete *SomeIncomplete; // #INCOMPLETE
enum E{} SomeE;
enum class E2{} SomeE2;

struct CorrectConvert {
operator int();
} Convert;

struct ExplicitConvertOnly {
explicit operator int() const; // #EXPL_CONV
} Explicit;

struct AmbiguousConvert{
operator int(); // #AMBIG_INT
operator short(); // #AMBIG_SHORT
operator float();
} Ambiguous;

short some_short();
int some_int();
long some_long();

void Test() {
#pragma acc kernels num_gangs(1)
while(1);

// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(1)
while(1);

#pragma acc parallel num_gangs(1)
while(1);

// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(some_short(), some_int(), some_long())
while(1);

#pragma acc parallel num_gangs(some_short(), some_int(), some_long())
while(1);

// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(some_short(), some_int(), some_long(), SomeE)
while(1);

// expected-error@+1{{too many integer expression arguments provided to OpenACC 'num_gangs' clause: 'parallel' directive expects maximum of 3, 4 were provided}}
#pragma acc parallel num_gangs(some_short(), some_int(), some_long(), SomeE)
while(1);

// expected-error@+1{{too many integer expression arguments provided to OpenACC 'num_gangs' clause: 'kernels' directive expects maximum of 1, 2 were provided}}
#pragma acc kernels num_gangs(1, 2)
while(1);

// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(1, 2)
while(1);

#pragma acc parallel num_gangs(1, 2)
while(1);

// expected-error@+3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel num_gangs(Ambiguous)
while(1);

// expected-error@+1{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel num_gangs(NC, SomeE)
while(1);

// expected-error@+1{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel num_gangs(SomeE, NC)
while(1);

// expected-error@+3{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
// expected-error@+1{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel num_gangs(Explicit, NC)
while(1);

// expected-error@+4{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
// expected-error@+2{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(Explicit, NC)
while(1);

// expected-error@+6{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
// expected-error@+4{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
// expected-error@+3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel num_gangs(Explicit, NC, Ambiguous)
while(1);

// expected-error@+7{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
// expected-error@+5{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
// expected-error@+4{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(Explicit, NC, Ambiguous)
while(1);
// TODO
}

struct HasInt {
using IntTy = int;
using ShortTy = short;
static constexpr int value = 1;
static constexpr AmbiguousConvert ACValue;
static constexpr ExplicitConvertOnly EXValue;

operator char();
};

template <typename T>
void TestInst() {
// expected-error@+2{{no member named 'Invalid' in 'HasInt'}}
// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(HasInt::Invalid)
while(1);

// expected-error@+2{{no member named 'Invalid' in 'HasInt'}}
// expected-note@#INST{{in instantiation of function template specialization}}
#pragma acc parallel num_gangs(T::Invalid)
while(1);

// expected-error@+1{{no member named 'Invalid' in 'HasInt'}}
#pragma acc parallel num_gangs(1, HasInt::Invalid)
while(1);

// expected-error@+1{{no member named 'Invalid' in 'HasInt'}}
#pragma acc parallel num_gangs(T::Invalid, 1)
while(1);

// expected-error@+2{{no member named 'Invalid' in 'HasInt'}}
// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(1, HasInt::Invalid)
while(1);

// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(T::Invalid, 1)
while(1);

#pragma acc parallel num_gangs(T::value, typename T::IntTy{})
while(1);

// expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
#pragma acc serial num_gangs(T::value, typename T::IntTy{})
while(1);
}

void Inst() {
TestInst<HasInt>(); // #INST
}
4 changes: 4 additions & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2803,6 +2803,10 @@ void OpenACCClauseEnqueue::VisitVectorLengthClause(
const OpenACCVectorLengthClause &C) {
Visitor.AddStmt(C.getIntExpr());
}
void OpenACCClauseEnqueue::VisitNumGangsClause(const OpenACCNumGangsClause &C) {
for (Expr *IE : C.getIntExprs())
Visitor.AddStmt(IE);
}
} // namespace

void EnqueueVisitor::EnqueueChildren(const OpenACCClause *C) {
Expand Down
4 changes: 2 additions & 2 deletions clang/unittests/Analysis/FlowSensitive/TestingSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ const IndirectFieldDecl *findIndirectFieldDecl(ASTContext &ASTCtx,
/// Requirements:
///
/// `Name` must be unique in `ASTCtx`.
template <class LocT>
template <class LocT = StorageLocation>
LocT &getLocForDecl(ASTContext &ASTCtx, const Environment &Env,
llvm::StringRef Name) {
const ValueDecl *VD = findValueDecl(ASTCtx, Name);
Expand All @@ -470,7 +470,7 @@ LocT &getLocForDecl(ASTContext &ASTCtx, const Environment &Env,
/// Requirements:
///
/// `Name` must be unique in `ASTCtx`.
template <class ValueT>
template <class ValueT = Value>
ValueT &getValueForDecl(ASTContext &ASTCtx, const Environment &Env,
llvm::StringRef Name) {
const ValueDecl *VD = findValueDecl(ASTCtx, Name);
Expand Down
68 changes: 63 additions & 5 deletions clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3637,7 +3637,7 @@ TEST(TransferTest, VarDeclInitAssignConditionalOperator) {
};
void target(A Foo, A Bar, bool Cond) {
A Baz = Cond ? Foo : Bar;
A Baz = Cond ? A(Foo) : A(Bar);
// Make sure A::i is modeled.
Baz.i;
/*[[p]]*/
Expand Down Expand Up @@ -5275,6 +5275,67 @@ TEST(TransferTest, BinaryOperatorComma) {
});
}

TEST(TransferTest, ConditionalOperatorValue) {
std::string Code = R"(
void target(bool Cond, bool B1, bool B2) {
bool JoinSame = Cond ? B1 : B1;
bool JoinDifferent = Cond ? B1 : B2;
// [[p]]
}
)";
runDataflow(
Code,
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
ASTContext &ASTCtx) {
Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();

auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "B1");
auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "B2");
auto &JoinSame = getValueForDecl<BoolValue>(ASTCtx, Env, "JoinSame");
auto &JoinDifferent =
getValueForDecl<BoolValue>(ASTCtx, Env, "JoinDifferent");

EXPECT_EQ(&JoinSame, &B1);

const Formula &JoinDifferentEqB1 =
Env.arena().makeEquals(JoinDifferent.formula(), B1.formula());
EXPECT_TRUE(Env.allows(JoinDifferentEqB1));
EXPECT_FALSE(Env.proves(JoinDifferentEqB1));

const Formula &JoinDifferentEqB2 =
Env.arena().makeEquals(JoinDifferent.formula(), B2.formula());
EXPECT_TRUE(Env.allows(JoinDifferentEqB2));
EXPECT_FALSE(Env.proves(JoinDifferentEqB1));
});
}

TEST(TransferTest, ConditionalOperatorLocation) {
std::string Code = R"(
void target(bool Cond, int I1, int I2) {
int &JoinSame = Cond ? I1 : I1;
int &JoinDifferent = Cond ? I1 : I2;
// [[p]]
}
)";
runDataflow(
Code,
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
ASTContext &ASTCtx) {
Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();

StorageLocation &I1 = getLocForDecl(ASTCtx, Env, "I1");
StorageLocation &I2 = getLocForDecl(ASTCtx, Env, "I2");
StorageLocation &JoinSame = getLocForDecl(ASTCtx, Env, "JoinSame");
StorageLocation &JoinDifferent =
getLocForDecl(ASTCtx, Env, "JoinDifferent");

EXPECT_EQ(&JoinSame, &I1);

EXPECT_NE(&JoinDifferent, &I1);
EXPECT_NE(&JoinDifferent, &I2);
});
}

TEST(TransferTest, IfStmtBranchExtendsFlowCondition) {
std::string Code = R"(
void target(bool Foo) {
Expand Down Expand Up @@ -5522,10 +5583,7 @@ TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) {
auto *Loc = Env.getReturnStorageLocation();
EXPECT_THAT(Loc, NotNull());

// TODO: We would really like to make this stronger assertion, but that
// doesn't work because we don't propagate values correctly through
// the conditional operator yet.
// EXPECT_EQ(Loc, SLoc);
EXPECT_EQ(Loc, SLoc);
},
{BuiltinOptions{ContextSensitiveOptions{}}});
}
Expand Down
48 changes: 25 additions & 23 deletions clang/utils/TableGen/ClangAttrEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ static std::string ReadPCHRecord(StringRef type) {
return StringSwitch<std::string>(type)
.EndsWith("Decl *", "Record.GetLocalDeclAs<" +
std::string(type.data(), 0, type.size() - 1) +
">(Record.readInt())")
">(LocalDeclID(Record.readInt()))")
.Case("TypeSourceInfo *", "Record.readTypeSourceInfo()")
.Case("Expr *", "Record.readExpr()")
.Case("IdentifierInfo *", "Record.readIdentifier()")
Expand Down Expand Up @@ -1618,7 +1618,7 @@ writePrettyPrintFunction(const Record &R,
Spelling += Namespace;
Spelling += " ";
}
} else if (Variety == "HLSLSemantic") {
} else if (Variety == "HLSLAnnotation") {
Prefix = ":";
Suffix = "";
} else {
Expand Down Expand Up @@ -3608,7 +3608,7 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
// and declspecs. Then generate a big switch statement for each of them.
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
std::vector<std::pair<const Record *, FlattenedSpelling>> Declspec, Microsoft,
GNU, Pragma, HLSLSemantic;
GNU, Pragma, HLSLAnnotation;
std::map<std::string,
std::vector<std::pair<const Record *, FlattenedSpelling>>>
CXX, C23;
Expand All @@ -3631,8 +3631,8 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
C23[SI.nameSpace()].emplace_back(R, SI);
else if (Variety == "Pragma")
Pragma.emplace_back(R, SI);
else if (Variety == "HLSLSemantic")
HLSLSemantic.emplace_back(R, SI);
else if (Variety == "HLSLAnnotation")
HLSLAnnotation.emplace_back(R, SI);
}
}

Expand All @@ -3650,9 +3650,9 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << "case AttributeCommonInfo::Syntax::AS_Pragma:\n";
OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
OS << "case AttributeCommonInfo::Syntax::AS_HLSLSemantic:\n";
OS << "case AttributeCommonInfo::Syntax::AS_HLSLAnnotation:\n";
OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(HLSLSemantic, OS, "HLSLSemantic");
GenerateHasAttrSpellingStringSwitch(HLSLAnnotation, OS, "HLSLAnnotation");
auto fn = [&OS](const char *Spelling,
const std::map<
std::string,
Expand Down Expand Up @@ -4669,7 +4669,7 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {

std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11,
Keywords, Pragma, C23, HLSLSemantic;
Keywords, Pragma, C23, HLSLAnnotation;
std::set<std::string> Seen;
for (const auto *A : Attrs) {
const Record &Attr = *A;
Expand Down Expand Up @@ -4720,8 +4720,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
Matches = &Keywords;
else if (Variety == "Pragma")
Matches = &Pragma;
else if (Variety == "HLSLSemantic")
Matches = &HLSLSemantic;
else if (Variety == "HLSLAnnotation")
Matches = &HLSLAnnotation;

assert(Matches && "Unsupported spelling variety found");

Expand Down Expand Up @@ -4757,8 +4757,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
StringMatcher("Name", Keywords, OS).Emit();
OS << " } else if (AttributeCommonInfo::AS_Pragma == Syntax) {\n";
StringMatcher("Name", Pragma, OS).Emit();
OS << " } else if (AttributeCommonInfo::AS_HLSLSemantic == Syntax) {\n";
StringMatcher("Name", HLSLSemantic, OS).Emit();
OS << " } else if (AttributeCommonInfo::AS_HLSLAnnotation == Syntax) {\n";
StringMatcher("Name", HLSLAnnotation, OS).Emit();
OS << " }\n";
OS << " return AttributeCommonInfo::UnknownAttribute;\n"
<< "}\n";
Expand Down Expand Up @@ -4876,7 +4876,7 @@ enum class SpellingKind : size_t {
Microsoft,
Keyword,
Pragma,
HLSLSemantic,
HLSLAnnotation,
NumSpellingKinds
};
static const size_t NumSpellingKinds = (size_t)SpellingKind::NumSpellingKinds;
Expand All @@ -4890,15 +4890,16 @@ class SpellingList {
}

void add(const Record &Attr, FlattenedSpelling Spelling) {
SpellingKind Kind = StringSwitch<SpellingKind>(Spelling.variety())
.Case("GNU", SpellingKind::GNU)
.Case("CXX11", SpellingKind::CXX11)
.Case("C23", SpellingKind::C23)
.Case("Declspec", SpellingKind::Declspec)
.Case("Microsoft", SpellingKind::Microsoft)
.Case("Keyword", SpellingKind::Keyword)
.Case("Pragma", SpellingKind::Pragma)
.Case("HLSLSemantic", SpellingKind::HLSLSemantic);
SpellingKind Kind =
StringSwitch<SpellingKind>(Spelling.variety())
.Case("GNU", SpellingKind::GNU)
.Case("CXX11", SpellingKind::CXX11)
.Case("C23", SpellingKind::C23)
.Case("Declspec", SpellingKind::Declspec)
.Case("Microsoft", SpellingKind::Microsoft)
.Case("Keyword", SpellingKind::Keyword)
.Case("Pragma", SpellingKind::Pragma)
.Case("HLSLAnnotation", SpellingKind::HLSLAnnotation);
std::string Name;
if (!Spelling.nameSpace().empty()) {
switch (Kind) {
Expand Down Expand Up @@ -5007,7 +5008,8 @@ static void WriteDocumentation(RecordKeeper &Records,
// so it must be last.
OS << ".. csv-table:: Supported Syntaxes\n";
OS << " :header: \"GNU\", \"C++11\", \"C23\", \"``__declspec``\",";
OS << " \"Keyword\", \"``#pragma``\", \"HLSL Semantic\", \"``#pragma clang ";
OS << " \"Keyword\", \"``#pragma``\", \"HLSL Annotation\", \"``#pragma "
"clang ";
OS << "attribute``\"\n\n \"";
for (size_t Kind = 0; Kind != NumSpellingKinds; ++Kind) {
SpellingKind K = (SpellingKind)Kind;
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ option(COMPILER_RT_BUILD_LIBFUZZER "Build libFuzzer" ON)
mark_as_advanced(COMPILER_RT_BUILD_LIBFUZZER)
option(COMPILER_RT_BUILD_PROFILE "Build profile runtime" ON)
mark_as_advanced(COMPILER_RT_BUILD_PROFILE)
option(COMPILER_RT_BUILD_CTX_PROFILE "Build ctx profile runtime" ON)
mark_as_advanced(COMPILER_RT_BUILD_CTX_PROFILE)
option(COMPILER_RT_BUILD_MEMPROF "Build memory profiling runtime" ON)
mark_as_advanced(COMPILER_RT_BUILD_MEMPROF)
option(COMPILER_RT_BUILD_XRAY_NO_PREINIT "Build xray with no preinit patching" OFF)
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64})
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC64}
${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
${RISCV32} ${RISCV64} ${LOONGARCH64})
set(ALL_CTX_PROFILE_SUPPORTED_ARCH ${X86_64})
set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X}
${LOONGARCH64} ${RISCV64})
set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
Expand Down
11 changes: 11 additions & 0 deletions compiler-rt/cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,9 @@ if(APPLE)
list_intersect(PROFILE_SUPPORTED_ARCH
ALL_PROFILE_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
list_intersect(CTX_PROFILE_SUPPORTED_ARCH
ALL_CTX_PROFILE_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
list_intersect(TSAN_SUPPORTED_ARCH
ALL_TSAN_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
Expand Down Expand Up @@ -678,6 +681,7 @@ else()
filter_available_targets(HWASAN_SUPPORTED_ARCH ${ALL_HWASAN_SUPPORTED_ARCH})
filter_available_targets(MEMPROF_SUPPORTED_ARCH ${ALL_MEMPROF_SUPPORTED_ARCH})
filter_available_targets(PROFILE_SUPPORTED_ARCH ${ALL_PROFILE_SUPPORTED_ARCH})
filter_available_targets(CTX_PROFILE_SUPPORTED_ARCH ${ALL_CTX_PROFILE_SUPPORTED_ARCH})
filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH})
filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH})
filter_available_targets(SAFESTACK_SUPPORTED_ARCH
Expand Down Expand Up @@ -803,6 +807,13 @@ else()
set(COMPILER_RT_HAS_PROFILE FALSE)
endif()

if (COMPILER_RT_HAS_SANITIZER_COMMON AND CTX_PROFILE_SUPPORTED_ARCH AND
OS_NAME MATCHES "Linux")
set(COMPILER_RT_HAS_CTX_PROFILE TRUE)
else()
set(COMPILER_RT_HAS_CTX_PROFILE FALSE)
endif()

if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH)
if (OS_NAME MATCHES "Linux|Darwin|FreeBSD|NetBSD")
set(COMPILER_RT_HAS_TSAN TRUE)
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ if(COMPILER_RT_BUILD_PROFILE AND COMPILER_RT_HAS_PROFILE)
compiler_rt_build_runtime(profile)
endif()

if(COMPILER_RT_BUILD_CTX_PROFILE AND COMPILER_RT_HAS_CTX_PROFILE)
compiler_rt_build_runtime(ctx_profile)
endif()

if(COMPILER_RT_BUILD_XRAY)
compiler_rt_build_runtime(xray)
endif()
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/builtins/fp_add_impl.inc
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static __inline fp_t __addXf3__(fp_t a, fp_t b) {

// Shift the significand of b by the difference in exponents, with a sticky
// bottom bit to get rounding correct.
const unsigned int align = aExponent - bExponent;
const unsigned int align = (unsigned int)(aExponent - bExponent);
if (align) {
if (align < typeWidth) {
const bool sticky = (bSignificand << (typeWidth - align)) != 0;
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/builtins/fp_fixint_impl.inc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static __inline fixint_t __fixint(fp_t a) {
// If 0 <= exponent < significandBits, right shift to get the result.
// Otherwise, shift left.
if (exponent < significandBits)
return sign * (significand >> (significandBits - exponent));
return (fixint_t)(sign * (significand >> (significandBits - exponent)));
else
return sign * ((fixuint_t)significand << (exponent - significandBits));
return (fixint_t)(sign * ((fixuint_t)significand << (exponent - significandBits)));
}
6 changes: 3 additions & 3 deletions compiler-rt/lib/builtins/fp_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ static __inline int rep_clz(rep_t a) { return clzsi(a); }
// 32x32 --> 64 bit multiply
static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
const uint64_t product = (uint64_t)a * b;
*hi = product >> 32;
*lo = product;
*hi = (rep_t)(product >> 32);
*lo = (rep_t)product;
}
COMPILER_RT_ABI fp_t __addsf3(fp_t a, fp_t b);

Expand Down Expand Up @@ -239,7 +239,7 @@ static __inline int normalize(rep_t *significand) {
return 1 - shift;
}

static __inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) {
static __inline void wideLeftShift(rep_t *hi, rep_t *lo, unsigned int count) {
*hi = *hi << count | *lo >> (typeWidth - count);
*lo = *lo << count;
}
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/builtins/int_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ typedef union {

static __inline ti_int make_ti(di_int h, di_int l) {
twords r;
r.s.high = h;
r.s.low = l;
r.s.high = (du_int)h;
r.s.low = (du_int)l;
return r.all;
}

Expand Down
19 changes: 19 additions & 0 deletions compiler-rt/lib/ctx_profile/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
add_compiler_rt_component(ctx_profile)

set(CTX_PROFILE_SOURCES
CtxInstrProfiling.cpp
)

set(CTX_PROFILE_HEADERS
CtxInstrProfiling.h
)

include_directories(..)
include_directories(../../include)

# We don't use the C++ Standard Library here, so avoid including it by mistake.
append_list_if(COMPILER_RT_HAS_NOSTDINCXX_FLAG -nostdinc++ EXTRA_FLAGS)

if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
endif()
40 changes: 40 additions & 0 deletions compiler-rt/lib/ctx_profile/CtxInstrProfiling.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===- CtxInstrProfiling.cpp - contextual instrumented PGO ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "CtxInstrProfiling.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_dense_map.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_thread_safety.h"

#include <assert.h>

using namespace __ctx_profile;

// FIXME(mtrofin): use malloc / mmap instead of sanitizer common APIs to reduce
// the dependency on the latter.
Arena *Arena::allocateNewArena(size_t Size, Arena *Prev) {
assert(!Prev || Prev->Next == nullptr);
Arena *NewArena =
new (__sanitizer::InternalAlloc(Size + sizeof(Arena))) Arena(Size);
if (Prev)
Prev->Next = NewArena;
return NewArena;
}

void Arena::freeArenaList(Arena *&A) {
assert(A);
for (auto *I = A; I != nullptr;) {
auto *Current = I;
I = I->Next;
__sanitizer::InternalFree(Current);
}
A = nullptr;
}
55 changes: 55 additions & 0 deletions compiler-rt/lib/ctx_profile/CtxInstrProfiling.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*===- CtxInstrProfiling.h- Contextual instrumentation-based PGO ---------===*\
|*
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|* See https://llvm.org/LICENSE.txt for license information.
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|*
\*===----------------------------------------------------------------------===*/

#ifndef CTX_PROFILE_CTXINSTRPROFILING_H_
#define CTX_PROFILE_CTXINSTRPROFILING_H_

#include <sanitizer/common_interface_defs.h>

namespace __ctx_profile {

/// Arena (bump allocator) forming a linked list. Intentionally not thread safe.
/// Allocation and de-allocation happen using sanitizer APIs. We make that
/// explicit.
class Arena final {
public:
// When allocating a new Arena, optionally specify an existing one to append
// to, assumed to be the last in the Arena list. We only need to support
// appending to the arena list.
static Arena *allocateNewArena(size_t Size, Arena *Prev = nullptr);
static void freeArenaList(Arena *&A);

uint64_t size() const { return Size; }

// Allocate S bytes or return nullptr if we don't have that many available.
char *tryBumpAllocate(size_t S) {
if (Pos + S > Size)
return nullptr;
Pos += S;
return start() + (Pos - S);
}

Arena *next() const { return Next; }

// the beginning of allocatable memory.
const char *start() const { return const_cast<Arena *>(this)->start(); }
const char *pos() const { return start() + Pos; }

private:
explicit Arena(uint32_t Size) : Size(Size) {}
~Arena() = delete;

char *start() { return reinterpret_cast<char *>(&this[1]); }

Arena *Next = nullptr;
uint64_t Pos = 0;
const uint64_t Size;
};

} // namespace __ctx_profile
#endif // CTX_PROFILE_CTXINSTRPROFILING_H_
82 changes: 82 additions & 0 deletions compiler-rt/lib/ctx_profile/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
include(CheckCXXCompilerFlag)
include(CompilerRTCompile)
include(CompilerRTLink)

set(CTX_PROFILE_UNITTEST_CFLAGS
${COMPILER_RT_UNITTEST_CFLAGS}
${COMPILER_RT_GTEST_CFLAGS}
${COMPILER_RT_GMOCK_CFLAGS}
${SANITIZER_TEST_CXX_CFLAGS}
-I${COMPILER_RT_SOURCE_DIR}/lib/
-DSANITIZER_COMMON_NO_REDEFINE_BUILTINS
-O2
-g
-fno-rtti
-Wno-pedantic
-fno-omit-frame-pointer)

# Suppress warnings for gmock variadic macros for clang and gcc respectively.
append_list_if(SUPPORTS_GNU_ZERO_VARIADIC_MACRO_ARGUMENTS_FLAG -Wno-gnu-zero-variadic-macro-arguments CTX_PROFILE_UNITTEST_CFLAGS)
append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros CTX_PROFILE_UNITTEST_CFLAGS)

file(GLOB CTX_PROFILE_HEADERS ../*.h)

set(CTX_PROFILE_SOURCES
../CtxInstrProfiling.cpp)

set(CTX_PROFILE_UNITTESTS
CtxInstrProfilingTest.cpp
driver.cpp)

include_directories(../../../include)

set(CTX_PROFILE_UNITTEST_HEADERS
${CTX_PROFILE_HEADERS})

set(CTX_PROFILE_UNITTEST_LINK_FLAGS
${COMPILER_RT_UNITTEST_LINK_FLAGS})

list(APPEND CTX_PROFILE_UNITTEST_LINK_FLAGS -pthread)

set(CTX_PROFILE_UNITTEST_DEPS)
if (TARGET cxx-headers OR HAVE_LIBCXX)
list(APPEND CTX_PROFILE_UNITTEST_DEPS cxx-headers)
endif()

set(CTX_PROFILE_UNITTEST_LINK_LIBRARIES
${COMPILER_RT_UNWINDER_LINK_LIBS}
${SANITIZER_TEST_CXX_LIBRARIES})
append_list_if(COMPILER_RT_HAS_LIBDL -ldl CTX_PROFILE_UNITTEST_LINK_LIBRARIES)

macro (add_ctx_profile_tests_for_arch arch)
set(CTX_PROFILE_TEST_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizerInternal.${arch}>
)
set(CTX_PROFILE_TEST_RUNTIME RTCtxProfileTest.${arch})
add_library(${CTX_PROFILE_TEST_RUNTIME} STATIC ${CTX_PROFILE_TEST_RUNTIME_OBJECTS})
set_target_properties(${CTX_PROFILE_TEST_RUNTIME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
FOLDER "Compiler-RT Runtime tests")
set(CTX_PROFILE_TEST_OBJECTS)
generate_compiler_rt_tests(CTX_PROFILE_TEST_OBJECTS
CtxProfileUnitTests "CtxProfile-${arch}-UnitTest" ${arch}
RUNTIME ${CTX_PROFILE_TEST_RUNTIME}
DEPS ${CTX_PROFILE_UNITTEST_DEPS}
SOURCES ${CTX_PROFILE_UNITTESTS} ${CTX_PROFILE_SOURCES} ${COMPILER_RT_GTEST_SOURCE}
COMPILE_DEPS ${CTX_PROFILE_UNITTEST_HEADERS}
CFLAGS ${CTX_PROFILE_UNITTEST_CFLAGS}
LINK_FLAGS ${CTX_PROFILE_UNITTEST_LINK_FLAGS} ${CTX_PROFILE_UNITTEST_LINK_LIBRARIES})
endmacro()

add_custom_target(CtxProfileUnitTests)
set_target_properties(CtxProfileUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST CTX_PROFILE_SUPPORTED_ARCH)
# CtxProfile unit tests are only run on the host machine.
foreach(arch ${COMPILER_RT_DEFAULT_TARGET_ARCH})
add_ctx_profile_tests_for_arch(${arch})
endforeach()
endif()
22 changes: 22 additions & 0 deletions compiler-rt/lib/ctx_profile/tests/CtxInstrProfilingTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "../CtxInstrProfiling.h"
#include "gtest/gtest.h"

using namespace __ctx_profile;

TEST(ArenaTest, Basic) {
Arena *A = Arena::allocateNewArena(1024);
EXPECT_EQ(A->size(), 1024U);
EXPECT_EQ(A->next(), nullptr);

auto *M1 = A->tryBumpAllocate(1020);
EXPECT_NE(M1, nullptr);
auto *M2 = A->tryBumpAllocate(4);
EXPECT_NE(M2, nullptr);
EXPECT_EQ(M1 + 1020, M2);
EXPECT_EQ(A->tryBumpAllocate(1), nullptr);
Arena *A2 = Arena::allocateNewArena(2024, A);
EXPECT_EQ(A->next(), A2);
EXPECT_EQ(A2->next(), nullptr);
Arena::freeArenaList(A);
EXPECT_EQ(A, nullptr);
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
//===-- Header for setting up the Pigweed tests -----------------*- C++ -*-===//
//===-- driver.cpp ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_UTILS_UNITTEST_PIGWEEDTEST_H
#define LLVM_LIBC_UTILS_UNITTEST_PIGWEEDTEST_H
#include "gtest/gtest.h"

#include <gtest/gtest.h>

namespace LIBC_NAMESPACE::testing {
using Test = ::testing::Test;
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

#endif // LLVM_LIBC_UTILS_UNITTEST_PIGWEEDTEST_H
10 changes: 5 additions & 5 deletions compiler-rt/test/gwp_asan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ if (COMPILER_RT_INCLUDE_TESTS AND COMPILER_RT_HAS_SCUDO_STANDALONE AND COMPILER_
${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py)
list(APPEND GWP_ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
endforeach()
endif()

add_lit_testsuite(check-gwp_asan "Running the GWP-ASan tests"
${GWP_ASAN_TESTSUITES}
DEPENDS ${GWP_ASAN_TEST_DEPS})
set_target_properties(check-gwp_asan PROPERTIES FOLDER "Compiler-RT Misc")
add_lit_testsuite(check-gwp_asan "Running the GWP-ASan tests"
${GWP_ASAN_TESTSUITES}
DEPENDS ${GWP_ASAN_TEST_DEPS})
set_target_properties(check-gwp_asan PROPERTIES FOLDER "Compiler-RT Misc")
endif()
49 changes: 21 additions & 28 deletions flang/include/flang/Common/real.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,27 @@ static constexpr int PrecisionOfRealKind(int kind) {
}
}

template <int BINARY_PRECISION> class RealDetails {
// RealCharacteristics is constexpr, but also useful when constructed
// with a non-constant precision argument.
class RealCharacteristics {
public:
explicit constexpr RealCharacteristics(int p) : binaryPrecision{p} {}

int binaryPrecision;
int bits{BitsForBinaryPrecision(binaryPrecision)};
bool isImplicitMSB{binaryPrecision != 64 /*x87*/};
int significandBits{binaryPrecision - isImplicitMSB};
int exponentBits{bits - significandBits - 1 /*sign*/};
int maxExponent{(1 << exponentBits) - 1};
int exponentBias{maxExponent / 2};
int decimalPrecision{LogBaseTwoToLogBaseTen(binaryPrecision - 1)};
int decimalRange{LogBaseTwoToLogBaseTen(exponentBias - 1)};
// Number of significant decimal digits in the fraction of the
// exact conversion of the least nonzero subnormal.
int maxDecimalConversionDigits{MaxDecimalConversionDigits(binaryPrecision)};
int maxHexadecimalConversionDigits{
MaxHexadecimalConversionDigits(binaryPrecision)};

private:
// Converts bit widths to whole decimal digits
static constexpr int LogBaseTwoToLogBaseTen(int logb2) {
Expand All @@ -118,33 +138,6 @@ template <int BINARY_PRECISION> class RealDetails {
(logb2 * LogBaseTenOfTwoTimesTenToThe12th) / TenToThe12th};
return static_cast<int>(logb10);
}

public:
RT_OFFLOAD_VAR_GROUP_BEGIN
static constexpr int binaryPrecision{BINARY_PRECISION};
static constexpr int bits{BitsForBinaryPrecision(binaryPrecision)};
static constexpr bool isImplicitMSB{binaryPrecision != 64 /*x87*/};
static constexpr int significandBits{binaryPrecision - isImplicitMSB};
static constexpr int exponentBits{bits - significandBits - 1 /*sign*/};
static constexpr int maxExponent{(1 << exponentBits) - 1};
static constexpr int exponentBias{maxExponent / 2};

static constexpr int decimalPrecision{
LogBaseTwoToLogBaseTen(binaryPrecision - 1)};
static constexpr int decimalRange{LogBaseTwoToLogBaseTen(exponentBias - 1)};

// Number of significant decimal digits in the fraction of the
// exact conversion of the least nonzero subnormal.
static constexpr int maxDecimalConversionDigits{
MaxDecimalConversionDigits(binaryPrecision)};

static constexpr int maxHexadecimalConversionDigits{
MaxHexadecimalConversionDigits(binaryPrecision)};
RT_OFFLOAD_VAR_GROUP_END

static_assert(binaryPrecision > 0);
static_assert(exponentBits > 1);
static_assert(exponentBits <= 15);
};

} // namespace Fortran::common
Expand Down
27 changes: 13 additions & 14 deletions flang/include/flang/Decimal/binary-floating-point.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,20 @@ enum FortranRounding {
RoundCompatible, /* RC: like RN, but ties go away from 0 */
};

template <int BINARY_PRECISION>
class BinaryFloatingPointNumber : public common::RealDetails<BINARY_PRECISION> {
template <int BINARY_PRECISION> class BinaryFloatingPointNumber {
public:
using Details = common::RealDetails<BINARY_PRECISION>;
using Details::binaryPrecision;
using Details::bits;
using Details::decimalPrecision;
using Details::decimalRange;
using Details::exponentBias;
using Details::exponentBits;
using Details::isImplicitMSB;
using Details::maxDecimalConversionDigits;
using Details::maxExponent;
using Details::maxHexadecimalConversionDigits;
using Details::significandBits;
static constexpr common::RealCharacteristics realChars{BINARY_PRECISION};
static constexpr int binaryPrecision{BINARY_PRECISION};
static constexpr int bits{realChars.bits};
static constexpr int isImplicitMSB{realChars.isImplicitMSB};
static constexpr int significandBits{realChars.significandBits};
static constexpr int exponentBits{realChars.exponentBits};
static constexpr int exponentBias{realChars.exponentBias};
static constexpr int maxExponent{realChars.maxExponent};
static constexpr int decimalPrecision{realChars.decimalPrecision};
static constexpr int decimalRange{realChars.decimalRange};
static constexpr int maxDecimalConversionDigits{
realChars.maxDecimalConversionDigits};

using RawType = common::HostUnsignedIntType<bits>;
static_assert(CHAR_BIT * sizeof(RawType) >= bits);
Expand Down
7 changes: 5 additions & 2 deletions flang/include/flang/Evaluate/call.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,15 +287,18 @@ template <typename A> class FunctionRef : public ProcedureRef {
: ProcedureRef{std::move(p), std::move(a)} {}

std::optional<DynamicType> GetType() const {
if (auto type{proc_.GetType()}) {
if constexpr (IsLengthlessIntrinsicType<A>) {
return A::GetType();
} else if (auto type{proc_.GetType()}) {
// TODO: Non constant explicit length parameters of PDTs result should
// likely be dropped too. This is not as easy as for characters since some
// long lived DerivedTypeSpec pointer would need to be created here. It is
// not clear if this is causing any issue so far since the storage size of
// PDTs is independent of length parameters.
return type->DropNonConstantCharacterLength();
} else {
return std::nullopt;
}
return std::nullopt;
}
};
} // namespace Fortran::evaluate
Expand Down
2 changes: 1 addition & 1 deletion flang/include/flang/Evaluate/characteristics.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ struct Procedure {
static std::optional<Procedure> Characterize(
const semantics::Symbol &, FoldingContext &);
static std::optional<Procedure> Characterize(
const ProcedureDesignator &, FoldingContext &);
const ProcedureDesignator &, FoldingContext &, bool emitError);
static std::optional<Procedure> Characterize(
const ProcedureRef &, FoldingContext &);
static std::optional<Procedure> Characterize(
Expand Down
2 changes: 1 addition & 1 deletion flang/include/flang/Evaluate/complex.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ extern template class Complex<Real<Integer<16>, 11>>;
extern template class Complex<Real<Integer<16>, 8>>;
extern template class Complex<Real<Integer<32>, 24>>;
extern template class Complex<Real<Integer<64>, 53>>;
extern template class Complex<Real<Integer<80>, 64>>;
extern template class Complex<Real<X87IntegerContainer, 64>>;
extern template class Complex<Real<Integer<128>, 113>>;
} // namespace Fortran::evaluate::value
#endif // FORTRAN_EVALUATE_COMPLEX_H_
15 changes: 11 additions & 4 deletions flang/include/flang/Evaluate/integer.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ namespace Fortran::evaluate::value {
// named accordingly in ALL CAPS so that they can be referenced easily in
// the language standard.
template <int BITS, bool IS_LITTLE_ENDIAN = isHostLittleEndian,
int PARTBITS = BITS <= 32 ? BITS : 32,
int PARTBITS = BITS <= 32 ? BITS
: BITS % 32 == 0 ? 32
: BITS % 16 == 0 ? 16
: 8,
typename PART = HostUnsignedInt<PARTBITS>,
typename BIGPART = HostUnsignedInt<PARTBITS * 2>>
typename BIGPART = HostUnsignedInt<PARTBITS * 2>, int ALIGNMENT = BITS>
class Integer {
public:
static constexpr int bits{BITS};
Expand All @@ -79,6 +82,8 @@ class Integer {
static_assert((parts - 1) * partBits + topPartBits == bits);
static constexpr Part partMask{static_cast<Part>(~0) >> extraPartBits};
static constexpr Part topPartMask{static_cast<Part>(~0) >> extraTopPartBits};
static constexpr int partsWithAlignment{
(ALIGNMENT + partBits - 1) / partBits};

public:
// Some types used for member function results
Expand Down Expand Up @@ -1043,14 +1048,16 @@ class Integer {
}
}

Part part_[parts]{};
Part part_[partsWithAlignment]{};
};

extern template class Integer<8>;
extern template class Integer<16>;
extern template class Integer<32>;
extern template class Integer<64>;
extern template class Integer<80>;
using X87IntegerContainer =
Integer<80, true, 16, std::uint16_t, std::uint32_t, 128>;
extern template class Integer<80, true, 16, std::uint16_t, std::uint32_t, 128>;
extern template class Integer<128>;
} // namespace Fortran::evaluate::value
#endif // FORTRAN_EVALUATE_INTEGER_H_
27 changes: 15 additions & 12 deletions flang/include/flang/Evaluate/real.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,19 @@ static constexpr std::int64_t ScaledLogBaseTenOfTwo{301029995664};
// class template must be (or look like) an instance of Integer<>;
// the second specifies the number of effective bits (binary precision)
// in the fraction.
template <typename WORD, int PREC>
class Real : public common::RealDetails<PREC> {
template <typename WORD, int PREC> class Real {
public:
using Word = WORD;
static constexpr int binaryPrecision{PREC};
using Details = common::RealDetails<PREC>;
using Details::exponentBias;
using Details::exponentBits;
using Details::isImplicitMSB;
using Details::maxExponent;
using Details::significandBits;
static constexpr common::RealCharacteristics realChars{PREC};
static constexpr int exponentBias{realChars.exponentBias};
static constexpr int exponentBits{realChars.exponentBits};
static constexpr int isImplicitMSB{realChars.isImplicitMSB};
static constexpr int maxExponent{realChars.maxExponent};
static constexpr int significandBits{realChars.significandBits};

static constexpr int bits{Word::bits};
static_assert(bits >= Details::bits);
static_assert(bits >= realChars.bits);
using Fraction = Integer<binaryPrecision>; // all bits made explicit

template <typename W, int P> friend class Real;
Expand Down Expand Up @@ -205,8 +204,8 @@ class Real : public common::RealDetails<PREC> {
}

static constexpr int DIGITS{binaryPrecision};
static constexpr int PRECISION{Details::decimalPrecision};
static constexpr int RANGE{Details::decimalRange};
static constexpr int PRECISION{realChars.decimalPrecision};
static constexpr int RANGE{realChars.decimalRange};
static constexpr int MAXEXPONENT{maxExponent - exponentBias};
static constexpr int MINEXPONENT{2 - exponentBias};
Real RRSPACING() const;
Expand Down Expand Up @@ -371,6 +370,10 @@ class Real : public common::RealDetails<PREC> {
return result;
}
bool isNegative{x.IsNegative()};
if (x.IsInfinite()) {
result.value = Infinity(isNegative);
return result;
}
A absX{x};
if (isNegative) {
absX = x.Negate();
Expand Down Expand Up @@ -493,7 +496,7 @@ extern template class Real<Integer<16>, 11>; // IEEE half format
extern template class Real<Integer<16>, 8>; // the "other" half format
extern template class Real<Integer<32>, 24>; // IEEE single
extern template class Real<Integer<64>, 53>; // IEEE double
extern template class Real<Integer<80>, 64>; // 80387 extended precision
extern template class Real<X87IntegerContainer, 64>; // 80387 extended precision
extern template class Real<Integer<128>, 113>; // IEEE quad
// N.B. No "double-double" support.
} // namespace Fortran::evaluate::value
Expand Down
5 changes: 4 additions & 1 deletion flang/include/flang/Evaluate/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,10 @@ class Type<TypeCategory::Real, KIND>
public:
static constexpr int precision{common::PrecisionOfRealKind(KIND)};
static constexpr int bits{common::BitsForBinaryPrecision(precision)};
using Scalar = value::Real<value::Integer<bits>, precision>;
using Scalar =
value::Real<std::conditional_t<precision == 64,
value::X87IntegerContainer, value::Integer<bits>>,
precision>;
};

// The KIND type parameter on COMPLEX is the kind of each of its components.
Expand Down
5 changes: 5 additions & 0 deletions flang/include/flang/Semantics/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,12 +435,17 @@ class ProcEntityDetails : public EntityDetails, public WithPassArg {
void set_init(std::nullptr_t) { init_ = nullptr; }
bool isCUDAKernel() const { return isCUDAKernel_; }
void set_isCUDAKernel(bool yes = true) { isCUDAKernel_ = yes; }
std::optional<SourceName> usedAsProcedureHere() const {
return usedAsProcedureHere_;
}
void set_usedAsProcedureHere(SourceName here) { usedAsProcedureHere_ = here; }

private:
const Symbol *rawProcInterface_{nullptr};
const Symbol *procInterface_{nullptr};
std::optional<const Symbol *> init_;
bool isCUDAKernel_{false};
std::optional<SourceName> usedAsProcedureHere_;
friend llvm::raw_ostream &operator<<(
llvm::raw_ostream &, const ProcEntityDetails &);
};
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Decimal/big-radix-floating-point.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
return *this;
}

RT_API_ATTRS bool IsInteger() const { return exponent_ >= 0; }

// Converts decimal floating-point to binary.
RT_API_ATTRS ConversionToBinaryResult<PREC> ConvertToBinary();

Expand Down
74 changes: 41 additions & 33 deletions flang/lib/Evaluate/characteristics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,11 +576,11 @@ static std::optional<DummyArgument> CharacterizeDummyArgument(
semantics::UnorderedSymbolSet seenProcs);
static std::optional<FunctionResult> CharacterizeFunctionResult(
const semantics::Symbol &symbol, FoldingContext &context,
semantics::UnorderedSymbolSet seenProcs);
semantics::UnorderedSymbolSet seenProcs, bool emitError);

static std::optional<Procedure> CharacterizeProcedure(
const semantics::Symbol &original, FoldingContext &context,
semantics::UnorderedSymbolSet seenProcs) {
semantics::UnorderedSymbolSet seenProcs, bool emitError) {
const auto &symbol{ResolveAssociations(original)};
if (seenProcs.find(symbol) != seenProcs.end()) {
std::string procsList{GetSeenProcs(seenProcs)};
Expand All @@ -591,14 +591,21 @@ static std::optional<Procedure> CharacterizeProcedure(
return std::nullopt;
}
seenProcs.insert(symbol);
auto CheckForNested{[&](const Symbol &symbol) {
if (emitError) {
context.messages().Say(
"Procedure '%s' is referenced before being sufficiently defined in a context where it must be so"_err_en_US,
symbol.name());
}
}};
auto result{common::visit(
common::visitors{
[&](const semantics::SubprogramDetails &subp)
-> std::optional<Procedure> {
Procedure result;
if (subp.isFunction()) {
if (auto fr{CharacterizeFunctionResult(
subp.result(), context, seenProcs)}) {
subp.result(), context, seenProcs, emitError)}) {
result.functionResult = std::move(fr);
} else {
return std::nullopt;
Expand Down Expand Up @@ -641,8 +648,8 @@ static std::optional<Procedure> CharacterizeProcedure(
}
if (const semantics::Symbol *
interfaceSymbol{proc.procInterface()}) {
auto result{
CharacterizeProcedure(*interfaceSymbol, context, seenProcs)};
auto result{CharacterizeProcedure(
*interfaceSymbol, context, seenProcs, /*emitError=*/false)};
if (result && (IsDummy(symbol) || IsPointer(symbol))) {
// Dummy procedures and procedure pointers may not be
// ELEMENTAL, but we do accept the use of elemental intrinsic
Expand Down Expand Up @@ -675,8 +682,8 @@ static std::optional<Procedure> CharacterizeProcedure(
}
},
[&](const semantics::ProcBindingDetails &binding) {
if (auto result{CharacterizeProcedure(
binding.symbol(), context, seenProcs)}) {
if (auto result{CharacterizeProcedure(binding.symbol(), context,
seenProcs, /*emitError=*/false)}) {
if (binding.symbol().attrs().test(semantics::Attr::INTRINSIC)) {
result->attrs.reset(Procedure::Attr::Elemental);
}
Expand All @@ -695,33 +702,32 @@ static std::optional<Procedure> CharacterizeProcedure(
}
},
[&](const semantics::UseDetails &use) {
return CharacterizeProcedure(use.symbol(), context, seenProcs);
return CharacterizeProcedure(
use.symbol(), context, seenProcs, /*emitError=*/false);
},
[](const semantics::UseErrorDetails &) {
// Ambiguous use-association will be handled later during symbol
// checks, ignore UseErrorDetails here without actual symbol usage.
return std::optional<Procedure>{};
},
[&](const semantics::HostAssocDetails &assoc) {
return CharacterizeProcedure(assoc.symbol(), context, seenProcs);
return CharacterizeProcedure(
assoc.symbol(), context, seenProcs, /*emitError=*/false);
},
[&](const semantics::GenericDetails &generic) {
if (const semantics::Symbol * specific{generic.specific()}) {
return CharacterizeProcedure(*specific, context, seenProcs);
return CharacterizeProcedure(
*specific, context, seenProcs, emitError);
} else {
return std::optional<Procedure>{};
}
},
[&](const semantics::EntityDetails &) {
context.messages().Say(
"Procedure '%s' is referenced before being sufficiently defined in a context where it must be so"_err_en_US,
symbol.name());
CheckForNested(symbol);
return std::optional<Procedure>{};
},
[&](const semantics::SubprogramNameDetails &) {
context.messages().Say(
"Procedure '%s' is referenced before being sufficiently defined in a context where it must be so"_err_en_US,
symbol.name());
CheckForNested(symbol);
return std::optional<Procedure>{};
},
[&](const auto &) {
Expand Down Expand Up @@ -752,7 +758,8 @@ static std::optional<Procedure> CharacterizeProcedure(
static std::optional<DummyProcedure> CharacterizeDummyProcedure(
const semantics::Symbol &symbol, FoldingContext &context,
semantics::UnorderedSymbolSet seenProcs) {
if (auto procedure{CharacterizeProcedure(symbol, context, seenProcs)}) {
if (auto procedure{CharacterizeProcedure(
symbol, context, seenProcs, /*emitError=*/true)}) {
// Dummy procedures may not be elemental. Elemental dummy procedure
// interfaces are errors when the interface is not intrinsic, and that
// error is caught elsewhere. Elemental intrinsic interfaces are
Expand Down Expand Up @@ -854,7 +861,8 @@ std::optional<DummyArgument> DummyArgument::FromActual(std::string &&name,
std::move(name), std::move(obj));
},
[&](const ProcedureDesignator &designator) {
if (auto proc{Procedure::Characterize(designator, context)}) {
if (auto proc{Procedure::Characterize(
designator, context, /*emitError=*/true)}) {
return std::make_optional<DummyArgument>(
std::move(name), DummyProcedure{std::move(*proc)});
} else {
Expand Down Expand Up @@ -988,7 +996,7 @@ bool FunctionResult::operator==(const FunctionResult &that) const {

static std::optional<FunctionResult> CharacterizeFunctionResult(
const semantics::Symbol &symbol, FoldingContext &context,
semantics::UnorderedSymbolSet seenProcs) {
semantics::UnorderedSymbolSet seenProcs, bool emitError) {
if (const auto *object{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
if (auto type{TypeAndShape::Characterize(
symbol, context, /*invariantOnly=*/false)}) {
Expand All @@ -1002,8 +1010,8 @@ static std::optional<FunctionResult> CharacterizeFunctionResult(
result.cudaDataAttr = object->cudaDataAttr();
return result;
}
} else if (auto maybeProc{
CharacterizeProcedure(symbol, context, seenProcs)}) {
} else if (auto maybeProc{CharacterizeProcedure(
symbol, context, seenProcs, emitError)}) {
FunctionResult result{std::move(*maybeProc)};
result.attrs.set(FunctionResult::Attr::Pointer);
return result;
Expand All @@ -1014,7 +1022,8 @@ static std::optional<FunctionResult> CharacterizeFunctionResult(
std::optional<FunctionResult> FunctionResult::Characterize(
const Symbol &symbol, FoldingContext &context) {
semantics::UnorderedSymbolSet seenProcs;
return CharacterizeFunctionResult(symbol, context, seenProcs);
return CharacterizeFunctionResult(
symbol, context, seenProcs, /*emitError=*/false);
}

bool FunctionResult::IsAssumedLengthCharacter() const {
Expand Down Expand Up @@ -1360,27 +1369,26 @@ bool Procedure::CanOverride(
}

std::optional<Procedure> Procedure::Characterize(
const semantics::Symbol &original, FoldingContext &context) {
const semantics::Symbol &symbol, FoldingContext &context) {
semantics::UnorderedSymbolSet seenProcs;
return CharacterizeProcedure(original, context, seenProcs);
return CharacterizeProcedure(symbol, context, seenProcs, /*emitError=*/true);
}

std::optional<Procedure> Procedure::Characterize(
const ProcedureDesignator &proc, FoldingContext &context) {
const ProcedureDesignator &proc, FoldingContext &context, bool emitError) {
if (const auto *symbol{proc.GetSymbol()}) {
if (auto result{
characteristics::Procedure::Characterize(*symbol, context)}) {
return result;
}
semantics::UnorderedSymbolSet seenProcs;
return CharacterizeProcedure(*symbol, context, seenProcs, emitError);
} else if (const auto *intrinsic{proc.GetSpecificIntrinsic()}) {
return intrinsic->characteristics.value();
} else {
return std::nullopt;
}
return std::nullopt;
}

std::optional<Procedure> Procedure::Characterize(
const ProcedureRef &ref, FoldingContext &context) {
if (auto callee{Characterize(ref.proc(), context)}) {
if (auto callee{Characterize(ref.proc(), context, /*emitError=*/true)}) {
if (callee->functionResult) {
if (const Procedure *
proc{callee->functionResult->IsProcedurePointer()}) {
Expand All @@ -1397,7 +1405,7 @@ std::optional<Procedure> Procedure::Characterize(
return Characterize(*procRef, context);
} else if (const auto *procDesignator{
std::get_if<ProcedureDesignator>(&expr.u)}) {
return Characterize(*procDesignator, context);
return Characterize(*procDesignator, context, /*emitError=*/true);
} else if (const Symbol * symbol{UnwrapWholeSymbolOrComponentDataRef(expr)}) {
return Characterize(*symbol, context);
} else {
Expand All @@ -1409,7 +1417,7 @@ std::optional<Procedure> Procedure::Characterize(

std::optional<Procedure> Procedure::FromActuals(const ProcedureDesignator &proc,
const ActualArguments &args, FoldingContext &context) {
auto callee{Characterize(proc, context)};
auto callee{Characterize(proc, context, /*emitError=*/true)};
if (callee) {
if (callee->dummyArguments.empty() &&
callee->attrs.test(Procedure::Attr::ImplicitInterface)) {
Expand Down
12 changes: 6 additions & 6 deletions flang/lib/Evaluate/check-expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,8 +666,8 @@ class CheckSpecificationExprHelper
"' not allowed for derived type components or type parameter"
" values";
}
if (auto procChars{
characteristics::Procedure::Characterize(x.proc(), context_)}) {
if (auto procChars{characteristics::Procedure::Characterize(
x.proc(), context_, /*emitError=*/true)}) {
const auto iter{std::find_if(procChars->dummyArguments.begin(),
procChars->dummyArguments.end(),
[](const characteristics::DummyArgument &dummy) {
Expand Down Expand Up @@ -856,8 +856,8 @@ class IsContiguousHelper
Result operator()(const Substring &) const { return std::nullopt; }

Result operator()(const ProcedureRef &x) const {
if (auto chars{
characteristics::Procedure::Characterize(x.proc(), context_)}) {
if (auto chars{characteristics::Procedure::Characterize(
x.proc(), context_, /*emitError=*/true)}) {
if (chars->functionResult) {
const auto &result{*chars->functionResult};
if (!result.IsProcedurePointer()) {
Expand Down Expand Up @@ -1103,8 +1103,8 @@ class StmtFunctionChecker
}
}
}
if (auto chars{
characteristics::Procedure::Characterize(proc, context_)}) {
if (auto chars{characteristics::Procedure::Characterize(
proc, context_, /*emitError=*/true)}) {
if (!chars->CanBeCalledViaImplicitInterface()) {
if (severity_) {
auto msg{
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Evaluate/complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,6 @@ template class Complex<Real<Integer<16>, 11>>;
template class Complex<Real<Integer<16>, 8>>;
template class Complex<Real<Integer<32>, 24>>;
template class Complex<Real<Integer<64>, 53>>;
template class Complex<Real<Integer<80>, 64>>;
template class Complex<Real<X87IntegerContainer, 64>>;
template class Complex<Real<Integer<128>, 113>>;
} // namespace Fortran::evaluate::value
3 changes: 2 additions & 1 deletion flang/lib/Evaluate/fold-implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,12 @@ std::optional<Constant<T>> Folder<T>::ApplySubscripts(const Constant<T> &array,
ConstantSubscripts resultShape;
ConstantSubscripts ssLB;
for (const auto &ss : subscripts) {
CHECK(ss.Rank() <= 1);
if (ss.Rank() == 1) {
resultShape.push_back(static_cast<ConstantSubscript>(ss.size()));
elements *= ss.size();
ssLB.push_back(ss.lbounds().front());
} else if (ss.Rank() > 1) {
return std::nullopt; // error recovery
}
}
ConstantSubscripts ssAt(rank, 0), at(rank, 0), tmp(1, 0);
Expand Down
Loading