From 9ab0d4d66fa14a9c57864fea72590886ace6d9ee Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Wed, 28 Dec 2022 11:19:27 -0800 Subject: [PATCH] [OpenMP][2/2] Make device functions have hidden visibility Similar to https://reviews.llvm.org/D136111, this time for class methods. D136111 summary: In OpenMP target offloading an in other offloading languages, we maintain a difference between device functions and kernel functions. Kernel functions must be visible to the host and act as the entry point to the target device. Device functions however cannot be called directly by the host and must be called by a kernel function. Currently, we make all definitions on the device protected by default. Because device functions cannot be called or used by the host they should have hidden visibility. This allows for the definitions to be better optimized via LTO or other passes. This patch marks every device class methods in the AST as having hidden visibility. The kernel function is generated later at code-gen and we set its visibility explicitly so it should not be affected. This prevents the user from overriding the visibility, but since the user can't do anything with these symbols anyway there is no point exporting them right now. --- clang/lib/AST/Decl.cpp | 10 ++++++++++ clang/test/OpenMP/target_visibility.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 clang/test/OpenMP/target_visibility.cpp diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index ccf5d71..236d4f9 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1020,6 +1020,16 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D, explicitSpecSuppressor = MD; } + // OpenMP target declare device functions are not callable from the host so + // they should not be exported from the device image. This applies to all + // functions as the host-callable kernel functions are emitted at codegen. + ASTContext &Context = D->getASTContext(); + if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice && + ((Context.getTargetInfo().getTriple().isAMDGPU() || + Context.getTargetInfo().getTriple().isNVPTX()) || + OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(MD))) + LV.mergeVisibility(HiddenVisibility, /*newExplicit=*/false); + } else if (const auto *RD = dyn_cast(D)) { if (const auto *spec = dyn_cast(RD)) { mergeTemplateLV(LV, spec, computation); diff --git a/clang/test/OpenMP/target_visibility.cpp b/clang/test/OpenMP/target_visibility.cpp new file mode 100644 index 0000000..af1a1bb --- /dev/null +++ b/clang/test/OpenMP/target_visibility.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -debug-info-kind=limited -verify -fopenmp -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -o - | FileCheck %s +// RUN: %clang_cc1 -debug-info-kind=limited -verify -fopenmp -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -o - | FileCheck %s +// expected-no-diagnostics + + +#pragma omp declare target + +struct A { +void foo() {} +static void sfoo() {} +}; + +#pragma omp end declare target + +struct B { +void bar(); +static void sbar(); +}; + +void B::bar() { A a; a.foo(); } +void B::sbar() { A::sfoo(); } +#pragma omp declare target to(B::bar, B::sbar) + +// CHECK-DAG: define hidden void @_ZN1B4sbarEv() +// CHECK-DAG: define linkonce_odr hidden void @_ZN1A4sfooEv() +// CHECK-DAG: define hidden void @_ZN1B3barEv( +// CHECK-DAG: define linkonce_odr hidden void @_ZN1A3fooEv( -- 2.7.4