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 186a3cbdcfe11f98e64f64636a6c6eafadc18937 Mon Sep 17 00:00:00 2001 From: Pincheng Wang <[email protected]> Date: Thu, 4 Jun 2026 22:51:04 +0800 Subject: [PATCH 3/4] [Clang][OpenMP] Fix formatting and tighten declare-simd test checks - CGOpenMPRuntime.cpp: align the continuation of the BuiltinID lib-function check and drop trailing whitespace flagged by `git diff --check`. - declare_simd_preserve_builtin.cpp: terminate the file with a newline. - declare_simd_inaccessiblemem.c: make the sincos CHECK-NOT match the specific `memory(inaccessiblemem...)` effect we are guarding against, so the test does not start failing once an unrelated `memory(...)` attribute is added on sincos in the future. --- 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 f8b910166186fad640b51720ca06b6fdd5c109ee Mon Sep 17 00:00:00 2001 From: Pincheng Wang <[email protected]> Date: Thu, 4 Jun 2026 23:02:45 +0800 Subject: [PATCH 4/4] [Clang][OpenMP] Apply clang-format to declare-simd codegen changes - Reorder the llvm/IR/{VFABIDemangler,Value}.h includes alphabetically. - Reflow getOrInsertFunction call and shouldEmitDeclareSimdVariantMetadata call to match what `git clang-format` produces on the touched lines. --- 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
