https://github.com/wpcwzy updated https://github.com/llvm/llvm-project/pull/193881
From a9fcb2faa6168d6259f1a29c9ec482823b36dee2 Mon Sep 17 00:00:00 2001 From: Pincheng Wang <[email protected]> Date: Wed, 22 Apr 2026 22:30:19 +0800 Subject: [PATCH 1/4] clang: preserve declare-simd libcalls --- clang/lib/CodeGen/CGBuiltin.cpp | 15 ++++ clang/lib/CodeGen/CGOpenMPRuntime.cpp | 72 +++++++++++++++++++ .../OpenMP/declare_simd_preserve_builtin.cpp | 14 ++++ 3 files changed, 101 insertions(+) create mode 100644 clang/test/OpenMP/declare_simd_preserve_builtin.cpp diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index da72a43643a54..b0abe0de56c19 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -28,6 +28,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Intrinsics.h" @@ -69,6 +70,16 @@ static bool shouldEmitBuiltinAsIR(unsigned BuiltinID, return false; } +static bool shouldPreserveLibCallForDeclareSimd(const FunctionDecl *FD, + const LangOptions &LangOpts) { + if (!FD || !LangOpts.OpenMP) + return false; + + return llvm::any_of(FD->redecls(), [](const FunctionDecl *Redecl) { + return Redecl->hasAttr<OMPDeclareSimdDeclAttr>(); + }); +} + static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue, @@ -2647,6 +2658,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, BuiltinID, CGM.getTriple(), ErrnoOverriden, getLangOpts().MathErrno, OptNone, IsOptimizationEnabled); + if (GenerateFPMathIntrinsics && + shouldPreserveLibCallForDeclareSimd(FD, getLangOpts())) + GenerateFPMathIntrinsics = false; + if (GenerateFPMathIntrinsics) { switch (BuiltinIDIfNoAsmLabel) { case Builtin::BIacos: diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index a8255ac74cfcf..5626836669761 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -36,6 +36,7 @@ #include "llvm/IR/GlobalValue.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Value.h" +#include "llvm/IR/VFABIDemangler.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/raw_ostream.h" #include <cassert> @@ -11311,6 +11312,72 @@ emitX86DeclareSimdFunction(const FunctionDecl *FD, llvm::Function *Fn, } } +static void emitDeclareSimdVariantMetadata(CodeGenModule &CGM, + llvm::Function *Fn) { + llvm::SmallVector<std::string, 8> VariantMappings; + for (llvm::Attribute Attr : Fn->getAttributes().getFnAttrs()) { + if (!Attr.isStringAttribute()) + continue; + + StringRef VariantName = Attr.getKindAsString(); + if (!VariantName.starts_with("_ZGV")) + continue; + + std::optional<llvm::VFInfo> Info = + llvm::VFABI::tryDemangleForVFABI(VariantName, Fn->getFunctionType()); + if (!Info) + continue; + + llvm::FunctionType *VectorTy = + llvm::VFABI::createFunctionType(*Info, Fn->getFunctionType()); + llvm::Function *VecFn = llvm::cast<llvm::Function>( + Fn->getParent()->getOrInsertFunction(Info->VectorName, VectorTy) + .getCallee()); + CGM.addCompilerUsedGlobal(VecFn); + VariantMappings.push_back(std::string(VariantName)); + } + + if (VariantMappings.empty()) + return; + + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); + for (const std::string &VariantName : VariantMappings) + Out << VariantName << ','; + Buffer.pop_back(); + + Fn->removeFnAttr(llvm::VFABI::MappingsAttrName); + Fn->addFnAttr(llvm::VFABI::MappingsAttrName, Buffer.str()); +} + +static bool shouldEmitDeclareSimdVariantMetadata(const FunctionDecl *FD, + const SourceManager &SM) { + if (!FD) + return false; + + for (const FunctionDecl *Redecl : FD->redecls()) { + if (!Redecl->hasAttr<OMPDeclareSimdDeclAttr>()) + continue; + + unsigned BuiltinID = Redecl->getBuiltinID(); + if (BuiltinID && + Redecl->getASTContext().BuiltinInfo.isLibFunction(BuiltinID)) + return true; + + SourceLocation Loc = SM.getExpansionLoc(Redecl->getLocation()); + if (!Loc.isValid()) + continue; + + // Keep support for library-style declarations coming from headers that are + // not marked as system headers (e.g. staged glibc build directories), but + // avoid enabling this for every non-main-file declaration. + if (!SM.isWrittenInMainFile(Loc) && Redecl->hasExternalFormalLinkage()) + return true; + } + + return false; +} + // This are the Functions that are needed to mangle the name of the // vector functions generated by the compiler, according to the rules // defined in the "Vector Function ABI specifications for AArch64", @@ -11577,6 +11644,7 @@ void CGOpenMPRuntime::emitDeclareSimdFunction(const FunctionDecl *FD, llvm::Function *Fn) { ASTContext &C = CGM.getContext(); FD = FD->getMostRecentDecl(); + const FunctionDecl *MostRecentFD = FD; while (FD) { // Map params to their positions in function decl. llvm::DenseMap<const Decl *, unsigned> ParamPositions; @@ -11724,6 +11792,10 @@ void CGOpenMPRuntime::emitDeclareSimdFunction(const FunctionDecl *FD, } FD = FD->getPreviousDecl(); } + + if (shouldEmitDeclareSimdVariantMetadata( + MostRecentFD, CGM.getContext().getSourceManager())) + emitDeclareSimdVariantMetadata(CGM, Fn); } namespace { diff --git a/clang/test/OpenMP/declare_simd_preserve_builtin.cpp b/clang/test/OpenMP/declare_simd_preserve_builtin.cpp new file mode 100644 index 0000000000000..e4452257a2537 --- /dev/null +++ b/clang/test/OpenMP/declare_simd_preserve_builtin.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -ffast-math -fopenmp -emit-llvm %s -o - | FileCheck %s + +double sqrt(double); + +#pragma omp declare simd notinbranch +double sqrt(double); + +double test(double x) { + return sqrt(x); +} + +// CHECK-LABEL: define{{.*}}@_Z4testd( +// CHECK: call{{.*}}@_Z4sqrtd( +// CHECK-NOT: llvm.sqrt \ No newline at end of file From 9b1eed70c1225e95753e9bf1501e6d0fad293b86 Mon Sep 17 00:00:00 2001 From: Pincheng Wang <[email protected]> Date: Thu, 4 Jun 2026 19:44:25 +0800 Subject: [PATCH 2/4] [Clang][OpenMP] Mark math declare-simd libcalls as InaccessibleMemOnly When clang emits a libm math function declaration that carries a #pragma omp declare simd, conservatively tighten its memory effects to inaccessiblemem-only. These functions only touch the floating-point environment (rounding mode, exceptions, errno reporting); they do not read or write user-visible memory through their arguments. Functions whose result is written back through a pointer (sincos, modf, frexp, remquo, ...) are excluded so that their effect on user memory is preserved. The set is identified by the existing builtin attribute ConstIgnoringErrnoAndExceptions, with an additional guard that rejects any builtin taking a pointer parameter. This complements the loop-vectorizer changes for issue #120868 by removing the false dependence edges that previously prevented OpenMP SIMD loops containing standard math calls from being vectorized via their VFABI mappings under -fmath-errno. --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 34 +++++++++++++++++++ .../OpenMP/declare_simd_inaccessiblemem.c | 21 ++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 clang/test/OpenMP/declare_simd_inaccessiblemem.c diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 5626836669761..653d146d3059b 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -38,6 +38,7 @@ #include "llvm/IR/Value.h" #include "llvm/IR/VFABIDemangler.h" #include "llvm/Support/AtomicOrdering.h" +#include "llvm/Support/ModRef.h" #include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdint> @@ -11640,6 +11641,31 @@ static void emitAArch64DeclareSimdFunction( } } +// Returns true if FD names a standard libm math builtin whose only side +// effects are the floating-point environment (rounding mode, exceptions, and +// any implementation-defined errno reporting). Functions that write results +// back through pointer parameters (sincos, modf, frexp, remquo, ...) are +// explicitly excluded so that we never weaken their memory effects. +static bool shouldMarkInaccessibleMemOnlyForDeclareSimd(const FunctionDecl *FD, + ASTContext &Ctx) { + if (!FD) + return false; + unsigned BuiltinID = FD->getBuiltinID(); + if (!BuiltinID) + return false; + // ConstWithoutErrnoAndExceptions is set on the standard libm math builtins + // whose only side effects come from the floating-point environment + // (rounding mode, exceptions, errno reporting). + if (!Ctx.BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID)) + return false; + // sincos-style functions take output pointers; their effects on user-visible + // memory cannot be modeled as inaccessible-memory-only. + for (const ParmVarDecl *P : FD->parameters()) + if (P->getType()->isAnyPointerType()) + return false; + return true; +} + void CGOpenMPRuntime::emitDeclareSimdFunction(const FunctionDecl *FD, llvm::Function *Fn) { ASTContext &C = CGM.getContext(); @@ -11796,6 +11822,14 @@ void CGOpenMPRuntime::emitDeclareSimdFunction(const FunctionDecl *FD, if (shouldEmitDeclareSimdVariantMetadata( MostRecentFD, CGM.getContext().getSourceManager())) emitDeclareSimdVariantMetadata(CGM, Fn); + + // Tighten memory effects for libm math functions that are otherwise modelled + // as may-access-any-memory. The vectorizer relies on this to avoid treating + // these calls as dependence-blocking memory accesses in OpenMP SIMD loops. + if (shouldMarkInaccessibleMemOnlyForDeclareSimd(MostRecentFD, + CGM.getContext())) + Fn->setMemoryEffects(Fn->getMemoryEffects() & + llvm::MemoryEffects::inaccessibleMemOnly()); } namespace { diff --git a/clang/test/OpenMP/declare_simd_inaccessiblemem.c b/clang/test/OpenMP/declare_simd_inaccessiblemem.c new file mode 100644 index 0000000000000..eb9163183708b --- /dev/null +++ b/clang/test/OpenMP/declare_simd_inaccessiblemem.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O0 -fopenmp -fmath-errno \ +// RUN: -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s + +// Verify that libm math builtins declared with #pragma omp declare simd get +// memory(inaccessiblemem: readwrite). Functions that take output pointers +// (e.g. sincos) must NOT be tightened, because they write through user memory. + +#pragma omp declare simd notinbranch +double acosh(double); + +#pragma omp declare simd notinbranch linear(s) linear(c) +void sincos(double, double *s, double *c); + +double test_acosh(double x) { return acosh(x); } +void test_sincos(double x, double *s, double *c) { sincos(x, s, c); } + +// CHECK: declare double @acosh(double {{[^)]*}}) [[ACOSH_ATTR:#[0-9]+]] +// CHECK: declare void @sincos(double {{[^)]*}}, ptr {{[^)]*}}, ptr {{[^)]*}}) [[SINCOS_ATTR:#[0-9]+]] + +// CHECK: attributes [[ACOSH_ATTR]] = { {{.*}}memory(inaccessiblemem: readwrite){{.*}} } +// CHECK-NOT: attributes [[SINCOS_ATTR]] = { {{.*}}memory({{.*}} } From b9d14a7a53732480836fbd7c99de8f0639c71cbf Mon Sep 17 00:00:00 2001 From: Pincheng Wang <[email protected]> Date: Thu, 4 Jun 2026 23:16:17 +0800 Subject: [PATCH 3/4] [Clang][OpenMP] Tidy up declare-simd codegen and test nits Realign the BuiltinID lib-function continuation in CGOpenMPRuntime.cpp and drop the trailing whitespace git diff --check complained about. Add the missing final newline to declare_simd_preserve_builtin.cpp. The sincos CHECK-NOT in declare_simd_inaccessiblemem.c was matching any memory(...) attribute, which would start firing if an unrelated memory effect ever lands on the declaration. Narrow it to memory(inaccessiblemem ...) so the test only enforces what we actually care about. --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 4 ++-- clang/test/OpenMP/declare_simd_inaccessiblemem.c | 2 +- clang/test/OpenMP/declare_simd_preserve_builtin.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 653d146d3059b..6fd487caeaea2 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -11362,13 +11362,13 @@ static bool shouldEmitDeclareSimdVariantMetadata(const FunctionDecl *FD, unsigned BuiltinID = Redecl->getBuiltinID(); if (BuiltinID && - Redecl->getASTContext().BuiltinInfo.isLibFunction(BuiltinID)) + Redecl->getASTContext().BuiltinInfo.isLibFunction(BuiltinID)) return true; SourceLocation Loc = SM.getExpansionLoc(Redecl->getLocation()); if (!Loc.isValid()) continue; - + // Keep support for library-style declarations coming from headers that are // not marked as system headers (e.g. staged glibc build directories), but // avoid enabling this for every non-main-file declaration. diff --git a/clang/test/OpenMP/declare_simd_inaccessiblemem.c b/clang/test/OpenMP/declare_simd_inaccessiblemem.c index eb9163183708b..da357e7bacddb 100644 --- a/clang/test/OpenMP/declare_simd_inaccessiblemem.c +++ b/clang/test/OpenMP/declare_simd_inaccessiblemem.c @@ -18,4 +18,4 @@ void test_sincos(double x, double *s, double *c) { sincos(x, s, c); } // CHECK: declare void @sincos(double {{[^)]*}}, ptr {{[^)]*}}, ptr {{[^)]*}}) [[SINCOS_ATTR:#[0-9]+]] // CHECK: attributes [[ACOSH_ATTR]] = { {{.*}}memory(inaccessiblemem: readwrite){{.*}} } -// CHECK-NOT: attributes [[SINCOS_ATTR]] = { {{.*}}memory({{.*}} } +// CHECK-NOT: attributes [[SINCOS_ATTR]] = { {{.*}}memory(inaccessiblemem{{.*}} } diff --git a/clang/test/OpenMP/declare_simd_preserve_builtin.cpp b/clang/test/OpenMP/declare_simd_preserve_builtin.cpp index e4452257a2537..7b6a808de13da 100644 --- a/clang/test/OpenMP/declare_simd_preserve_builtin.cpp +++ b/clang/test/OpenMP/declare_simd_preserve_builtin.cpp @@ -11,4 +11,4 @@ double test(double x) { // CHECK-LABEL: define{{.*}}@_Z4testd( // CHECK: call{{.*}}@_Z4sqrtd( -// CHECK-NOT: llvm.sqrt \ No newline at end of file +// CHECK-NOT: llvm.sqrt From a0eb3f97987fc3c8d271987841de53bad5d65894 Mon Sep 17 00:00:00 2001 From: Pincheng Wang <[email protected]> Date: Thu, 4 Jun 2026 23:16:29 +0800 Subject: [PATCH 4/4] [Clang][OpenMP] clang-format declare-simd codegen Sort llvm/IR/VFABIDemangler.h before llvm/IR/Value.h and reflow the getOrInsertFunction call and the shouldEmitDeclareSimdVariantMetadata call so the touched lines match git clang-format. --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 6fd487caeaea2..ed5ccc5620e3d 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -35,8 +35,8 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/InstrTypes.h" -#include "llvm/IR/Value.h" #include "llvm/IR/VFABIDemangler.h" +#include "llvm/IR/Value.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/ModRef.h" #include "llvm/Support/raw_ostream.h" @@ -11332,7 +11332,8 @@ static void emitDeclareSimdVariantMetadata(CodeGenModule &CGM, llvm::FunctionType *VectorTy = llvm::VFABI::createFunctionType(*Info, Fn->getFunctionType()); llvm::Function *VecFn = llvm::cast<llvm::Function>( - Fn->getParent()->getOrInsertFunction(Info->VectorName, VectorTy) + Fn->getParent() + ->getOrInsertFunction(Info->VectorName, VectorTy) .getCallee()); CGM.addCompilerUsedGlobal(VecFn); VariantMappings.push_back(std::string(VariantName)); @@ -11819,8 +11820,8 @@ void CGOpenMPRuntime::emitDeclareSimdFunction(const FunctionDecl *FD, FD = FD->getPreviousDecl(); } - if (shouldEmitDeclareSimdVariantMetadata( - MostRecentFD, CGM.getContext().getSourceManager())) + if (shouldEmitDeclareSimdVariantMetadata(MostRecentFD, + CGM.getContext().getSourceManager())) emitDeclareSimdVariantMetadata(CGM, Fn); // Tighten memory effects for libm math functions that are otherwise modelled _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
