59 changes: 59 additions & 0 deletions clang/test/CodeGen/aarch64-elf-pauthabi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
// RUN: -fptrauth-intrinsics \
// RUN: -fptrauth-calls \
// RUN: -fptrauth-returns \
// RUN: -fptrauth-auth-traps \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-init-fini %s | \
// RUN: FileCheck %s --check-prefix=ALL

// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
// RUN: -fptrauth-intrinsics %s | FileCheck %s --check-prefix=INTRIN

// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
// RUN: -fptrauth-calls %s | FileCheck %s --check-prefix=CALL

// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
// RUN: -fptrauth-returns %s | FileCheck %s --check-prefix=RET

// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
// RUN: -fptrauth-auth-traps %s | FileCheck %s --check-prefix=TRAP

// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
// RUN: -fptrauth-calls -fptrauth-vtable-pointer-address-discrimination %s | \
// RUN: FileCheck %s --check-prefix=VPTRADDR

// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
// RUN: -fptrauth-calls -fptrauth-vtable-pointer-type-discrimination %s | \
// RUN: FileCheck %s --check-prefix=VPTRTYPE

// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
// RUN: -fptrauth-calls -fptrauth-init-fini %s | \
// RUN: FileCheck %s --check-prefix=INITFINI

// ALL: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// ALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 127}

// INTRIN: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// INTRIN: !{i32 1, !"aarch64-elf-pauthabi-version", i32 1}

// CALL: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// CALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 2}

// RET: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// RET: !{i32 1, !"aarch64-elf-pauthabi-version", i32 4}

// TRAP: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// TRAP: !{i32 1, !"aarch64-elf-pauthabi-version", i32 8}

// VPTRADDR: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// VPTRADDR: !{i32 1, !"aarch64-elf-pauthabi-version", i32 18}

// VPTRTYPE: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// VPTRTYPE: !{i32 1, !"aarch64-elf-pauthabi-version", i32 34}

// INITFINI: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// INITFINI: !{i32 1, !"aarch64-elf-pauthabi-version", i32 66}

void foo() {}
240 changes: 240 additions & 0 deletions clang/test/CodeGen/aarch64-fmv-dependencies.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
// Test/document all of the dependencies between possible AArch64 FMV extensions.
// Also test the name mangling.

// RUN: %clang --target=aarch64-linux-gnu --rtlib=compiler-rt -emit-llvm -S -o - %s | FileCheck %s

