[clang] [OpenMP][CodeGen] Preserve libcalls for declare simd redecls (PR #193881)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 23 19:29:46 PDT 2026
https://github.com/wpcwzy created https://github.com/llvm/llvm-project/pull/193881
This is PR 1/2 fixing issue #120868 ,where LLVM fails to utilize SIMD counterparts of standard math functions (such as acos, sin etc.) even when they are properly annotated with "#pragma omp declare simd" in system headers like glibc.
This PR inhibits lowering to LLVM math intrinsics (e.g. llvm.acos.*) when an "OMPDeclareSimdDeclAttr" is present. Emits the mapping attribute using "VFABI::MappingAttrName" to the function declaration itself when appropriate.
For OpenMP declare-simd flows, folding scalar math calls into LLVM math intrinsics can hide or bypass the expected vector-function mapping path. If any redeclaration carries "OMPDeclareSimdDeclAttr", we should preserve the scalar libcall form.
Test case for this new behaviour is added. Before submitting this PR, the LLVM unit tests, regression tests, llvm-test-suite are ran without failing.
>From a9fcb2faa6168d6259f1a29c9ec482823b36dee2 Mon Sep 17 00:00:00 2001
From: Pincheng Wang <pincheng.plct at isrc.iscas.ac.cn>
Date: Wed, 22 Apr 2026 22:30:19 +0800
Subject: [PATCH] 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
More information about the cfe-commits
mailing list