// CHECK: define dso_local i32 @fmv._Maes() #[[ATTR0:[0-9]+]] {
__attribute__((target_version("aes"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mbf16() #[[bf16_ebf16:[0-9]+]] {
__attribute__((target_version("bf16"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mbti() #[[bti:[0-9]+]] {
__attribute__((target_version("bti"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mcrc() #[[crc:[0-9]+]] {
__attribute__((target_version("crc"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mdgh() #[[ATTR0:[0-9]+]] {
__attribute__((target_version("dgh"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mdit() #[[dit:[0-9]+]] {
__attribute__((target_version("dit"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mdotprod() #[[dotprod:[0-9]+]] {
__attribute__((target_version("dotprod"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mdpb() #[[dpb:[0-9]+]] {
__attribute__((target_version("dpb"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mdpb2() #[[dpb2:[0-9]+]] {
__attribute__((target_version("dpb2"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mebf16() #[[bf16_ebf16:[0-9]+]] {
__attribute__((target_version("ebf16"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mf32mm() #[[f32mm:[0-9]+]] {
__attribute__((target_version("f32mm"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mf64mm() #[[f64mm:[0-9]+]] {
__attribute__((target_version("f64mm"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mfcma() #[[fcma:[0-9]+]] {
__attribute__((target_version("fcma"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mflagm() #[[flagm:[0-9]+]] {
__attribute__((target_version("flagm"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mflagm2() #[[flagm2:[0-9]+]] {
__attribute__((target_version("flagm2"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mfp() #[[ATTR0:[0-9]+]] {
__attribute__((target_version("fp"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mfp16() #[[fp16:[0-9]+]] {
__attribute__((target_version("fp16"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mfp16fml() #[[fp16fml:[0-9]+]] {
__attribute__((target_version("fp16fml"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mfrintts() #[[frintts:[0-9]+]] {
__attribute__((target_version("frintts"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mi8mm() #[[i8mm:[0-9]+]] {
__attribute__((target_version("i8mm"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mjscvt() #[[jscvt:[0-9]+]] {
__attribute__((target_version("jscvt"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mls64() #[[ATTR0:[0-9]+]] {
__attribute__((target_version("ls64"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mls64_accdata() #[[ls64_accdata:[0-9]+]] {
__attribute__((target_version("ls64_accdata"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mls64_v() #[[ATTR0:[0-9]+]] {
__attribute__((target_version("ls64_v"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mlse() #[[lse:[0-9]+]] {
__attribute__((target_version("lse"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mmemtag() #[[ATTR0:[0-9]+]] {
__attribute__((target_version("memtag"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mmemtag2() #[[memtag2:[0-9]+]] {
__attribute__((target_version("memtag2"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mmemtag3() #[[memtag2:[0-9]+]] {
__attribute__((target_version("memtag3"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mmops() #[[mops:[0-9]+]] {
__attribute__((target_version("mops"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mpmull() #[[pmull:[0-9]+]] {
__attribute__((target_version("pmull"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mpredres() #[[predres:[0-9]+]] {
__attribute__((target_version("predres"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mrcpc() #[[rcpc:[0-9]+]] {
__attribute__((target_version("rcpc"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mrcpc2() #[[rcpc:[0-9]+]] {
__attribute__((target_version("rcpc2"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mrcpc3() #[[rcpc3:[0-9]+]] {
__attribute__((target_version("rcpc3"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mrdm() #[[rdm:[0-9]+]] {
__attribute__((target_version("rdm"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mrng() #[[rng:[0-9]+]] {
__attribute__((target_version("rng"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mrpres() #[[ATTR0:[0-9]+]] {
__attribute__((target_version("rpres"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msb() #[[sb:[0-9]+]] {
__attribute__((target_version("sb"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msha1() #[[ATTR0:[0-9]+]] {
__attribute__((target_version("sha1"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msha2() #[[sha2:[0-9]+]] {
__attribute__((target_version("sha2"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msha3() #[[sha3:[0-9]+]] {
__attribute__((target_version("sha3"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msimd() #[[ATTR0:[0-9]+]] {
__attribute__((target_version("simd"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msm4() #[[sm4:[0-9]+]] {
__attribute__((target_version("sm4"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msme() #[[sme:[0-9]+]] {
__attribute__((target_version("sme"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msme-f64f64() #[[sme_f64f64:[0-9]+]] {
__attribute__((target_version("sme-f64f64"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msme-i16i64() #[[sme_i16i64:[0-9]+]] {
__attribute__((target_version("sme-i16i64"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msme2() #[[sme2:[0-9]+]] {
__attribute__((target_version("sme2"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mssbs() #[[ATTR0:[0-9]+]] {
__attribute__((target_version("ssbs"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mssbs2() #[[ssbs2:[0-9]+]] {
__attribute__((target_version("ssbs2"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msve() #[[sve:[0-9]+]] {
__attribute__((target_version("sve"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msve-bf16() #[[sve_bf16_ebf16:[0-9]+]] {
__attribute__((target_version("sve-bf16"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msve-ebf16() #[[sve_bf16_ebf16:[0-9]+]] {
__attribute__((target_version("sve-ebf16"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msve-i8mm() #[[sve_i8mm:[0-9]+]] {
__attribute__((target_version("sve-i8mm"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msve2() #[[sve2:[0-9]+]] {
__attribute__((target_version("sve2"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msve2-aes() #[[sve2_aes_sve2_pmull128:[0-9]+]] {
__attribute__((target_version("sve2-aes"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msve2-bitperm() #[[sve2_bitperm:[0-9]+]] {
__attribute__((target_version("sve2-bitperm"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msve2-pmull128() #[[sve2_aes_sve2_pmull128:[0-9]+]] {
__attribute__((target_version("sve2-pmull128"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msve2-sha3() #[[sve2_sha3:[0-9]+]] {
__attribute__((target_version("sve2-sha3"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Msve2-sm4() #[[sve2_sm4:[0-9]+]] {
__attribute__((target_version("sve2-sm4"))) int fmv(void) { return 0; }

// CHECK: define dso_local i32 @fmv._Mwfxt() #[[wfxt:[0-9]+]] {
__attribute__((target_version("wfxt"))) int fmv(void) { return 0; }

// CHECK-NOT: define dso_local i32 @fmv._M{{.*}}
__attribute__((target_version("non_existent_extension"))) int fmv(void);

__attribute__((target_version("default"))) int fmv(void);

int caller() {
return fmv();
}

// CHECK: attributes #[[ATTR0:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[bf16_ebf16:[0-9]+]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[bti:[0-9]+]] = { {{.*}} "target-features"="+bti,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[crc:[0-9]+]] = { {{.*}} "target-features"="+crc,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[dit:[0-9]+]] = { {{.*}} "target-features"="+dit,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[dotprod:[0-9]+]] = { {{.*}} "target-features"="+dotprod,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[dpb:[0-9]+]] = { {{.*}} "target-features"="+ccpp,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[dpb2:[0-9]+]] = { {{.*}} "target-features"="+ccdp,+ccpp,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[f32mm:[0-9]+]] = { {{.*}} "target-features"="+f32mm,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+v8a"
// CHECK: attributes #[[f64mm:[0-9]+]] = { {{.*}} "target-features"="+f64mm,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+v8a"
// CHECK: attributes #[[fcma:[0-9]+]] = { {{.*}} "target-features"="+complxnum,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[flagm:[0-9]+]] = { {{.*}} "target-features"="+flagm,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[flagm2:[0-9]+]] = { {{.*}} "target-features"="+altnzcv,+flagm,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[fp16:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[fp16fml:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+fp16fml,+fullfp16,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[frintts:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+fptoint,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[i8mm:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+i8mm,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[jscvt:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+jsconv,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[ls64_accdata:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+ls64,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[lse:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+lse,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[memtag2:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+mte,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[mops:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+mops,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[pmull:[0-9]+]] = { {{.*}} "target-features"="+aes,+fp-armv8,+neon,+outline-atomics,+v8a"
// CHECK: attributes #[[predres:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+predres,+v8a"
// CHECK: attributes #[[rcpc:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+rcpc,+v8a"
// CHECK: attributes #[[rcpc3:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+rcpc,+rcpc3,+v8a"
// CHECK: attributes #[[rdm:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+rdm,+v8a"
// CHECK: attributes #[[rng:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+rand,+v8a"
// CHECK: attributes #[[sb:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+sb,+v8a"
// CHECK: attributes #[[sha2:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+sha2,+v8a"
// CHECK: attributes #[[sha3:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+sha2,+sha3,+v8a"
// CHECK: attributes #[[sm4:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+sm4,+v8a"
// CHECK: attributes #[[sme:[0-9]+]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+neon,+outline-atomics,+sme,+v8a"
// CHECK: attributes #[[sme_f64f64:[0-9]+]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+neon,+outline-atomics,+sme,+sme-f64f64,+v8a"
// CHECK: attributes #[[sme_i16i64:[0-9]+]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+neon,+outline-atomics,+sme,+sme-i16i64,+v8a"
// CHECK: attributes #[[sme2:[0-9]+]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+neon,+outline-atomics,+sme,+sme2,+v8a"
// CHECK: attributes #[[ssbs2:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+ssbs,+v8a"
// CHECK: attributes #[[sve:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+v8a"
// CHECK: attributes #[[sve_bf16_ebf16:[0-9]+]] = { {{.*}} "target-features"="+bf16,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+v8a"
// CHECK: attributes #[[sve_i8mm:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+i8mm,+neon,+outline-atomics,+sve,+v8a"
// CHECK: attributes #[[sve2:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+sve2,+v8a"
// CHECK: attributes #[[sve2_aes_sve2_pmull128:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+sve2,+sve2-aes,+v8a"
// CHECK: attributes #[[sve2_bitperm:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+sve2,+sve2-bitperm,+v8a"
// CHECK: attributes #[[sve2_sha3:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+sve2,+sve2-sha3,+v8a"
// CHECK: attributes #[[sve2_sm4:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+sve2,+sve2-sm4,+v8a"
// CHECK: attributes #[[wfxt:[0-9]+]] = { {{.*}} "target-features"="+fp-armv8,+neon,+outline-atomics,+v8a,+wfxt"
6 changes: 6 additions & 0 deletions clang/test/CodeGen/builtins-wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,12 @@ float load_f16_f32(__fp16 *addr) {
// WEBASSEMBLY: call float @llvm.wasm.loadf16.f32(ptr %{{.*}})
}

void store_f16_f32(float val, __fp16 *addr) {
return __builtin_wasm_storef16_f32(val, addr);
// WEBASSEMBLY: tail call void @llvm.wasm.storef16.f32(float %val, ptr %{{.*}})
// WEBASSEMBLY-NEXT: ret
}

__externref_t externref_null() {
return __builtin_wasm_ref_null_extern();
// WEBASSEMBLY: tail call ptr addrspace(10) @llvm.wasm.ref.null.extern()
Expand Down
27 changes: 27 additions & 0 deletions clang/test/Driver/aarch64-fmv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Test which driver flags enable/disable Function Multiversioning on aarch64.

// FMV is enabled for non-android aarch64 targets:
// RUN: %clang --target=aarch64 --rtlib=compiler-rt -### -c %s 2>&1 | FileCheck -check-prefix=FMV-ENABLED %s
// RUN: %clang --target=aarch64-linux-gnu --rtlib=compiler-rt -### -c %s 2>&1 | FileCheck -check-prefix=FMV-ENABLED %s
// RUN: %clang --target=arm64-apple-ios --rtlib=compiler-rt -### -c %s 2>&1 | FileCheck -check-prefix=FMV-ENABLED %s
// RUN: %clang --target=arm64-apple-macosx --rtlib=compiler-rt -### -c %s 2>&1 | FileCheck -check-prefix=FMV-ENABLED %s

// android23 defaults to --rtlib=compiler-rt:
// RUN: %clang --target=aarch64-linux-android23 -### -c %s 2>&1 | FileCheck -check-prefix=FMV-ENABLED %s
// RUN: %clang --target=aarch64-linux-android23 --rtlib=compiler-rt -### -c %s 2>&1 | FileCheck -check-prefix=FMV-ENABLED %s

// FMV is disabled without compiler-rt:
// RUN: %clang --target=aarch64 -### -c %s 2>&1 | FileCheck -check-prefix=FMV-DISABLED %s
// RUN: %clang --target=aarch64-linux-gnu -### -c %s 2>&1 | FileCheck -check-prefix=FMV-DISABLED %s

// Disabled for older android versions:
// RUN: %clang --rtlib=compiler-rt --target=aarch64-linux-android -### -c %s 2>&1 | FileCheck -check-prefix=FMV-DISABLED %s
// RUN: %clang --rtlib=compiler-rt --target=aarch64-linux-android22 -### -c %s 2>&1 | FileCheck -check-prefix=FMV-DISABLED %s
// RUN: %clang --rtlib=compiler-rt --target=aarch64-linux-android22 -mno-fmv -### -c %s 2>&1 | FileCheck -check-prefix=FMV-DISABLED %s

// Disabled explicitly:
// RUN: %clang --rtlib=compiler-rt --target=aarch64 -mno-fmv -### -c %s 2>&1 | FileCheck -check-prefix=FMV-DISABLED %s
// RUN: %clang --rtlib=compiler-rt --target=aarch64-linux-android23 -mno-fmv -### -c %s 2>&1 | FileCheck -check-prefix=FMV-DISABLED %s

// FMV-ENABLED-NOT: "-target-feature" "-fmv"
// FMV-DISABLED: "-target-feature" "-fmv"
12 changes: 6 additions & 6 deletions clang/test/Driver/aarch64-implied-sme-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// SME-CONFLICT: "-target-feature" "-bf16"{{.*}} "-target-feature" "-sme"

// RUN: %clang -target aarch64-linux-gnu -march=armv8-a+sme-i16i64 %s -### 2>&1 | FileCheck %s --check-prefix=SME-I16I64
// SME-I16I64: "-target-feature" "+bf16"{{.*}} "-target-feature" "+sme-i16i64" "-target-feature" "+sme"
// SME-I16I64: "-target-feature" "+bf16"{{.*}} "-target-feature" "+sme" "-target-feature" "+sme-i16i64"

// RUN: %clang -target aarch64-linux-gnu -march=armv8-a+nosme-i16i64 %s -### 2>&1 | FileCheck %s --check-prefix=NOSME-I16I64
// NOSME-I16I64-NOT: "-target-feature" "+sme-i16i64"
Expand All @@ -23,7 +23,7 @@
// NOSME-I16I64-NOT: sme-i16i64"

// RUN: %clang -target aarch64-linux-gnu -march=armv8-a+sme-i16i64+nosme-i16i64 %s -### 2>&1 | FileCheck %s --check-prefix=SME-I16I64-REVERT
// SME-I16I64-REVERT: "-target-feature" "+bf16"{{.*}} "-target-feature" "-sme-i16i64" "-target-feature" "+sme"
// SME-I16I64-REVERT: "-target-feature" "+bf16"{{.*}} "-target-feature" "+sme" "-target-feature" "-sme-i16i64"

// RUN: %clang -target aarch64-linux-gnu -march=armv8-a+nosme-f64f64 %s -### 2>&1 | FileCheck %s --check-prefix=NOSME-F64F64
// NOSME-F64F64-NOT: "-target-feature" "+sme-f64f64"
Expand All @@ -32,20 +32,20 @@
// NOSME-F64F64-NOT: sme-f64f64"

// RUN: %clang -target aarch64-linux-gnu -march=armv8-a+sme-f64f64+nosme-f64f64 %s -### 2>&1 | FileCheck %s --check-prefix=SME-F64F64-REVERT
// SME-F64F64-REVERT: "-target-feature" "+bf16"{{.*}} "-target-feature" "-sme-f64f64" "-target-feature" "+sme"
// SME-F64F64-REVERT: "-target-feature" "+bf16"{{.*}} "-target-feature" "+sme" "-target-feature" "-sme-f64f64"

// RUN: %clang -target aarch64-linux-gnu -march=armv8-a+sme-f64f64+nosme-i16i64 %s -### 2>&1 | FileCheck %s --check-prefix=SME-SUBFEATURE-MIX
// SME-SUBFEATURE-MIX-NOT: "+sme-i16i64"
// SME-SUBFEATURE-MIX: "-target-feature" "+bf16"{{.*}} "-target-feature" "+sme-f64f64" "-target-feature" "+sme"
// SME-SUBFEATURE-MIX: "-target-feature" "+bf16"{{.*}} "-target-feature" "+sme" "-target-feature" "+sme-f64f64"
// SME-SUBFEATURE-MIX-NOT: "+sme-i16i64"

// RUN: %clang -target aarch64-linux-gnu -march=armv8-a+sme-i16i64+nosme %s -### 2>&1 | FileCheck %s --check-prefix=SME-SUBFEATURE-CONFLICT1
// SME-SUBFEATURE-CONFLICT1: "-target-feature" "+bf16"{{.*}} "-target-feature" "-sme-i16i64" "-target-feature" "-sme"
// SME-SUBFEATURE-CONFLICT1: "-target-feature" "+bf16"{{.*}} "-target-feature" "-sme" "-target-feature" "-sme-i16i64"

// RUN: %clang -target aarch64-linux-gnu -march=armv8-a+sme-f64f64+nobf16 %s -### 2>&1 | FileCheck %s --check-prefix=SME-SUBFEATURE-CONFLICT2
// SME-SUBFEATURE-CONFLICT2-NOT: "-target-feature" "+bf16"
// SME-SUBFEATURE-CONFLICT2-NOT: "-target-feature" "+sme"
// SME-SUBFEATURE-CONFLICT2-NOT: "-target-feature" "+sme-f64f64"

// RUN: %clang -target aarch64-linux-gnu -march=armv8-a+nosme+sme-i16i64 %s -### 2>&1 | FileCheck %s --check-prefix=SME-SUBFEATURE-CONFLICT-REV
// SME-SUBFEATURE-CONFLICT-REV: "-target-feature" "+bf16"{{.*}} "-target-feature" "+sme-i16i64" "-target-feature" "+sme"
// SME-SUBFEATURE-CONFLICT-REV: "-target-feature" "+bf16"{{.*}} "-target-feature" "+sme" "-target-feature" "+sme-i16i64"
22 changes: 11 additions & 11 deletions clang/test/Driver/aarch64-implied-sve-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
// SVE-SVE2: "-target-feature" "+sve" "-target-feature" "+sve2"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-bitperm %s -### 2>&1 | FileCheck %s --check-prefix=SVE2-BITPERM
// SVE2-BITPERM: "-target-feature" "+sve" "-target-feature" "+sve2-bitperm" "-target-feature" "+sve2"
// SVE2-BITPERM: "-target-feature" "+sve" "-target-feature" "+sve2" "-target-feature" "+sve2-bitperm"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+nosve2-bitperm %s -### 2>&1 | FileCheck %s --check-prefix=NOSVE2-BITPERM
// NOSVE2-BITPERM-NOT: "-target-feature" "+sve2-bitperm"
Expand All @@ -33,40 +33,40 @@
// NOSVE2-BITPERM-NOT: sve2-bitperm"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-bitperm+nosve2-bitperm %s -### 2>&1 | FileCheck %s --check-prefix=SVE2-BITPERM-REVERT
// SVE2-BITPERM-REVERT: "-target-feature" "+sve" "-target-feature" "-sve2-bitperm" "-target-feature" "+sve2"
// SVE2-BITPERM-REVERT: "-target-feature" "+sve" "-target-feature" "+sve2" "-target-feature" "-sve2-bitperm"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-aes+nosve2-aes %s -### 2>&1 | FileCheck %s --check-prefix=SVE2-AES-REVERT
// SVE2-AES-REVERT: "-target-feature" "+sve" "-target-feature" "-sve2-aes" "-target-feature" "+sve2"
// SVE2-AES-REVERT: "-target-feature" "+sve" "-target-feature" "+sve2" "-target-feature" "-sve2-aes"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-sha3+nosve2-sha3 %s -### 2>&1 | FileCheck %s --check-prefix=SVE2-SHA3-REVERT
// SVE2-SHA3-REVERT: "-target-feature" "+sve" "-target-feature" "-sve2-sha3" "-target-feature" "+sve2"
// SVE2-SHA3-REVERT: "-target-feature" "+sve" "-target-feature" "+sve2" "-target-feature" "-sve2-sha3"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-sm4+nosve2-sm4 %s -### 2>&1 | FileCheck %s --check-prefix=SVE2-SM4-REVERT
// SVE2-SM4-REVERT: "-target-feature" "+sve" "-target-feature" "-sve2-sm4" "-target-feature" "+sve2"
// SVE2-SM4-REVERT: "-target-feature" "+sve" "-target-feature" "+sve2" "-target-feature" "-sve2-sm4"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-sha3 %s -### 2>&1 | FileCheck %s --check-prefix=SVE2-SHA3
// SVE2-SHA3: "-target-feature" "+sve" "-target-feature" "+sve2-sha3" "-target-feature" "+sve2"
// SVE2-SHA3: "-target-feature" "+sve" "-target-feature" "+sve2" "-target-feature" "+sve2-sha3"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-aes %s -### 2>&1 | FileCheck %s --check-prefix=SVE2-AES
// SVE2-AES: "-target-feature" "+sve" "-target-feature" "+sve2-aes" "-target-feature" "+sve2"
// SVE2-AES: "-target-feature" "+sve" "-target-feature" "+sve2" "-target-feature" "+sve2-aes"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-sm4 %s -### 2>&1 | FileCheck %s --check-prefix=SVE2-SM4
// SVE2-SM4: "-target-feature" "+sve" "-target-feature" "+sve2-sm4" "-target-feature" "+sve2"
// SVE2-SM4: "-target-feature" "+sve" "-target-feature" "+sve2" "-target-feature" "+sve2-sm4"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-bitperm+nosve2-aes %s -### 2>&1 | FileCheck %s --check-prefix=SVE2-SUBFEATURE-MIX
// SVE2-SUBFEATURE-MIX: "-target-feature" "+sve" "-target-feature" "+sve2-bitperm" "-target-feature" "+sve2"
// SVE2-SUBFEATURE-MIX: "-target-feature" "+sve" "-target-feature" "+sve2" "-target-feature" "+sve2-bitperm"
// SVE2-SUBFEATURE-NOT: sve2-aes

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-sm4+nosve2 %s -### 2>&1 | FileCheck %s --check-prefix=SVE2-SUBFEATURE-CONFLICT
// SVE2-SUBFEATURE-CONFLICT: "-target-feature" "+sve" "-target-feature" "-sve2-sm4" "-target-feature" "-sve2"
// SVE2-SUBFEATURE-CONFLICT: "-target-feature" "+sve" "-target-feature" "-sve2" "-target-feature" "-sve2-sm4"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-aes+nosve %s -### 2>&1 | FileCheck %s --check-prefix=SVE-SUBFEATURE-CONFLICT
// SVE-SUBFEATURE-CONFLICT-NOT: "-target-feature" "+sve2-aes"
// SVE-SUBFEATURE-CONFLICT-NOT: "-target-feature" "+sve2"
// SVE-SUBFEATURE-CONFLICT-NOT: "-target-feature" "+sve"

// RUN: %clang --target=aarch64-linux-gnu -march=armv8-a+nosve+sve2-aes %s -### 2>&1 | FileCheck %s --check-prefix=SVE-SUBFEATURE-CONFLICT-REV
// SVE-SUBFEATURE-CONFLICT-REV: "-target-feature" "+sve" "-target-feature" "+sve2-aes" "-target-feature" "+sve2"
// SVE-SUBFEATURE-CONFLICT-REV: "-target-feature" "+sve" "-target-feature" "+sve2" "-target-feature" "+sve2-aes"

// RUN: %clang --target=aarch64-linux-gnu -mcpu=neoverse-n2+nosve2 %s -### 2>&1 | FileCheck %s --check-prefix=SVE-MCPU-FEATURES
// SVE-MCPU-FEATURES-NOT: "-target-feature" "+sve2-bitperm"
Expand Down
28 changes: 24 additions & 4 deletions clang/test/Driver/aarch64-ptrauth.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
// RUN: %clang -### -c --target=aarch64 -fno-ptrauth-intrinsics -fptrauth-intrinsics %s 2>&1 | FileCheck %s --check-prefix=INTRIN
// INTRIN: "-cc1"{{.*}} "-fptrauth-intrinsics"
// RUN: %clang -### -c --target=aarch64 %s 2>&1 | FileCheck %s --check-prefix NONE
// NONE: "-cc1"
// NONE-NOT: "-fptrauth-

// RUN: not %clang -### -c --target=x86_64 -fptrauth-intrinsics %s 2>&1 | FileCheck %s --check-prefix=ERR
// ERR: error: unsupported option '-fptrauth-intrinsics' for target '{{.*}}'
// RUN: %clang -### -c --target=aarch64 \
// RUN: -fno-ptrauth-intrinsics -fptrauth-intrinsics \
// RUN: -fno-ptrauth-calls -fptrauth-calls \
// RUN: -fno-ptrauth-returns -fptrauth-returns \
// RUN: -fno-ptrauth-auth-traps -fptrauth-auth-traps \
// RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fno-ptrauth-vtable-pointer-type-discrimination -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fno-ptrauth-init-fini -fptrauth-init-fini \
// RUN: %s 2>&1 | FileCheck %s --check-prefix=ALL
// ALL: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-init-fini"

// RUN: not %clang -### -c --target=x86_64 -fptrauth-intrinsics -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps \
// RUN: -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-init-fini %s 2>&1 | FileCheck %s --check-prefix=ERR
// ERR: error: unsupported option '-fptrauth-intrinsics' for target '{{.*}}'
// ERR-NEXT: error: unsupported option '-fptrauth-calls' for target '{{.*}}'
// ERR-NEXT: error: unsupported option '-fptrauth-returns' for target '{{.*}}'
// ERR-NEXT: error: unsupported option '-fptrauth-auth-traps' for target '{{.*}}'
// ERR-NEXT: error: unsupported option '-fptrauth-vtable-pointer-address-discrimination' for target '{{.*}}'
// ERR-NEXT: error: unsupported option '-fptrauth-vtable-pointer-type-discrimination' for target '{{.*}}'
// ERR-NEXT: error: unsupported option '-fptrauth-init-fini' for target '{{.*}}'
11 changes: 11 additions & 0 deletions clang/test/Driver/clang-offload-bundler.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,17 @@
// RUN: -output=%t.res.tgt1 -input=%t.hip.bundle.bc -unbundle 2>&1 | FileCheck %s -check-prefix=NOGFX906
// NOGFX906: error: Can't find bundles for hip-amdgcn-amd-amdhsa--gfx906

//
// Check hip and hipv4 are compatible as offload kind.
//
// RUN: clang-offload-bundler -type=o -targets=hip-amdgcn-amd-amdhsa--gfx90a -input=%t.tgt1 -output=%t.bundle3.o
// RUN: clang-offload-bundler -type=o -targets=hipv4-amdgcn-amd-amdhsa--gfx90a:sramecc-:xnack+ -output=%t.res.tgt1 -input=%t.bundle3.o -unbundle
// RUN: diff %t.tgt1 %t.res.tgt1

// RUN: clang-offload-bundler -type=o -targets=hipv4-amdgcn-amd-amdhsa--gfx90a -input=%t.tgt1 -output=%t.bundle3.o
// RUN: clang-offload-bundler -type=o -targets=hip-amdgcn-amd-amdhsa--gfx90a:sramecc-:xnack+ -output=%t.res.tgt1 -input=%t.bundle3.o -unbundle
// RUN: diff %t.tgt1 %t.res.tgt1

//
// Check archive unbundling
//
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Driver/linker-wrapper-image.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@

// OPENMP: define internal void @.omp_offloading.descriptor_reg() section ".text.startup" {
// OPENMP-NEXT: entry:
// OPENMP-NEXT: %0 = call i32 @atexit(ptr @.omp_offloading.descriptor_unreg)
// OPENMP-NEXT: call void @__tgt_register_lib(ptr @.omp_offloading.descriptor)
// OPENMP-NEXT: %0 = call i32 @atexit(ptr @.omp_offloading.descriptor_unreg)
// OPENMP-NEXT: ret void
// OPENMP-NEXT: }

Expand Down
4 changes: 2 additions & 2 deletions clang/test/Driver/linker-wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ __attribute__((visibility("protected"), used)) int x;

// HIP: clang{{.*}} -o [[IMG_GFX908:.+]] --target=amdgcn-amd-amdhsa -mcpu=gfx908
// HIP: clang{{.*}} -o [[IMG_GFX90A:.+]] --target=amdgcn-amd-amdhsa -mcpu=gfx90a
// HIP: clang-offload-bundler{{.*}}-type=o -bundle-align=4096 -compress -compression-level=6 -targets=host-x86_64-unknown-linux,hipv4-amdgcn-amd-amdhsa--gfx90a,hipv4-amdgcn-amd-amdhsa--gfx908 -input=/dev/null -input=[[IMG_GFX90A]] -input=[[IMG_GFX908]] -output={{.*}}.hipfb
// HIP: clang-offload-bundler{{.*}}-type=o -bundle-align=4096 -compress -compression-level=6 -targets=host-x86_64-unknown-linux,hip-amdgcn-amd-amdhsa--gfx90a,hip-amdgcn-amd-amdhsa--gfx908 -input=/dev/null -input=[[IMG_GFX90A]] -input=[[IMG_GFX908]] -output={{.*}}.hipfb

// RUN: clang-offload-packager -o %t.out \
// RUN: --image=file=%t.elf.o,kind=openmp,triple=amdgcn-amd-amdhsa,arch=gfx908 \
Expand Down Expand Up @@ -210,7 +210,7 @@ __attribute__((visibility("protected"), used)) int x;
// RUN: %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=RELOCATABLE-LINK-HIP

// RELOCATABLE-LINK-HIP: clang{{.*}} -o {{.*}}.img --target=amdgcn-amd-amdhsa
// RELOCATABLE-LINK-HIP: clang-offload-bundler{{.*}} -type=o -bundle-align=4096 -targets=host-x86_64-unknown-linux,hipv4-amdgcn-amd-amdhsa--gfx90a -input=/dev/null -input={{.*}} -output={{.*}}
// RELOCATABLE-LINK-HIP: clang-offload-bundler{{.*}} -type=o -bundle-align=4096 -targets=host-x86_64-unknown-linux,hip-amdgcn-amd-amdhsa--gfx90a -input=/dev/null -input={{.*}} -output={{.*}}
// RELOCATABLE-LINK-HIP: /usr/bin/ld.lld{{.*}}-r
// RELOCATABLE-LINK-HIP: llvm-objcopy{{.*}}a.out --remove-section .llvm.offloading

Expand Down
4 changes: 2 additions & 2 deletions clang/test/Driver/plugin-driver-args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@

// Plugins are only relevant for the -cc1 phase. No warning should be raised
// when only using the assembler. See GH #88173.
// RUN: %clang -c -fpass-plugin=bar.so -fplugin=bar.so -fplugin-arg-bar-option -Werror -x assembler %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PLUGIN-ASM
// CHECK-PLUGIN-ASM-NOT: argument unused during compilation
// RUN: %clang -c -fpass-plugin=bar.so -fplugin=bar.so -fplugin-arg-bar-option -Wunused-command-line-argument -x assembler %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PLUGIN-ASM
// CHECK-PLUGIN-ASM-NOT: argument unused during compilation: '-f{{[a-z-]*plugin[^']*}}'
48 changes: 16 additions & 32 deletions clang/test/ParserOpenACC/parse-wait-clause.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
void func() {
int i, j;

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

// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait clause-list
{}

Expand All @@ -17,12 +15,10 @@ void func() {
#pragma acc parallel wait (
{}

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

// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait () clause-list
{}

Expand Down Expand Up @@ -61,12 +57,10 @@ void func() {
#pragma acc parallel wait (queues:
{}

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

// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait (queues:) clause-list
{}

Expand All @@ -75,12 +69,10 @@ void func() {
#pragma acc parallel wait (devnum: i + j:queues:
{}

// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
#pragma acc parallel wait (devnum: i + j:queues:)
{}

// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait (devnum: i + j:queues:) clause-list
{}

Expand Down Expand Up @@ -108,13 +100,11 @@ void func() {
#pragma acc parallel wait(i, j, 1+1, 3.3
{}

// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
#pragma acc parallel wait(i, j, 1+1, 3.3)
{}
// expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait(i, j, 1+1, 3.3) clause-list
{}

Expand Down Expand Up @@ -146,14 +136,12 @@ void func() {
#pragma acc parallel wait(queues:i, j, 1+1, 3.3,
{}

// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
#pragma acc parallel wait(queues:i, j, 1+1, 3.3)
{}

// expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait(queues:i, j, 1+1, 3.3) clause-list
{}

Expand All @@ -162,13 +150,11 @@ void func() {
// expected-note@+1{{to match this '('}}
#pragma acc parallel wait(devnum:3:i, j, 1+1, 3.3
{}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
#pragma acc parallel wait(devnum:3:i, j, 1+1, 3.3)
{}
// expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait(devnum:3:i, j, 1+1, 3.3) clause-list
{}

Expand All @@ -177,13 +163,11 @@ void func() {
// expected-note@+1{{to match this '('}}
#pragma acc parallel wait(devnum:3:queues:i, j, 1+1, 3.3
{}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
#pragma acc parallel wait(devnum:3:queues:i, j, 1+1, 3.3)
{}
// expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+2{{invalid OpenACC clause 'clause'}}
// expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
// expected-error@+1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait(devnum:3:queues:i, j, 1+1, 3.3) clause-list
{}
}
107 changes: 105 additions & 2 deletions clang/test/Preprocessor/ptrauth_feature.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,59 @@
// RUN: %clang_cc1 %s -E -triple=arm64-- | FileCheck %s --check-prefixes=NOINTRIN
// RUN: %clang_cc1 %s -E -triple=arm64-- -fptrauth-intrinsics | FileCheck %s --check-prefixes=INTRIN
// RUN: %clang_cc1 -E %s -triple=aarch64 \
// RUN: -fptrauth-intrinsics \
// RUN: -fptrauth-calls \
// RUN: -fptrauth-returns \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-init-fini | \
// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI

// RUN: %clang_cc1 -E %s -triple=aarch64 \
// RUN: -fptrauth-calls \
// RUN: -fptrauth-returns \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-init-fini | \
// RUN: FileCheck %s --check-prefixes=NOINTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI

// RUN: %clang_cc1 -E %s -triple=aarch64 \
// RUN: -fptrauth-intrinsics \
// RUN: -fptrauth-returns \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-init-fini | \
// RUN: FileCheck %s --check-prefixes=INTRIN,NOCALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI

// RUN: %clang_cc1 -E %s -triple=aarch64 \
// RUN: -fptrauth-intrinsics \
// RUN: -fptrauth-calls \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-init-fini | \
// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,NORETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI

// RUN: %clang_cc1 -E %s -triple=aarch64 \
// RUN: -fptrauth-intrinsics \
// RUN: -fptrauth-calls \
// RUN: -fptrauth-returns \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-init-fini | \
// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,NOVPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI

// RUN: %clang_cc1 -E %s -triple=aarch64 \
// RUN: -fptrauth-intrinsics \
// RUN: -fptrauth-calls \
// RUN: -fptrauth-returns \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fptrauth-init-fini | \
// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,INITFINI

// RUN: %clang_cc1 -E %s -triple=aarch64 \
// RUN: -fptrauth-intrinsics \
// RUN: -fptrauth-calls \
// RUN: -fptrauth-returns \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fptrauth-vtable-pointer-type-discrimination | \
// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,NOINITFINI

#if __has_feature(ptrauth_intrinsics)
// INTRIN: has_ptrauth_intrinsics
Expand All @@ -8,3 +62,52 @@ void has_ptrauth_intrinsics() {}
// NOINTRIN: no_ptrauth_intrinsics
void no_ptrauth_intrinsics() {}
#endif

#if __has_feature(ptrauth_calls)
// CALLS: has_ptrauth_calls
void has_ptrauth_calls() {}
#else
// NOCALLS: no_ptrauth_calls
void no_ptrauth_calls() {}
#endif

// This is always enabled when ptrauth_calls is enabled
#if __has_feature(ptrauth_member_function_pointer_type_discrimination)
// CALLS: has_ptrauth_member_function_pointer_type_discrimination
void has_ptrauth_member_function_pointer_type_discrimination() {}
#else
// NOCALLS: no_ptrauth_member_function_pointer_type_discrimination
void no_ptrauth_member_function_pointer_type_discrimination() {}
#endif

#if __has_feature(ptrauth_returns)
// RETS: has_ptrauth_returns
void has_ptrauth_returns() {}
#else
// NORETS: no_ptrauth_returns
void no_ptrauth_returns() {}
#endif

#if __has_feature(ptrauth_vtable_pointer_address_discrimination)
// VPTR_ADDR_DISCR: has_ptrauth_vtable_pointer_address_discrimination
void has_ptrauth_vtable_pointer_address_discrimination() {}
#else
// NOVPTR_ADDR_DISCR: no_ptrauth_vtable_pointer_address_discrimination
void no_ptrauth_vtable_pointer_address_discrimination() {}
#endif

#if __has_feature(ptrauth_vtable_pointer_type_discrimination)
// VPTR_TYPE_DISCR: has_ptrauth_vtable_pointer_type_discrimination
void has_ptrauth_vtable_pointer_type_discrimination() {}
#else
// NOVPTR_TYPE_DISCR: no_ptrauth_vtable_pointer_type_discrimination
void no_ptrauth_vtable_pointer_type_discrimination() {}
#endif

#if __has_feature(ptrauth_init_fini)
// INITFINI: has_ptrauth_init_fini
void has_ptrauth_init_fini() {}
#else
// NOINITFINI: no_ptrauth_init_fini
void no_ptrauth_init_fini() {}
#endif
16 changes: 12 additions & 4 deletions clang/test/SemaCXX/cxx2a-consteval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,14 @@ void test() {
constexpr int (*f2)(void) = lstatic; // expected-error {{constexpr variable 'f2' must be initialized by a constant expression}} \
// expected-note {{pointer to a consteval declaration is not a constant expression}}

int (*f3)(void) = []() consteval { return 3; }; // expected-error {{cannot take address of consteval call operator of '(lambda at}} \
// expected-note {{declared here}}
}

consteval void consteval_test() {
constexpr auto l1 = []() consteval { return 3; };

int (*f1)(void) = l1; // ok
}
}

Expand Down Expand Up @@ -1098,11 +1106,11 @@ int bad = 10; // expected-note 6{{declared here}}
tester glob1(make_name("glob1"));
tester glob2(make_name("glob2"));
constexpr tester cglob(make_name("cglob"));
tester paddedglob(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \
tester paddedglob(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}

constexpr tester glob3 = { make_name("glob3") };
constexpr tester glob4 = { make_name(pad(bad)) }; // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \
constexpr tester glob4 = { make_name(pad(bad)) }; // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
// expected-error {{constexpr variable 'glob4' must be initialized by a constant expression}} \
// expected-note 2{{read of non-const variable 'bad' is not allowed in a constant expression}}

Expand All @@ -1114,12 +1122,12 @@ auto V1 = make_name(pad(bad)); // expected-error {{call to consteval function 'G
void foo() {
static tester loc1(make_name("loc1"));
static constexpr tester loc2(make_name("loc2"));
static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \
static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}
}

void bar() {
static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \
static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}
}
}
Expand Down
26 changes: 26 additions & 0 deletions clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,3 +394,29 @@ static_assert(none_of(
));

}

#if __cplusplus >= 202302L
namespace lvalue_to_rvalue_init_from_heap {

struct S {
int *value;
constexpr S(int v) : value(new int {v}) {} // expected-note 2 {{heap allocation performed here}}
constexpr ~S() { delete value; }
};
consteval S fn() { return S(5); }
int fn2() { return 2; } // expected-note {{declared here}}

constexpr int a = *fn().value;
constinit int b = *fn().value;
const int c = *fn().value;
int d = *fn().value;

constexpr int e = *fn().value + fn2(); // expected-error {{must be initialized by a constant expression}} \
// expected-error {{call to consteval function 'lvalue_to_rvalue_init_from_heap::fn' is not a constant expression}} \
// expected-note {{non-constexpr function 'fn2'}} \
// expected-note {{pointer to heap-allocated object}}

int f = *fn().value + fn2(); // expected-error {{call to consteval function 'lvalue_to_rvalue_init_from_heap::fn' is not a constant expression}} \
// expected-note {{pointer to heap-allocated object}}
}
#endif
1 change: 1 addition & 0 deletions clang/test/SemaCXX/enum-scoped.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ enum class E4 {
e1 = -2147483648, // ok
e2 = 2147483647, // ok
e3 = 2147483648 // expected-error{{enumerator value evaluates to 2147483648, which cannot be narrowed to type 'int'}}
// expected-warning@-1{{changes value}}
};

enum class E5 {
Expand Down
122 changes: 122 additions & 0 deletions clang/test/SemaHLSL/packoffset-invalid.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -fnative-half-type -verify %s

// expected-warning@+1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}}
cbuffer Mix
{
float4 M1 : packoffset(c0);
float M2;
float M3 : packoffset(c1.y);
}

// expected-warning@+1{{cannot mix packoffset elements with nonpackoffset elements in a cbuffer}}
cbuffer Mix2
{
float4 M4;
float M5 : packoffset(c1.y);
float M6 ;
}

// expected-error@+1{{attribute 'packoffset' only applies to shader constant in a constant buffer}}
float4 g : packoffset(c0);

cbuffer IllegalOffset
{
// expected-error@+1{{invalid resource class specifier 't2' for packoffset, expected 'c'}}
float4 i1 : packoffset(t2);
// expected-error@+1{{invalid component 'm' used; expected 'x', 'y', 'z', or 'w'}}
float i2 : packoffset(c1.m);
}

cbuffer Overlap
{
float4 o1 : packoffset(c0);
// expected-error@+1{{packoffset overlap between 'o2', 'o1'}}
float2 o2 : packoffset(c0.z);
}

cbuffer CrossReg
{
// expected-error@+1{{packoffset cannot cross register boundary}}
float4 c1 : packoffset(c0.y);
// expected-error@+1{{packoffset cannot cross register boundary}}
float2 c2 : packoffset(c1.w);
}

struct ST {
float s;
};

cbuffer Aggregate
{
// expected-error@+1{{packoffset cannot cross register boundary}}
ST A1 : packoffset(c0.y);
// expected-error@+1{{packoffset cannot cross register boundary}}
float A2[2] : packoffset(c1.w);
}

cbuffer Double {
// expected-error@+1{{packoffset at 'y' not match alignment 64 required by 'double'}}
double d : packoffset(c.y);
// expected-error@+1{{packoffset cannot cross register boundary}}
double2 d2 : packoffset(c.z);
// expected-error@+1{{packoffset cannot cross register boundary}}
double3 d3 : packoffset(c.z);
}

cbuffer ParsingFail {
// expected-error@+1{{expected identifier}}
float pf0 : packoffset();
// expected-error@+1{{expected identifier}}
float pf1 : packoffset((c0));
// expected-error@+1{{expected ')'}}
float pf2 : packoffset(c0, x);
// expected-error@+1{{invalid component 'X' used}}
float pf3 : packoffset(c.X);
// expected-error@+1{{expected '(' after ''}}
float pf4 : packoffset;
// expected-error@+1{{expected identifier}}
float pf5 : packoffset(;
// expected-error@+1{{expected '(' after '}}
float pf6 : packoffset);
// expected-error@+1{{expected '(' after '}}
float pf7 : packoffset c0.x;

// expected-error@+1{{invalid component 'xy' used}}
float pf8 : packoffset(c0.xy);
// expected-error@+1{{invalid component 'rg' used}}
float pf9 : packoffset(c0.rg);
// expected-error@+1{{invalid component 'yes' used}}
float pf10 : packoffset(c0.yes);
// expected-error@+1{{invalid component 'woo'}}
float pf11 : packoffset(c0.woo);
// expected-error@+1{{invalid component 'xr' used}}
float pf12 : packoffset(c0.xr);
}

struct ST2 {
float a;
float2 b;
};

cbuffer S {
float S0 : packoffset(c0.y);
ST2 S1[2] : packoffset(c1);
// expected-error@+1{{packoffset overlap between 'S2', 'S1'}}
half2 S2 : packoffset(c1.w);
half2 S3 : packoffset(c2.w);
}

struct ST23 {
float s0;
ST2 s1;
};

cbuffer S2 {
float S20 : packoffset(c0.y);
ST2 S21 : packoffset(c1);
half2 S22 : packoffset(c2.w);
double S23[2] : packoffset(c3);
// expected-error@+1{{packoffset overlap between 'S24', 'S23'}}
float S24 : packoffset(c3.z);
float S25 : packoffset(c4.z);
}
229 changes: 229 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-intexpr-clause-ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,93 @@ void NormalUses() {
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel wait
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
#pragma acc parallel wait()
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
#pragma acc parallel wait(some_int(), some_long())
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// 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: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
#pragma acc parallel wait(queues:some_int(), some_long())
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has queues tag
// CHECK-NEXT: <<<NULL>>>
// 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: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
#pragma acc parallel wait(devnum: some_int() :some_int(), some_long())
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has devnum
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// 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: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
#pragma acc parallel wait(devnum: some_int() : queues :some_int(), some_long()) wait(devnum: some_int() : queues :some_int(), some_long())
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause has devnum has queues tag
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// 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: wait clause has devnum has queues tag
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// 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: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
}


Expand Down Expand Up @@ -282,6 +369,72 @@ void TemplUses(T t, U u) {
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel wait
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel wait()
while (true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

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

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

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

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


// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}}EndMarker
Expand Down Expand Up @@ -437,6 +590,82 @@ void TemplUses(T t, U u) {
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: wait clause
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt'
// 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: wait clause has queues tag
// CHECK-NEXT: <<<NULL>>>
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt'
// 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: wait clause has devnum has queues tag
// 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: 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: wait clause has devnum
// 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: 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: DeclStmt
// CHECK-NEXT: VarDecl{{.*}}EndMarker
}
Expand Down
38 changes: 38 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-wait-clause.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct NotConvertible{} NC;
short getS();
int getI();

void uses() {
int arr[5];

#pragma acc parallel wait
while(1);

#pragma acc serial wait()
while(1);

#pragma acc kernels wait(getS(), getI())
while(1);

#pragma acc parallel wait(devnum:getS(): getI())
while(1);

#pragma acc parallel wait(devnum:getS(): queues: getI()) wait(devnum:getI(): queues: getS(), getI(), 5)
while(1);

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

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

// expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('int[5]' invalid)}}
// expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('int[5]' invalid)}}
// expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel wait(devnum:arr : queues: arr, NC, 5)
while(1);
}
104 changes: 104 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-wait-clause.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// RUN: %clang_cc1 %s -fopenacc -verify

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

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

void Test() {

// 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 wait(Ambiguous)
while (true);

// expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc parallel wait(4, Explicit, 5)
while (true);

// 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 wait(queues: Ambiguous, 5)
while (true);

// expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc parallel wait(devnum: Explicit: 5)
while (true);

// expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc parallel wait(devnum: Explicit:queues: 5)
while (true);

// expected-error@+1{{use of undeclared identifier 'queues'}}
#pragma acc parallel wait(devnum: queues: 5)
while (true);
}

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() {

#pragma acc parallel wait(T{})
while (true);

#pragma acc parallel wait(devnum:typename T::ShortTy{}:queues:typename T::IntTy{})
while (true);

// expected-error@+4{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
// expected-note@#INST{{in instantiation of function template specialization}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel wait(devnum:T::value :queues:T::ACValue)
while (true);

// expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
// expected-error@+3{{multiple conversions from expression type 'const 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 wait(devnum:T::EXValue :queues:T::ACValue)
while (true);

// expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
// expected-error@+3{{multiple conversions from expression type 'const 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 wait(T::EXValue, T::ACValue)
while (true);

// expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
// expected-error@+3{{multiple conversions from expression type 'const 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 wait(queues: T::EXValue, T::ACValue)
while (true);

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

void Inst() {
TestInst<HasInt>(); // #INST
}
2 changes: 1 addition & 1 deletion clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ fatbinary(ArrayRef<std::pair<StringRef, StringRef>> InputFiles,

SmallVector<StringRef> Targets = {"-targets=host-x86_64-unknown-linux"};
for (const auto &[File, Arch] : InputFiles)
Targets.push_back(Saver.save("hipv4-amdgcn-amd-amdhsa--" + Arch));
Targets.push_back(Saver.save("hip-amdgcn-amd-amdhsa--" + Arch));
CmdArgs.push_back(Saver.save(llvm::join(Targets, ",")));

#ifdef _WIN32
Expand Down
6 changes: 6 additions & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2851,6 +2851,12 @@ void OpenACCClauseEnqueue::VisitAsyncClause(const OpenACCAsyncClause &C) {
if (C.hasIntExpr())
Visitor.AddStmt(C.getIntExpr());
}
void OpenACCClauseEnqueue::VisitWaitClause(const OpenACCWaitClause &C) {
if (const Expr *DevNumExpr = C.getDevNumExpr())
Visitor.AddStmt(DevNumExpr);
for (Expr *QE : C.getQueueIdExprs())
Visitor.AddStmt(QE);
}
} // namespace

void EnqueueVisitor::EnqueueChildren(const OpenACCClause *C) {
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/ctx_profile/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set(CTX_PROFILE_SOURCES
)

set(CTX_PROFILE_HEADERS
CtxInstrContextNode.h
CtxInstrProfiling.h
)

Expand Down
116 changes: 116 additions & 0 deletions compiler-rt/lib/ctx_profile/CtxInstrContextNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//===--- CtxInstrContextNode.h - Contextual Profile Node --------*- 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
//
//===----------------------------------------------------------------------===//
//==============================================================================
//
// NOTE!
// llvm/lib/ProfileData/CtxInstrContextNode.h and
// compiler-rt/lib/ctx_profile/CtxInstrContextNode.h
// must be exact copies of eachother
//
// compiler-rt creates these objects as part of the instrumentation runtime for
// contextual profiling. LLVM only consumes them to convert a contextual tree
// to a bitstream.
//
//==============================================================================

/// The contextual profile is a directed tree where each node has one parent. A
/// node (ContextNode) corresponds to a function activation. The root of the
/// tree is at a function that was marked as entrypoint to the compiler. A node
/// stores counter values for edges and a vector of subcontexts. These are the
/// contexts of callees. The index in the subcontext vector corresponds to the
/// index of the callsite (as was instrumented via llvm.instrprof.callsite). At
/// that index we find a linked list, potentially empty, of ContextNodes. Direct
/// calls will have 0 or 1 values in the linked list, but indirect callsites may
/// have more.
///
/// The ContextNode has a fixed sized header describing it - the GUID of the
/// function, the size of the counter and callsite vectors. It is also an
/// (intrusive) linked list for the purposes of the indirect call case above.
///
/// Allocation is expected to happen on an Arena. The allocation lays out inline
/// the counter and subcontexts vectors. The class offers APIs to correctly
/// reference the latter.
///
/// The layout is as follows:
///
/// [[declared fields][counters vector][vector of ptrs to subcontexts]]
///
/// See also documentation on the counters and subContexts members below.
///
/// The structure of the ContextNode is known to LLVM, because LLVM needs to:
/// (1) increment counts, and
/// (2) form a GEP for the position in the subcontext list of a callsite
/// This means changes to LLVM contextual profile lowering and changes here
/// must be coupled.
/// Note: the header content isn't interesting to LLVM (other than its size)
///
/// Part of contextual collection is the notion of "scratch contexts". These are
/// buffers that are "large enough" to allow for memory-safe acceses during
/// counter increments - meaning the counter increment code in LLVM doesn't need
/// to be concerned with memory safety. Their subcontexts never get populated,
/// though. The runtime code here produces and recognizes them.

#ifndef LLVM_PROFILEDATA_CTXINSTRCONTEXTNODE_H
#define LLVM_PROFILEDATA_CTXINSTRCONTEXTNODE_H

#include <stdint.h>
#include <stdlib.h>

namespace llvm {
namespace ctx_profile {
using GUID = uint64_t;

class ContextNode final {
const GUID Guid;
ContextNode *const Next;
const uint32_t NrCounters;
const uint32_t NrCallsites;

public:
ContextNode(GUID Guid, uint32_t NrCounters, uint32_t NrCallsites,
ContextNode *Next = nullptr)
: Guid(Guid), Next(Next), NrCounters(NrCounters),
NrCallsites(NrCallsites) {}

static inline size_t getAllocSize(uint32_t NrCounters, uint32_t NrCallsites) {
return sizeof(ContextNode) + sizeof(uint64_t) * NrCounters +
sizeof(ContextNode *) * NrCallsites;
}

// The counters vector starts right after the static header.
uint64_t *counters() {
ContextNode *addr_after = &(this[1]);
return reinterpret_cast<uint64_t *>(addr_after);
}

uint32_t counters_size() const { return NrCounters; }
uint32_t callsites_size() const { return NrCallsites; }

const uint64_t *counters() const {
return const_cast<ContextNode *>(this)->counters();
}

// The subcontexts vector starts right after the end of the counters vector.
ContextNode **subContexts() {
return reinterpret_cast<ContextNode **>(&(counters()[NrCounters]));
}

ContextNode *const *subContexts() const {
return const_cast<ContextNode *>(this)->subContexts();
}

GUID guid() const { return Guid; }
ContextNode *next() const { return Next; }

size_t size() const { return getAllocSize(NrCounters, NrCallsites); }

uint64_t entrycount() const { return counters()[0]; }
};
} // namespace ctx_profile
} // namespace llvm
#endif
58 changes: 30 additions & 28 deletions compiler-rt/lib/ctx_profile/CtxInstrProfiling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ bool validate(const ContextRoot *Root) {
}
return true;
}

inline ContextNode *allocContextNode(char *Place, GUID Guid,
uint32_t NrCounters, uint32_t NrCallsites,
ContextNode *Next = nullptr) {
assert(reinterpret_cast<uint64_t>(Place) % ExpectedAlignment == 0);
return new (Place) ContextNode(Guid, NrCounters, NrCallsites, Next);
}

void resetContextNode(ContextNode &Node) {
// FIXME(mtrofin): this is std::memset, which we can probably use if we
// drop/reduce the dependency on sanitizer_common.
for (uint32_t I = 0; I < Node.counters_size(); ++I)
Node.counters()[I] = 0;
for (uint32_t I = 0; I < Node.callsites_size(); ++I)
for (auto *Next = Node.subContexts()[I]; Next; Next = Next->next())
resetContextNode(*Next);
}

void onContextEnter(ContextNode &Node) { ++Node.counters()[0]; }

} // namespace

// the scratch buffer - what we give when we can't produce a real context (the
Expand Down Expand Up @@ -134,27 +154,9 @@ void Arena::freeArenaList(Arena *&A) {
A = nullptr;
}

inline ContextNode *ContextNode::alloc(char *Place, GUID Guid,
uint32_t NrCounters,
uint32_t NrCallsites,
ContextNode *Next) {
assert(reinterpret_cast<uint64_t>(Place) % ExpectedAlignment == 0);
return new (Place) ContextNode(Guid, NrCounters, NrCallsites, Next);
}

void ContextNode::reset() {
// FIXME(mtrofin): this is std::memset, which we can probably use if we
// drop/reduce the dependency on sanitizer_common.
for (uint32_t I = 0; I < NrCounters; ++I)
counters()[I] = 0;
for (uint32_t I = 0; I < NrCallsites; ++I)
for (auto *Next = subContexts()[I]; Next; Next = Next->Next)
Next->reset();
}

// If this is the first time we hit a callsite with this (Guid) particular
// callee, we need to allocate.
ContextNode *getCallsiteSlow(uint64_t Guid, ContextNode **InsertionPoint,
ContextNode *getCallsiteSlow(GUID Guid, ContextNode **InsertionPoint,
uint32_t NrCounters, uint32_t NrCallsites) {
auto AllocSize = ContextNode::getAllocSize(NrCounters, NrCallsites);
auto *Mem = __llvm_ctx_profile_current_context_root->CurrentMem;
Expand All @@ -169,8 +171,8 @@ ContextNode *getCallsiteSlow(uint64_t Guid, ContextNode **InsertionPoint,
Mem->allocateNewArena(getArenaAllocSize(AllocSize), Mem);
AllocPlace = Mem->tryBumpAllocate(AllocSize);
}
auto *Ret = ContextNode::alloc(AllocPlace, Guid, NrCounters, NrCallsites,
*InsertionPoint);
auto *Ret = allocContextNode(AllocPlace, Guid, NrCounters, NrCallsites,
*InsertionPoint);
*InsertionPoint = Ret;
return Ret;
}
Expand Down Expand Up @@ -224,7 +226,7 @@ ContextNode *__llvm_ctx_profile_get_context(void *Callee, GUID Guid,
"Context: %p, Asked: %lu %u %u, Got: %lu %u %u \n",
Ret, Guid, NrCallsites, NrCounters, Ret->guid(),
Ret->callsites_size(), Ret->counters_size());
Ret->onEntry();
onContextEnter(*Ret);
return Ret;
}

Expand All @@ -241,8 +243,8 @@ void setupContext(ContextRoot *Root, GUID Guid, uint32_t NrCounters,
auto *M = Arena::allocateNewArena(getArenaAllocSize(Needed));
Root->FirstMemBlock = M;
Root->CurrentMem = M;
Root->FirstNode = ContextNode::alloc(M->tryBumpAllocate(Needed), Guid,
NrCounters, NrCallsites);
Root->FirstNode = allocContextNode(M->tryBumpAllocate(Needed), Guid,
NrCounters, NrCallsites);
AllContextRoots.PushBack(Root);
}

Expand All @@ -254,7 +256,7 @@ ContextNode *__llvm_ctx_profile_start_context(
}
if (Root->Taken.TryLock()) {
__llvm_ctx_profile_current_context_root = Root;
Root->FirstNode->onEntry();
onContextEnter(*Root->FirstNode);
return Root->FirstNode;
}
// If this thread couldn't take the lock, return scratch context.
Expand All @@ -281,13 +283,13 @@ void __llvm_ctx_profile_start_collection() {
for (auto *Mem = Root->FirstMemBlock; Mem; Mem = Mem->next())
++NrMemUnits;

Root->FirstNode->reset();
resetContextNode(*Root->FirstNode);
}
__sanitizer::Printf("[ctxprof] Initial NrMemUnits: %zu \n", NrMemUnits);
}

bool __llvm_ctx_profile_fetch(
void *Data, bool (*Writer)(void *W, const __ctx_profile::ContextNode &)) {
bool __llvm_ctx_profile_fetch(void *Data,
bool (*Writer)(void *W, const ContextNode &)) {
assert(Writer);
__sanitizer::GenericScopedLock<__sanitizer::SpinMutex> Lock(
&AllContextsMutex);
Expand Down
118 changes: 13 additions & 105 deletions compiler-rt/lib/ctx_profile/CtxInstrProfiling.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@
#ifndef CTX_PROFILE_CTXINSTRPROFILING_H_
#define CTX_PROFILE_CTXINSTRPROFILING_H_

#include "CtxInstrContextNode.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include <sanitizer/common_interface_defs.h>

using namespace llvm::ctx_profile;

namespace __ctx_profile {
using GUID = uint64_t;

static constexpr size_t ExpectedAlignment = 8;
// We really depend on this, see further below. We currently support x86_64.
// When we want to support other archs, we need to trace the places Alignment is
Expand Down Expand Up @@ -62,99 +65,6 @@ class Arena final {
// it to be thus aligned.
static_assert(alignof(Arena) == ExpectedAlignment);

/// The contextual profile is a directed tree where each node has one parent. A
/// node (ContextNode) corresponds to a function activation. The root of the
/// tree is at a function that was marked as entrypoint to the compiler. A node
/// stores counter values for edges and a vector of subcontexts. These are the
/// contexts of callees. The index in the subcontext vector corresponds to the
/// index of the callsite (as was instrumented via llvm.instrprof.callsite). At
/// that index we find a linked list, potentially empty, of ContextNodes. Direct
/// calls will have 0 or 1 values in the linked list, but indirect callsites may
/// have more.
///
/// The ContextNode has a fixed sized header describing it - the GUID of the
/// function, the size of the counter and callsite vectors. It is also an
/// (intrusive) linked list for the purposes of the indirect call case above.
///
/// Allocation is expected to happen on an Arena. The allocation lays out inline
/// the counter and subcontexts vectors. The class offers APIs to correctly
/// reference the latter.
///
/// The layout is as follows:
///
/// [[declared fields][counters vector][vector of ptrs to subcontexts]]
///
/// See also documentation on the counters and subContexts members below.
///
/// The structure of the ContextNode is known to LLVM, because LLVM needs to:
/// (1) increment counts, and
/// (2) form a GEP for the position in the subcontext list of a callsite
/// This means changes to LLVM contextual profile lowering and changes here
/// must be coupled.
/// Note: the header content isn't interesting to LLVM (other than its size)
///
/// Part of contextual collection is the notion of "scratch contexts". These are
/// buffers that are "large enough" to allow for memory-safe acceses during
/// counter increments - meaning the counter increment code in LLVM doesn't need
/// to be concerned with memory safety. Their subcontexts never get populated,
/// though. The runtime code here produces and recognizes them.
class ContextNode final {
const GUID Guid;
ContextNode *const Next;
const uint32_t NrCounters;
const uint32_t NrCallsites;

public:
ContextNode(GUID Guid, uint32_t NrCounters, uint32_t NrCallsites,
ContextNode *Next = nullptr)
: Guid(Guid), Next(Next), NrCounters(NrCounters),
NrCallsites(NrCallsites) {}
static inline ContextNode *alloc(char *Place, GUID Guid, uint32_t NrCounters,
uint32_t NrCallsites,
ContextNode *Next = nullptr);

static inline size_t getAllocSize(uint32_t NrCounters, uint32_t NrCallsites) {
return sizeof(ContextNode) + sizeof(uint64_t) * NrCounters +
sizeof(ContextNode *) * NrCallsites;
}

// The counters vector starts right after the static header.
uint64_t *counters() {
ContextNode *addr_after = &(this[1]);
return reinterpret_cast<uint64_t *>(addr_after);
}

uint32_t counters_size() const { return NrCounters; }
uint32_t callsites_size() const { return NrCallsites; }

const uint64_t *counters() const {
return const_cast<ContextNode *>(this)->counters();
}

// The subcontexts vector starts right after the end of the counters vector.
ContextNode **subContexts() {
return reinterpret_cast<ContextNode **>(&(counters()[NrCounters]));
}

ContextNode *const *subContexts() const {
return const_cast<ContextNode *>(this)->subContexts();
}

GUID guid() const { return Guid; }
ContextNode *next() { return Next; }

size_t size() const { return getAllocSize(NrCounters, NrCallsites); }

void reset();

// since we go through the runtime to get a context back to LLVM, in the entry
// basic block, might as well handle incrementing the entry basic block
// counter.
void onEntry() { ++counters()[0]; }

uint64_t entrycount() const { return counters()[0]; }
};

// Verify maintenance to ContextNode doesn't change this invariant, which makes
// sure the inlined vectors are appropriately aligned.
static_assert(alignof(ContextNode) == ExpectedAlignment);
Expand Down Expand Up @@ -219,8 +129,7 @@ extern "C" {
extern __thread void *volatile __llvm_ctx_profile_expected_callee[2];
/// TLS where LLVM stores the pointer inside a caller's subcontexts vector that
/// corresponds to the callsite being lowered.
extern __thread __ctx_profile::ContextNode *
*volatile __llvm_ctx_profile_callsite[2];
extern __thread ContextNode **volatile __llvm_ctx_profile_callsite[2];

// __llvm_ctx_profile_current_context_root is exposed for unit testing,
// othwerise it's only used internally by compiler-rt/ctx_profile.
Expand All @@ -229,20 +138,19 @@ extern __thread __ctx_profile::ContextRoot

/// called by LLVM in the entry BB of a "entry point" function. The returned
/// pointer may be "tainted" - its LSB set to 1 - to indicate it's scratch.
__ctx_profile::ContextNode *
__llvm_ctx_profile_start_context(__ctx_profile::ContextRoot *Root,
__ctx_profile::GUID Guid, uint32_t Counters,
uint32_t Callsites);
ContextNode *__llvm_ctx_profile_start_context(__ctx_profile::ContextRoot *Root,
GUID Guid, uint32_t Counters,
uint32_t Callsites);

/// paired with __llvm_ctx_profile_start_context, and called at the exit of the
/// entry point function.
void __llvm_ctx_profile_release_context(__ctx_profile::ContextRoot *Root);

/// called for any other function than entry points, in the entry BB of such
/// function. Same consideration about LSB of returned value as .._start_context
__ctx_profile::ContextNode *
__llvm_ctx_profile_get_context(void *Callee, __ctx_profile::GUID Guid,
uint32_t NrCounters, uint32_t NrCallsites);
ContextNode *__llvm_ctx_profile_get_context(void *Callee, GUID Guid,
uint32_t NrCounters,
uint32_t NrCallsites);

/// Prepares for collection. Currently this resets counter values but preserves
/// internal context tree structure.
Expand All @@ -257,7 +165,7 @@ void __llvm_ctx_profile_free();
/// The Writer's first parameter plays the role of closure for Writer, and is
/// what the caller of __llvm_ctx_profile_fetch passes as the Data parameter.
/// The second parameter is the root of a context tree.
bool __llvm_ctx_profile_fetch(
void *Data, bool (*Writer)(void *, const __ctx_profile::ContextNode &));
bool __llvm_ctx_profile_fetch(void *Data,
bool (*Writer)(void *, const ContextNode &));
}
#endif // CTX_PROFILE_CTXINSTRPROFILING_H_
2 changes: 1 addition & 1 deletion compiler-rt/test/asan/TestCases/Posix/fake_stack_gc.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clangxx_asan -O0 -pthread %s -o %t && %env_asan_opts=use_sigaltstack=0 %run not --crash %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -O0 -pthread %s -o %t && %env_asan_opts=use_sigaltstack=0 not --crash %run %t 2>&1 | FileCheck %s

// Check that fake stack does not discard frames on the main stack, when GC is
// triggered from high alt stack.
Expand Down
22 changes: 22 additions & 0 deletions compiler-rt/test/ctx_profile/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@ set(CTX_PROFILE_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})

set(CTX_PROFILE_TESTSUITES)

macro(get_bits_for_arch arch bits)
if (${arch} MATCHES "x86_64")
set(${bits} 64)
else()
message(FATAL_ERROR "Unexpected target architecture: ${arch}")
endif()
endmacro()

set(CTX_PROFILE_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS} ctx_profile)

foreach(arch ${CTX_PROFILE_SUPPORTED_ARCH})
set(CTX_PROFILE_TEST_TARGET_ARCH ${arch})
string(TOLOWER "-${arch}-${OS_NAME}" CTX_PROFILE_TEST_CONFIG_SUFFIX)
string(TOUPPER ${arch} ARCH_UPPER_CASE)
set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config)
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py
)
list(APPEND CTX_PROFILE_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
endforeach()

# Add unit tests.
if(COMPILER_RT_INCLUDE_TESTS)
foreach(arch ${CTX_PROFILE_SUPPORTED_ARCH})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
;
; NOTE: if this test fails, please make sure the two files are identical copies
; of eachother.
;
; RUN: diff %crt_src/lib/ctx_profile/CtxInstrContextNode.h %llvm_src/include/llvm/ProfileData/CtxInstrContextNode.h
31 changes: 31 additions & 0 deletions compiler-rt/test/ctx_profile/lit.cfg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# -*- Python -*-

import os
import platform
import re

import lit.formats

# Only run the tests on supported OSs.
if config.host_os not in ["Linux"]:
config.unsupported = True


def get_required_attr(config, attr_name):
attr_value = getattr(config, attr_name, None)
if attr_value == None:
lit_config.fatal(
"No attribute %r in test configuration! You may need to run "
"tests from your build directory or add this attribute "
"to lit.site.cfg.py " % attr_name
)
return attr_value


# Setup config name.
config.name = "CtxProfile" + config.name_suffix

# Setup source root.
config.test_source_root = os.path.dirname(__file__)
# Default test suffixes.
config.suffixes = [".c", ".cpp", ".test"]
14 changes: 14 additions & 0 deletions compiler-rt/test/ctx_profile/lit.site.cfg.py.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@LIT_SITE_CFG_IN_HEADER@

# Tool-specific config options.
config.name_suffix = "@CTX_PROFILE_TEST_CONFIG_SUFFIX@"
config.target_cflags = "@CTX_PROFILE_TEST_TARGET_CFLAGS@"
config.clang = "@CTX_PROFILE_TEST_TARGET_CC@"
config.bits = "@CTX_PROFILE_TEST_BITS@"
config.target_arch = "@CTX_PROFILE_TEST_TARGET_ARCH@"

# Load common config for all compiler-rt lit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")

# Load tool-specific config that would do the real work.
lit_config.load_config(config, "@CTX_PROFILE_LIT_SOURCE_DIR@/lit.cfg.py")
3 changes: 3 additions & 0 deletions compiler-rt/test/dfsan/release_shadow_space.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// DFSAN_OPTIONS=no_huge_pages_for_shadow=false RUN: %clang_dfsan %s -DORIGIN_TRACKING -mllvm -dfsan-track-origins=1 -o %t && %run %t
// DFSAN_OPTIONS=no_huge_pages_for_shadow=true RUN: %clang_dfsan %s -DORIGIN_TRACKING -mllvm -dfsan-track-origins=1 -o %t && %run %t

// This test is flaky right now: https://github.com/llvm/llvm-project/issues/91287
// UNSUPPORTED: target={{.*}}

#include <assert.h>
#include <sanitizer/dfsan_interface.h>
#include <stdbool.h>
Expand Down
6 changes: 6 additions & 0 deletions compiler-rt/test/lit.common.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -987,3 +987,9 @@ def is_windows_lto_supported():
gcc_dir = os.path.dirname(config.clang)
libasan_dir = os.path.join(gcc_dir, "..", "lib" + config.bits)
push_dynamic_library_lookup_path(config, libasan_dir)


# Help tests that make sure certain files are in-sync between compiler-rt and
# llvm.
config.substitutions.append(("%crt_src", config.compiler_rt_src_root))
config.substitutions.append(("%llvm_src", config.llvm_src_root))
30 changes: 24 additions & 6 deletions flang/docs/Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,17 @@ end
These definitions yield fairly poor results due to floating-point
cancellation, and every Fortran compiler (including this one)
uses better algorithms.
* When an index variable of a `FORALL` or `DO CONCURRENT` is present
in the enclosing scope, and the construct does not have an explicit
type specification for its index variables, some weird restrictions
in F'2023 subclause 19.4 paragraphs 6 & 8 should apply. Since this
compiler properly scopes these names, violations of these restrictions
elicit only portability warnings by default.
* The rules for pairwise distinguishing the specific procedures of a
generic interface are inadequate, as admitted in note C.11.6 of F'2023.
Generic interfaces whose specific procedures can be easily proven by
hand to be pairwise distinct (i.e., no ambiguous reference is possible)
appear in real applications, but are still non-conforming under the
incomplete tests in F'2023 15.4.3.4.5.
These cases are compiled with optional portability warnings.
* `PROCEDURE(), BIND(C) :: PROC` is not conforming, as there is no
procedure interface. This compiler accepts it, since there is otherwise
no way to declare an interoperable dummy procedure with an arbitrary
interface like `void (*)()`.

## Extensions, deletions, and legacy features supported by default

Expand Down Expand Up @@ -351,6 +349,9 @@ end
when necessary to the type of the result.
An `OPTIONAL`, `POINTER`, or `ALLOCATABLE` argument after
the first two cannot be converted, as it may not be present.
* A derived type that meets (most of) the requirements of an interoperable
derived type can be used as such where an interoperable type is
required, with warnings, even if it lacks the BIND(C) attribute.

### Extensions supported when enabled by options

Expand Down Expand Up @@ -728,6 +729,23 @@ end
array and structure constructors not to be finalized, so it also makes sense
not to finalize their allocatable components when releasing their storage).

* F'2023 19.4 paragraph 5: "If integer-type-spec appears in data-implied-do or
ac-implied-do-control it has the specified type and type parameters; otherwise
it has the type and type parameters that it would have if it were the name of
a variable in the innermost executable construct or scoping unit that includes
the DATA statement or array constructor, and this type shall be integer type."
Reading "would have if it were" as being the subjunctive, this would mean that
an untyped implied DO index variable should be implicitly typed according to
the rules active in the enclosing scope. But all other Fortran compilers interpret
the "would have if it were" as meaning "has if it is" -- i.e., if the name
is visible in the enclosing scope, the type of that name is used as the
type of the implied DO index. So this is an error, not a simple application
of the default implicit typing rule:
```
character j
print *, [(j,j=1,10)]
```

## De Facto Standard Features

* `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the
Expand Down
3 changes: 2 additions & 1 deletion flang/include/flang/Common/Fortran-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
ImpliedDoIndexScope, DistinctCommonSizes, OddIndexVariableRestrictions,
IndistinguishableSpecifics, SubroutineAndFunctionSpecifics,
EmptySequenceType, NonSequenceCrayPointee, BranchIntoConstruct,
BadBranchTarget, ConvertedArgument, HollerithPolymorphic, ListDirectedSize)
BadBranchTarget, ConvertedArgument, HollerithPolymorphic, ListDirectedSize,
NonBindCInteroperability)

// Portability and suspicious usage warnings
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
Expand Down
6 changes: 4 additions & 2 deletions flang/include/flang/Evaluate/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,11 @@ std::optional<Expr<SomeType>> AsGenericExpr(const Symbol &);
// Propagate std::optional from input to output.
template <typename A>
std::optional<Expr<SomeType>> AsGenericExpr(std::optional<A> &&x) {
if (!x)
if (x) {
return AsGenericExpr(std::move(*x));
} else {
return std::nullopt;
return AsGenericExpr(std::move(*x));
}
}

template <typename A>
Expand Down
12 changes: 12 additions & 0 deletions flang/include/flang/Lower/AbstractConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,18 @@ class AbstractConverter {
/// function.
virtual void bindHostAssocTuple(mlir::Value val) = 0;

/// Returns fir.dummy_scope operation's result value to be used
/// as dummy_scope operand of hlfir.declare operations for the dummy
/// arguments of this function.
virtual mlir::Value dummyArgsScopeValue() const = 0;

/// Returns true if the given symbol is a dummy argument of this function.
/// Note that it returns false for all the symbols after all the variables
/// are instantiated for this function, i.e. it can only be used reliably
/// during the instatiation of the variables.
virtual bool
isRegisteredDummySymbol(Fortran::semantics::SymbolRef symRef) const = 0;

//===--------------------------------------------------------------------===//
// Types
//===--------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions flang/include/flang/Optimizer/Builder/HLFIRTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ fir::FortranVariableOpInterface
genDeclare(mlir::Location loc, fir::FirOpBuilder &builder,
const fir::ExtendedValue &exv, llvm::StringRef name,
fir::FortranVariableFlagsAttr flags,
mlir::Value dummyScope = nullptr,
fir::CUDADataAttributeAttr cudaAttr = {});

/// Generate an hlfir.associate to build a variable from an expression value.
Expand Down
1 change: 1 addition & 0 deletions flang/include/flang/Optimizer/HLFIR/HLFIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def hlfir_DeclareOp : hlfir_Op<"declare", [AttrSizedOperandSegments,
let builders = [
OpBuilder<(ins "mlir::Value":$memref, "llvm::StringRef":$uniq_name,
CArg<"mlir::Value", "{}">:$shape, CArg<"mlir::ValueRange", "{}">:$typeparams,
CArg<"mlir::Value", "{}">:$dummy_scope,
CArg<"fir::FortranVariableFlagsAttr", "{}">:$fortran_attrs,
CArg<"fir::CUDADataAttributeAttr", "{}">:$cuda_attr)>];

Expand Down
3 changes: 2 additions & 1 deletion flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -2905,7 +2905,8 @@ struct ModuleSubprogram {
UNION_CLASS_BOILERPLATE(ModuleSubprogram);
std::variant<common::Indirection<FunctionSubprogram>,
common::Indirection<SubroutineSubprogram>,
common::Indirection<SeparateModuleSubprogram>>
common::Indirection<SeparateModuleSubprogram>,
common::Indirection<CompilerDirective>>
u;
};

Expand Down
28 changes: 17 additions & 11 deletions flang/lib/Evaluate/fold-designator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,8 @@ static std::optional<DataRef> OffsetToDataRef(FoldingContext &context,
if (IsAllocatableOrPointer(symbol)) {
return entity.IsSymbol() ? DataRef{symbol}
: DataRef{std::move(entity.GetComponent())};
}
std::optional<DataRef> result;
if (std::optional<DynamicType> type{DynamicType::From(symbol)}) {
} else if (std::optional<DynamicType> type{DynamicType::From(symbol)}) {
std::optional<DataRef> result;
if (!type->IsUnlimitedPolymorphic()) {
if (std::optional<Shape> shape{GetShape(context, symbol)}) {
if (GetRank(*shape) > 0) {
Expand All @@ -289,7 +288,7 @@ static std::optional<DataRef> OffsetToDataRef(FoldingContext &context,
: DataRef{std::move(entity.GetComponent())};
}
if (result && type->category() == TypeCategory::Derived &&
size < result->GetLastSymbol().size()) {
size <= result->GetLastSymbol().size()) {
if (const Symbol *
component{OffsetToUniqueComponent(
type->GetDerivedTypeSpec(), offset)}) {
Expand All @@ -298,25 +297,32 @@ static std::optional<DataRef> OffsetToDataRef(FoldingContext &context,
NamedEntity{Component{std::move(*result), *component}}, offset,
size);
}
result.reset();
}
}
}
return result;
} else {
return std::nullopt;
}
return result;
}

// Reconstructs a Designator from a symbol, an offset, and a size.
// Returns a ProcedureDesignator in the case of a whole procedure pointer.
std::optional<Expr<SomeType>> OffsetToDesignator(FoldingContext &context,
const Symbol &baseSymbol, ConstantSubscript offset, std::size_t size) {
if (offset < 0) {
return std::nullopt;
}
if (std::optional<DataRef> dataRef{
OffsetToDataRef(context, NamedEntity{baseSymbol}, offset, size)}) {
} else if (std::optional<DataRef> dataRef{OffsetToDataRef(
context, NamedEntity{baseSymbol}, offset, size)}) {
const Symbol &symbol{dataRef->GetLastSymbol()};
if (std::optional<Expr<SomeType>> result{
AsGenericExpr(std::move(*dataRef))}) {
if (IsProcedurePointer(symbol)) {
if (std::holds_alternative<SymbolRef>(dataRef->u)) {
return Expr<SomeType>{ProcedureDesignator{symbol}};
} else if (auto *component{std::get_if<Component>(&dataRef->u)}) {
return Expr<SomeType>{ProcedureDesignator{std::move(*component)}};
}
} else if (std::optional<Expr<SomeType>> result{
AsGenericExpr(std::move(*dataRef))}) {
if (IsAllocatableOrPointer(symbol)) {
} else if (auto type{DynamicType::From(symbol)}) {
if (auto elementBytes{
Expand Down
4 changes: 2 additions & 2 deletions flang/lib/Evaluate/formatting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -539,10 +539,10 @@ std::string DynamicType::AsFortran() const {
result += length->AsFortran();
}
return result + ')';
} else if (IsUnlimitedPolymorphic()) {
return "CLASS(*)";
} else if (IsAssumedType()) {
return "TYPE(*)";
} else if (IsUnlimitedPolymorphic()) {
return "CLASS(*)";
} else if (IsTypelessIntrinsicArgument()) {
return "(typeless intrinsic function argument)";
} else {
Expand Down
6 changes: 3 additions & 3 deletions flang/lib/Evaluate/tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ namespace Fortran::evaluate {
static constexpr bool allowOperandDuplication{false};

std::optional<Expr<SomeType>> AsGenericExpr(DataRef &&ref) {
const Symbol &symbol{ref.GetLastSymbol()};
if (auto dyType{DynamicType::From(symbol)}) {
if (auto dyType{DynamicType::From(ref.GetLastSymbol())}) {
return TypedWrapper<Designator, DataRef>(*dyType, std::move(ref));
} else {
return std::nullopt;
}
return std::nullopt;
}

std::optional<Expr<SomeType>> AsGenericExpr(const Symbol &symbol) {
Expand Down
Loading