From d216a07e5abc61246ee82c77c900afa6706cf553 Mon Sep 17 00:00:00 2001 From: Tony Varghese Date: Sat, 18 Oct 2025 11:39:43 -0400 Subject: [PATCH 1/7] [PowerPC][AIX] Support #pragma comment copyright for AIX --- .../clang/Basic/DiagnosticParseKinds.td | 3 + clang/include/clang/Basic/PragmaKinds.h | 3 +- clang/lib/AST/TextNodeDumper.cpp | 3 + clang/lib/CodeGen/CodeGenModule.cpp | 28 ++++ clang/lib/CodeGen/CodeGenModule.h | 5 + clang/lib/Parse/ParsePragma.cpp | 26 +++- .../pragma-comment-copyright-aix-multi-lto.c | 110 +++++++++++++ .../PowerPC/pragma-comment-copyright-aix.c | 35 +++++ .../Transforms/Utils/CopyrightMetadataPass.h | 43 ++++++ llvm/lib/Passes/PassBuilder.cpp | 1 + llvm/lib/Passes/PassBuilderPipelines.cpp | 7 + llvm/lib/Passes/PassRegistry.def | 1 + llvm/lib/Transforms/Utils/CMakeLists.txt | 1 + .../Utils/CopyrightMetadataPass.cpp | 144 ++++++++++++++++++ .../PowerPC/pragma-comment-copyright-aix.ll | 51 +++++++ .../CopyrightMetadata/copyright-metadata.ll | 35 +++++ 16 files changed, 493 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-multi-lto.c create mode 100644 clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c create mode 100644 llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h create mode 100644 llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp create mode 100644 llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll create mode 100644 llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 9401377002223..fcbb1ab555619 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1368,6 +1368,9 @@ def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">; // PS4 recognizes only #pragma comment(lib) def warn_pragma_comment_ignored : Warning<"'#pragma comment %0' ignored">, InGroup; +def warn_pragma_comment_once : Warning<"'#pragma comment %0' " + "can be specified only once per source file - ignored">, + InGroup; // - #pragma detect_mismatch def err_pragma_detect_mismatch_malformed : Error< "pragma detect_mismatch is malformed; it requires two comma-separated " diff --git a/clang/include/clang/Basic/PragmaKinds.h b/clang/include/clang/Basic/PragmaKinds.h index 42f049f7323d2..52ca58855d460 100644 --- a/clang/include/clang/Basic/PragmaKinds.h +++ b/clang/include/clang/Basic/PragmaKinds.h @@ -17,7 +17,8 @@ enum PragmaMSCommentKind { PCK_Lib, // #pragma comment(lib, ...) PCK_Compiler, // #pragma comment(compiler, ...) PCK_ExeStr, // #pragma comment(exestr, ...) - PCK_User // #pragma comment(user, ...) + PCK_User, // #pragma comment(user, ...) + PCK_Copyright // #pragma comment(copyright, ...) }; enum PragmaMSStructKind { diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 7bc0404db1bee..c58c33f95c193 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -2526,6 +2526,9 @@ void TextNodeDumper::VisitPragmaCommentDecl(const PragmaCommentDecl *D) { case PCK_User: OS << "user"; break; + case PCK_Copyright: + OS << "copyright"; + break; } StringRef Arg = D->getArg(); if (!Arg.empty()) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index a6a1b84e278b9..3da6be86d216c 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1569,6 +1569,14 @@ void CodeGenModule::Release() { EmitBackendOptionsMetadata(getCodeGenOpts()); + // Emit copyright metadata for AIX + if (!AIXCopyrightComment.empty()) { + auto *NMD = + getModule().getOrInsertNamedMetadata("aix.copyright.comment"); + for (auto *MD : AIXCopyrightComment) + NMD->addOperand(MD); + } + // If there is device offloading code embed it in the host now. EmbedObject(&getModule(), CodeGenOpts, *getFileSystem(), getDiags()); @@ -3402,6 +3410,23 @@ void CodeGenModule::AddDependentLib(StringRef Lib) { LinkerOptionsMetadata.push_back(llvm::MDNode::get(C, MDOpts)); } +/// Process the #pragma comment(copyright, " copy right string ") +/// and create llvm metadata for the copyrgiht +void CodeGenModule::ProcessPragmaCommentCopyright(StringRef Comment) { + + // Pragma Comment Copyright is enabled only when: + // - OS is AIX + // - Comment is non empty + if (!getTriple().isOSAIX() || Comment.empty()) + return; + + // Create llvm metadata with the comment string + auto &C = getLLVMContext(); + llvm::Metadata *Ops[] = {llvm::MDString::get(C, Comment.str())}; + auto *Node = llvm::MDNode::get(C, Ops); + AIXCopyrightComment.push_back(Node); // This should be available during the runtime +} + /// Add link options implied by the given module, including modules /// it depends on, using a postorder walk. static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod, @@ -7579,6 +7604,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case PCK_Lib: AddDependentLib(PCD->getArg()); break; + case PCK_Copyright: + ProcessPragmaCommentCopyright(PCD->getArg()); + break; case PCK_Compiler: case PCK_ExeStr: case PCK_User: diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index a253bcda2d06c..e6cd9ca10f344 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -587,6 +587,9 @@ class CodeGenModule : public CodeGenTypeCache { /// A vector of metadata strings for dependent libraries for ELF. SmallVector ELFDependentLibraries; + /// A vector of metadata strings for copyright comment for AIX + SmallVector AIXCopyrightComment; + /// @name Cache for Objective-C runtime types /// @{ @@ -1458,6 +1461,8 @@ class CodeGenModule : public CodeGenTypeCache { /// Appends a dependent lib to the appropriate metadata value. void AddDependentLib(StringRef Lib); + /// Append AIX copyright comment to the module-level metadata. + void ProcessPragmaCommentCopyright(StringRef Comment); llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD); diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 7c2b9280f0b76..655e64674b866 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -473,7 +473,8 @@ void Parser::initializePragmaHandlers() { PP.AddPragmaHandler(OpenACCHandler.get()); if (getLangOpts().MicrosoftExt || - getTargetInfo().getTriple().isOSBinFormatELF()) { + getTargetInfo().getTriple().isOSBinFormatELF() || + getTargetInfo().getTriple().isOSAIX()) { MSCommentHandler = std::make_unique(Actions); PP.AddPragmaHandler(MSCommentHandler.get()); } @@ -595,7 +596,8 @@ void Parser::resetPragmaHandlers() { OpenACCHandler.reset(); if (getLangOpts().MicrosoftExt || - getTargetInfo().getTriple().isOSBinFormatELF()) { + getTargetInfo().getTriple().isOSBinFormatELF() || + getTargetInfo().getTriple().isOSAIX()) { PP.RemovePragmaHandler(MSCommentHandler.get()); MSCommentHandler.reset(); } @@ -3208,6 +3210,7 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, .Case("compiler", PCK_Compiler) .Case("exestr", PCK_ExeStr) .Case("user", PCK_User) + .Case("copyright", PCK_Copyright) .Default(PCK_Unknown); if (Kind == PCK_Unknown) { PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); @@ -3220,6 +3223,19 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, return; } + // pragma comment copyright can each appear only once in a TU. + if (PP.getTargetInfo().getTriple().isOSAIX()) { + static bool SeenAIXCopyright = false; + if (Kind == PCK_Copyright) { + if (SeenAIXCopyright) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_once) + << II->getName(); + return; + } + SeenAIXCopyright = true; + } + } + // Read the optional string if present. PP.Lex(Tok); std::string ArgumentString; @@ -3246,6 +3262,12 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, return; } + if (PP.getTargetInfo().getTriple().isOSAIX()) { + // Accept and ignore well-formed copyright with empty string. + if(Kind == PCK_Copyright && ArgumentString.empty()) + return; + } + // If the pragma is lexically sound, notify any interested PPCallbacks. if (PP.getPPCallbacks()) PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString); diff --git a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-multi-lto.c b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-multi-lto.c new file mode 100644 index 0000000000000..ebba95742c21b --- /dev/null +++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-multi-lto.c @@ -0,0 +1,110 @@ +// REQUIRES: powerpc-registered-target, system-aix, clang +// +// This test verifies correct handling of `#pragma comment(copyright, ...)` +// on AIX for multiple Translation Units (TUs). +// +// Each TU defines one `#pragma comment(copyright, "...")` which should: +// - Generate a unique read-only `__llvm_copyright` csect containing the string. +// - Create a `.ref` directive from at least one function in that TU to the +// corresponding copyright symbol. +// - Preserve these copyright strings across LTO and ThinLTO linking. +// +// ----------------------------------------------------------------------------- +// Build WITHOUT LTO +// ----------------------------------------------------------------------------- +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/file1.c -o %t/file1.bc +// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/file2.c -o %t/file2.bc +// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/file3.c -o %t/file3.bc +// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/main.c -o %t/main.bc +// +// Compile each bitcode file to XCOFF object and link them together: +// RUN: %clang -c %t/file1.bc -o %t/file1.o +// RUN: %clang -c %t/file2.bc -o %t/file2.o +// RUN: %clang -c %t/file3.bc -o %t/file3.o +// RUN: %clang -c %t/main.bc -o %t/main.o +// RUN: %clang %t/file1.o %t/file2.o %t/file3.o %t/main.o -o %t/nonlto.exe +// +// Verify assembly emission and linked outputs: +// RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t/file1.bc -o - | FileCheck %s --check-prefix=CHECK-ASM +// RUN: /bin/strings -a %t/nonlto.exe | FileCheck %s --check-prefix=CHECK-STRINGS +// RUN: llvm-nm %t/nonlto.exe | FileCheck %s --check-prefix=CHECK-NM +// RUN: llvm-objdump -r %t/nonlto.exe | FileCheck %s --check-prefix=CHECK-OBJDUMP +// +// ----------------------------------------------------------------------------- +// Build WITH Full LTO +// ----------------------------------------------------------------------------- +// RUN: %clang -flto %t/file1.bc %t/file2.bc %t/file3.bc %t/main.bc -o %t/lto.exe +// RUN: /bin/strings -a %t/lto.exe | FileCheck %s --check-prefix=CHECK-STRINGS +// RUN: llvm-nm %t/lto.exe | FileCheck %s --check-prefix=CHECK-NM +// RUN: llvm-objdump -r %t/lto.exe | FileCheck %s --check-prefix=CHECK-OBJDUMP +// +// ----------------------------------------------------------------------------- +// Build WITH ThinLTO +// ----------------------------------------------------------------------------- +// RUN: %clang -flto=thin %t/file1.bc %t/file2.bc %t/file3.bc %t/main.bc -o %t/lto-thin.exe +// RUN: /bin/strings -a %t/lto-thin.exe | FileCheck %s --check-prefix=CHECK-STRINGS +// RUN: llvm-nm %t/lto-thin.exe | FileCheck %s --check-prefix=CHECK-NM +// RUN: llvm-objdump -r %t/lto-thin.exe | FileCheck %s --check-prefix=CHECK-OBJDUMP +// +// ----------------------------------------------------------------------------- +// Assembly Checks (for a single TU) +// ----------------------------------------------------------------------------- +// +// Verify that the backend: +// - Emits a `.ref` directive to tie the string to the TU +// - Emits the string in a dedicated read-only csect +// +// CHECK-ASM: .ref __aix_copyright_str +// CHECK-ASM: .csect __llvm_copyright[RO],2 +// CHECK-ASM-NEXT: .lglobl __aix_copyright_str +// CHECK-ASM: __aix_copyright_str +// CHECK-ASM: .string "Copyright 2025 TU A" +// +// ----------------------------------------------------------------------------- +// Final Binary Checks +// ----------------------------------------------------------------------------- +// +// Ensure all TUs’ copyright strings are preserved. +// CHECK-STRINGS-DAG: Copyright 2025 TU A +// CHECK-STRINGS-DAG: Copyright 2025 TU B +// CHECK-STRINGS-DAG: Copyright 2025 TU C +// CHECK-STRINGS-DAG: Copyright 2025 Main Program +// +// Check that the symbols are visible in the binary symbol table. +// CHECK-NM: t __aix_copyright_str +// CHECK-NM: t __llvm_copyright +// +// Ensure there’s a relocation record referencing the copyright symbol. +// CHECK-OBJDUMP-LABEL: RELOCATION RECORDS FOR [.text] +// CHECK-OBJDUMP: R_REF __aix_copyright_str +// + +//=== file1.c === +//--- file1.c +#pragma comment(copyright, "Copyright 2025 TU A") +void func1(void) {} + +//=== file2.c === +//--- file2.c +#pragma comment(copyright, "Copyright 2025 TU B") +void func2(void) {} + +//=== file3.c === +//--- file3.c +#pragma comment(copyright, "Copyright 2025 TU C") +void func3(void) {} + +//=== main.c === +//--- main.c +#pragma comment(copyright, "Copyright 2025 Main Program") +void func1(void); +void func2(void); +void func3(void); +int main(void) { + func1(); + func2(); + func3(); + return 0; +} diff --git a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c new file mode 100644 index 0000000000000..43f085f3cf459 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c @@ -0,0 +1,35 @@ +// REQUIRES: powerpc-registered-target, system-aix +// RUN: %clang_cc1 %s -triple powerpc-ibm-aix -O0 -disable-llvm-passes -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix -O0 -disable-llvm-passes -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple powerpc-ibm-aix -verify +// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix -verify +// RUN: %clang_cc1 %s -DTEST_EMPTY_COPYRIGHT -triple powerpc-ibm-aix -verify + +// RUN: %clang_cc1 %s -x c++ -triple powerpc-ibm-aix -O0 -disable-llvm-passes -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -x c++ -triple powerpc64-ibm-aix -O0 -disable-llvm-passes -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -x c++ -triple powerpc-ibm-aix -verify +// RUN: %clang_cc1 %s -x c++ -triple powerpc64-ibm-aix -verify +// RUN: %clang_cc1 %s -x c++ -DTEST_EMPTY_COPYRIGHT -triple powerpc-ibm-aix -verify + +#ifndef TEST_EMPTY_COPYRIGHT +// Test basic pragma comment types +#pragma comment(copyright, "@(#) Copyright") + +// Test duplicate copyright - should warn and ignore +#pragma comment(copyright, "Duplicate Copyright") // expected-warning {{'#pragma comment copyright' can be specified only once per source file - ignored}} + +int main() { return 0; } + +// Check that both metadata sections are present +// CHECK: !aix.copyright.comment = !{![[copyright:[0-9]+]]} + +// Check individual metadata content +// CHECK: ![[copyright]] = !{!"@(#) Copyright"} + +#else +// Test empty copyright string - valid with no warning +#pragma comment(copyright, "") // expected-no-diagnostics + +int main() { return 0; } + +#endif \ No newline at end of file diff --git a/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h b/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h new file mode 100644 index 0000000000000..2da265de81fd2 --- /dev/null +++ b/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h @@ -0,0 +1,43 @@ +//===-- CopyrightMetadataPass.h - Lower AIX copyright metadata -*- 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 +// +//===----------------------------------------------------------------------===// +// +// The CopyrightMetadataPass lowers the module-level metadata emitted by Clang +// for `#pragma comment(copyright, "...")` on AIX: +// +// !aix.copyright.comment = !{!"Copyright ..."} +// +// into an internal constant string global that is preserved across all compiler +// and linker stages. Each translation unit produces one TU-local string symbol +// (`__aix_copyright_str`), and the pass attaches `!implicit.ref` metadata to +// defined functions referencing this symbol. The PowerPC AIX backend recognizes +// this metadata and emits `.ref` directives in the XCOFF assembly, ensuring the +// copyright strings: +// +// • survive optimization and LTO, +// • are not removed by linker garbage collection, and +// • remain visible in the final binary. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H +#define LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { +class CopyrightMetadataPass : public PassInfoMixin { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); + + static bool isRequired() { return true; } +}; + + +} // namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_WYVERN_COPYRIGHTMETADATAPASS_H \ No newline at end of file diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index f5281ea69b512..24526d9f973ff 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -347,6 +347,7 @@ #include "llvm/Transforms/Utils/BreakCriticalEdges.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h" +#include "llvm/Transforms/Utils/CopyrightMetadataPass.h" #include "llvm/Transforms/Utils/CountVisits.h" #include "llvm/Transforms/Utils/DXILUpgrade.h" #include "llvm/Transforms/Utils/Debugify.h" diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index c6beb3fdf09bd..cd6cd126ef2bb 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -135,6 +135,7 @@ #include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/AssumeBundleBuilder.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" +#include "llvm/Transforms/Utils/CopyrightMetadataPass.h" #include "llvm/Transforms/Utils/CountVisits.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/ExtraPassManager.h" @@ -1454,6 +1455,9 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, const bool LTOPreLink = isLTOPreLink(LTOPhase); ModulePassManager MPM; + // Process copyright metadata early, before any optimizations + MPM.addPass(CopyrightMetadataPass()); + // Run partial inlining pass to partially inline functions that have // large bodies. if (RunPartialInlining) @@ -2274,6 +2278,9 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level, ModulePassManager MPM; + // Process copyright metadata at O0 before any other transformations + MPM.addPass(CopyrightMetadataPass()); + // Perform pseudo probe instrumentation in O0 mode. This is for the // consistency between different build modes. For example, a LTO build can be // mixed with an O0 prelink and an O2 postlink. Loading a sample profile in diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 074c328ef0931..3f60ce0734a33 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -61,6 +61,7 @@ MODULE_PASS("check-debugify", NewPMCheckDebugifyPass()) MODULE_PASS("constmerge", ConstantMergePass()) MODULE_PASS("coro-cleanup", CoroCleanupPass()) MODULE_PASS("coro-early", CoroEarlyPass()) +MODULE_PASS("copyright-metadata", CopyrightMetadataPass()) MODULE_PASS("cross-dso-cfi", CrossDSOCFIPass()) MODULE_PASS("ctx-instr-gen", PGOInstrumentationGen(PGOInstrumentationType::CTXPROF)) diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt index f367ca2fdf56b..13643e9f411b9 100644 --- a/llvm/lib/Transforms/Utils/CMakeLists.txt +++ b/llvm/lib/Transforms/Utils/CMakeLists.txt @@ -17,6 +17,7 @@ add_llvm_component_library(LLVMTransformUtils CodeLayout.cpp CodeMoverUtils.cpp ControlFlowUtils.cpp + CopyrightMetadataPass.cpp CtorUtils.cpp CountVisits.cpp Debugify.cpp diff --git a/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp b/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp new file mode 100644 index 0000000000000..4d594f7ba5936 --- /dev/null +++ b/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp @@ -0,0 +1,144 @@ +//===-- CopyrightMetadataPass.cpp - Lower AIX copyright metadata ----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This pass lowers module-level copyright metadata emitted by Clang: +// +// !aix.copyright.comment = !{!"Copyright ..."} +// +// into concrete, translation-unit–local globals to ensure that copyright +// strings: +// +// • survive all optimization and LTO pipelines, +// • are not removed by linker garbage collection, and +// • remain visible in the final XCOFF binary. +// +// For each module (translation unit), the pass performs the following: +// +// 1. Creates a null-terminated, internal constant string global +// (`__aix_copyright_str`) containing the copyright text. +// +// 2. Marks the string in `llvm.used` so it cannot be dropped by +// optimization or LTO. +// +// 3. Attaches `!implicit.ref` metadata referencing the string to every +// defined function in the module. The PowerPC AIX backend recognizes +// this metadata and emits a `.ref` directive from the function to the +// string, creating a concrete relocation that prevents the linker from +// discarding it. +// +//===----------------------------------------------------------------------===// + + +#include "llvm/Transforms/Utils/CopyrightMetadataPass.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/TargetParser/Triple.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +#define DEBUG_TYPE "copyright-metadata" + +using namespace llvm; + +namespace llvm { + +static cl::opt + DisableCopyrightMetadata("disable-copyright-metadata", cl::ReallyHidden, + cl::desc("Disable copyright metadata pass."), + cl::init(false)); + +static bool isAIXTriple(const Module &M) { + return Triple(M.getTargetTriple()).isOSAIX(); +} + +PreservedAnalyses CopyrightMetadataPass::run(Module &M, + ModuleAnalysisManager &AM) { + if (DisableCopyrightMetadata || !isAIXTriple(M)) + return PreservedAnalyses::all(); + + LLVMContext &Ctx = M.getContext(); + + // Single-metadata: !aix.copyright.comment = !{!0} + // Each operand node is expected to have one MDString operand. + NamedMDNode *MD = M.getNamedMetadata("aix.copyright.comment"); + if (!MD || MD->getNumOperands() == 0) + return PreservedAnalyses::all(); + + // At this point we are guarateed that one TU contains a single copyright + // metadata entry. Create TU-local string global for that metadata entry. + MDNode *MdNode = MD->getOperand(0); + if (!MdNode || MdNode->getNumOperands() == 0) + return PreservedAnalyses::all(); + + auto *MdString = dyn_cast_or_null(MdNode->getOperand(0)); + if (!MdString) + return PreservedAnalyses::all(); + + StringRef Text = MdString->getString(); + if (Text.empty()) + return PreservedAnalyses::all(); + + // 1. Create a single NULL-terminated string global + Constant *StrInit = ConstantDataArray::getString(Ctx, Text, /*AddNull=*/true); + + // Internal, constant, TU-local — avoids duplicate symbol issues across TUs. + auto *StrGV = new GlobalVariable(M, StrInit->getType(), + /*isConstant=*/true, + GlobalValue::InternalLinkage, StrInit, + /*Name=*/"__aix_copyright_str"); + StrGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + StrGV->setAlignment(Align(1)); + StrGV->setSection("__llvm_copyright"); + + // 2. Ensure LLVM doesn't delete it (through all pipelines/LTO). + appendToUsed(M, {StrGV}); + // appendToCompilerUsed(M, {StrGV}); + + // 3. Attach !implicit ref to every defined function + // Create a metadata node pointing to the copyright string: + // !N = !{ptr @__aix_copyright_str} + Metadata *Ops[] = {ConstantAsMetadata::get(StrGV)}; + auto *ValMD = ValueAsMetadata::get(StrGV); + MDNode *ImplicitRefMD = MDNode::get(Ctx, Ops); + + auto addImplicitRef = [&](Function &F) { + if (F.isDeclaration()) + return; + // Attach the implicit.ref metadata to the function + F.setMetadata("implicit.ref", ImplicitRefMD); + LLVM_DEBUG(dbgs() << "[copyright] attached implicit.ref to function: " + << F.getName() << "\n"); + }; + + for (Function &F : M) + addImplicitRef(F); + + // Remove the original metadata since we've processed it + // This prevents reprocessing if the pass runs multiple times + MD->eraseFromParent(); + LLVM_DEBUG(dbgs() << "[copyright] created string and anchor for module\n"); + + return PreservedAnalyses::all(); +} + +} // namespace llvm \ No newline at end of file diff --git a/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll b/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll new file mode 100644 index 0000000000000..d73a5642c107e --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll @@ -0,0 +1,51 @@ +; REQUIRES: powerpc-registered-target, system-aix + +; Ensure the CopyrightMetadataPass (direct-byte variant) materializes +; a TU-local string and forces a text→data relocation via a tiny ctor, +; so the AIX/XCOFF linker keeps the string alive. + +; Build IR with the pass: +; RUN: opt -passes=copyright-metadata %s -o %t.bc + +; ---------------- 32-bit AIX ---------------- +; RUN: llc -mtriple=powerpc-ibm-aix -filetype=obj -o %t32.o %t.bc +; RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t.bc -o - | FileCheck %s --check-prefix=CHECK-ASM + +; Symbol table should show our TU-local names (locals are listed with -t). +; RUN: llvm-objdump -t %t32.o | FileCheck %s --check-prefix=CHECK-SYMS + +; Relocations should reference the string (due to the volatile byte load). +; RUN: llvm-objdump -r %t32.o | FileCheck %s --check-prefix=CHECK-REL + +; ---------------- 64-bit AIX ---------------- +; RUN: llc -mtriple=powerpc64-ibm-aix -filetype=obj -o %t64.o %t.bc +; RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t.bc -o - | FileCheck %s --check-prefix=CHECK-ASM +; RUN: llvm-objdump -t %t64.o | FileCheck %s --check-prefix=CHECK-SYMS +; RUN: llvm-objdump -r %t64.o | FileCheck %s --check-prefix=CHECK-REL + +target triple = "powerpc-ibm-aix" + +define i32 @main() { entry: ret i32 0 } + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"wchar_size", i32 2} +!aix.copyright.comment = !{!1} +!1 = !{!"Copyright IBM"} + +; Assembly Checks (for a single TU) +; Verify that the backend: +; - Emits a `.ref` directive to tie the string to the TU +; - Emits the string in a dedicated read-only csect +; +; CHECK-ASM: .ref __aix_copyright_str +; CHECK-ASM: .csect __llvm_copyright[RO],2 +; CHECK-ASM-NEXT: .lglobl __aix_copyright_str +; CHECK-ASM: __aix_copyright_str +; CHECK-ASM: .string "Copyright IBM" + +; TU-local globals/functions should be present in the symbol table +; CHECK-SYMS: __aix_copyright_str + +; Relocation in the object should target the string (from the ctor’s volatile load) +; CHECK-LABEL: RELOCATION RECORDS FOR [.text] +; CHECK-REL: __aix_copyright_str \ No newline at end of file diff --git a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll new file mode 100644 index 0000000000000..5ddcd84e97ca3 --- /dev/null +++ b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll @@ -0,0 +1,35 @@ +; RUN: opt -passes=copyright-metadata -S %s -o - | FileCheck %s + +; Verify the pass converts !aix.copyright.comment into: +; - internal constant string global +; - marks it in llvm.used and llvm.compiler.used +; - creates an internal anchor function and registers it in llvm.global_ctors + +target triple = "powerpc-ibm-aix" + +define void @f0() { +entry: + ret void +} +define i32 @main() { +entry: + ret i32 0 +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"wchar_size", i32 2} + +!aix.copyright.comment = !{!1} +!1 = !{!"@(#) Copyright IBM 2025"} + + +; ---- Globals-------------------------------------------- +; CHECK: @__aix_copyright_str = internal unnamed_addr constant [24 x i8] c"@(#) Copyright IBM 2025\00", section "__llvm_copyright", align 1 +; Preservation in used sets +; CHECK-NEXT: @llvm.used = appending global [1 x ptr] [ptr @__aix_copyright_str], section "llvm.metadata" +; CHECK-NOT: ![[copyright:[0-9]+]] = !{!"@(#) Copyright IBM 2025"} + +; Function has an implicit ref MD pointing at the string: +; CHECK: define void @f0() !implicit.ref ![[MD:[0-9]+]] +; CHECK: define i32 @main() !implicit.ref ![[MD]] +; CHECK: ![[MD]] = !{ptr @__aix_copyright_str} \ No newline at end of file From ed469d43c7151c6b9f9d87ac9c75ec529d48c660 Mon Sep 17 00:00:00 2001 From: Tony Varghese Date: Tue, 21 Oct 2025 09:56:06 -0400 Subject: [PATCH 2/7] Addressed the review comments. removed redundant tests --- .../clang/Basic/DiagnosticParseKinds.td | 2 +- clang/lib/CodeGen/CodeGenModule.cpp | 20 ++-- clang/lib/CodeGen/CodeGenModule.h | 7 +- clang/lib/Parse/ParsePragma.cpp | 8 +- .../pragma-comment-copyright-aix-multi-lto.c | 110 ------------------ .../PowerPC/pragma-comment-copyright-aix.c | 3 +- .../Transforms/Utils/CopyrightMetadataPass.h | 20 +--- .../Utils/CopyrightMetadataPass.cpp | 60 ++++++---- .../PowerPC/pragma-comment-copyright-aix.ll | 51 -------- .../CopyrightMetadata/copyright-metadata.ll | 45 +++++-- 10 files changed, 90 insertions(+), 236 deletions(-) delete mode 100644 clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-multi-lto.c delete mode 100644 llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index fcbb1ab555619..ee59b6469eee3 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1369,7 +1369,7 @@ def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">; def warn_pragma_comment_ignored : Warning<"'#pragma comment %0' ignored">, InGroup; def warn_pragma_comment_once : Warning<"'#pragma comment %0' " - "can be specified only once per source file - ignored">, + "can be specified only once per translation unit - ignored">, InGroup; // - #pragma detect_mismatch def err_pragma_detect_mismatch_malformed : Error< diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 3da6be86d216c..38d6447e7e0df 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1570,11 +1570,9 @@ void CodeGenModule::Release() { EmitBackendOptionsMetadata(getCodeGenOpts()); // Emit copyright metadata for AIX - if (!AIXCopyrightComment.empty()) { - auto *NMD = - getModule().getOrInsertNamedMetadata("aix.copyright.comment"); - for (auto *MD : AIXCopyrightComment) - NMD->addOperand(MD); + if (AIXCopyrightComment) { + auto *NMD = getModule().getOrInsertNamedMetadata("aix.copyright.comment"); + NMD->addOperand(AIXCopyrightComment); } // If there is device offloading code embed it in the host now. @@ -3410,21 +3408,19 @@ void CodeGenModule::AddDependentLib(StringRef Lib) { LinkerOptionsMetadata.push_back(llvm::MDNode::get(C, MDOpts)); } -/// Process the #pragma comment(copyright, " copy right string ") -/// and create llvm metadata for the copyrgiht +/// Process the #pragma comment(copyright, "copyright string ") +/// and create llvm metadata for the copyright void CodeGenModule::ProcessPragmaCommentCopyright(StringRef Comment) { - // Pragma Comment Copyright is enabled only when: - // - OS is AIX - // - Comment is non empty - if (!getTriple().isOSAIX() || Comment.empty()) + if (!getTriple().isOSAIX()) return; // Create llvm metadata with the comment string auto &C = getLLVMContext(); llvm::Metadata *Ops[] = {llvm::MDString::get(C, Comment.str())}; auto *Node = llvm::MDNode::get(C, Ops); - AIXCopyrightComment.push_back(Node); // This should be available during the runtime + if(!AIXCopyrightComment) + AIXCopyrightComment = Node; } /// Add link options implied by the given module, including modules diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index e6cd9ca10f344..bb71575309b6e 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -587,8 +587,9 @@ class CodeGenModule : public CodeGenTypeCache { /// A vector of metadata strings for dependent libraries for ELF. SmallVector ELFDependentLibraries; - /// A vector of metadata strings for copyright comment for AIX - SmallVector AIXCopyrightComment; + /// Single module-level copyright comment for AIX (if any). + /// We only ever accept one per TU. + llvm::MDNode *AIXCopyrightComment = nullptr; /// @name Cache for Objective-C runtime types /// @{ @@ -1461,7 +1462,7 @@ class CodeGenModule : public CodeGenTypeCache { /// Appends a dependent lib to the appropriate metadata value. void AddDependentLib(StringRef Lib); - /// Append AIX copyright comment to the module-level metadata. + /// Record the AIX copyright comment in module-level metadata. void ProcessPragmaCommentCopyright(StringRef Comment); llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD); diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 655e64674b866..6bcc799402e07 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -236,6 +236,7 @@ struct PragmaCommentHandler : public PragmaHandler { private: Sema &Actions; + bool SeenAIXCopyright = false; // TU-scoped }; struct PragmaDetectMismatchHandler : public PragmaHandler { @@ -3223,17 +3224,14 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, return; } - // pragma comment copyright can each appear only once in a TU. - if (PP.getTargetInfo().getTriple().isOSAIX()) { - static bool SeenAIXCopyright = false; - if (Kind == PCK_Copyright) { + // On AIX, pragma comment copyright can each appear only once in a TU. + if (PP.getTargetInfo().getTriple().isOSAIX() && Kind == PCK_Copyright) { if (SeenAIXCopyright) { PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_once) << II->getName(); return; } SeenAIXCopyright = true; - } } // Read the optional string if present. diff --git a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-multi-lto.c b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-multi-lto.c deleted file mode 100644 index ebba95742c21b..0000000000000 --- a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-multi-lto.c +++ /dev/null @@ -1,110 +0,0 @@ -// REQUIRES: powerpc-registered-target, system-aix, clang -// -// This test verifies correct handling of `#pragma comment(copyright, ...)` -// on AIX for multiple Translation Units (TUs). -// -// Each TU defines one `#pragma comment(copyright, "...")` which should: -// - Generate a unique read-only `__llvm_copyright` csect containing the string. -// - Create a `.ref` directive from at least one function in that TU to the -// corresponding copyright symbol. -// - Preserve these copyright strings across LTO and ThinLTO linking. -// -// ----------------------------------------------------------------------------- -// Build WITHOUT LTO -// ----------------------------------------------------------------------------- -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/file1.c -o %t/file1.bc -// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/file2.c -o %t/file2.bc -// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/file3.c -o %t/file3.bc -// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/main.c -o %t/main.bc -// -// Compile each bitcode file to XCOFF object and link them together: -// RUN: %clang -c %t/file1.bc -o %t/file1.o -// RUN: %clang -c %t/file2.bc -o %t/file2.o -// RUN: %clang -c %t/file3.bc -o %t/file3.o -// RUN: %clang -c %t/main.bc -o %t/main.o -// RUN: %clang %t/file1.o %t/file2.o %t/file3.o %t/main.o -o %t/nonlto.exe -// -// Verify assembly emission and linked outputs: -// RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t/file1.bc -o - | FileCheck %s --check-prefix=CHECK-ASM -// RUN: /bin/strings -a %t/nonlto.exe | FileCheck %s --check-prefix=CHECK-STRINGS -// RUN: llvm-nm %t/nonlto.exe | FileCheck %s --check-prefix=CHECK-NM -// RUN: llvm-objdump -r %t/nonlto.exe | FileCheck %s --check-prefix=CHECK-OBJDUMP -// -// ----------------------------------------------------------------------------- -// Build WITH Full LTO -// ----------------------------------------------------------------------------- -// RUN: %clang -flto %t/file1.bc %t/file2.bc %t/file3.bc %t/main.bc -o %t/lto.exe -// RUN: /bin/strings -a %t/lto.exe | FileCheck %s --check-prefix=CHECK-STRINGS -// RUN: llvm-nm %t/lto.exe | FileCheck %s --check-prefix=CHECK-NM -// RUN: llvm-objdump -r %t/lto.exe | FileCheck %s --check-prefix=CHECK-OBJDUMP -// -// ----------------------------------------------------------------------------- -// Build WITH ThinLTO -// ----------------------------------------------------------------------------- -// RUN: %clang -flto=thin %t/file1.bc %t/file2.bc %t/file3.bc %t/main.bc -o %t/lto-thin.exe -// RUN: /bin/strings -a %t/lto-thin.exe | FileCheck %s --check-prefix=CHECK-STRINGS -// RUN: llvm-nm %t/lto-thin.exe | FileCheck %s --check-prefix=CHECK-NM -// RUN: llvm-objdump -r %t/lto-thin.exe | FileCheck %s --check-prefix=CHECK-OBJDUMP -// -// ----------------------------------------------------------------------------- -// Assembly Checks (for a single TU) -// ----------------------------------------------------------------------------- -// -// Verify that the backend: -// - Emits a `.ref` directive to tie the string to the TU -// - Emits the string in a dedicated read-only csect -// -// CHECK-ASM: .ref __aix_copyright_str -// CHECK-ASM: .csect __llvm_copyright[RO],2 -// CHECK-ASM-NEXT: .lglobl __aix_copyright_str -// CHECK-ASM: __aix_copyright_str -// CHECK-ASM: .string "Copyright 2025 TU A" -// -// ----------------------------------------------------------------------------- -// Final Binary Checks -// ----------------------------------------------------------------------------- -// -// Ensure all TUs’ copyright strings are preserved. -// CHECK-STRINGS-DAG: Copyright 2025 TU A -// CHECK-STRINGS-DAG: Copyright 2025 TU B -// CHECK-STRINGS-DAG: Copyright 2025 TU C -// CHECK-STRINGS-DAG: Copyright 2025 Main Program -// -// Check that the symbols are visible in the binary symbol table. -// CHECK-NM: t __aix_copyright_str -// CHECK-NM: t __llvm_copyright -// -// Ensure there’s a relocation record referencing the copyright symbol. -// CHECK-OBJDUMP-LABEL: RELOCATION RECORDS FOR [.text] -// CHECK-OBJDUMP: R_REF __aix_copyright_str -// - -//=== file1.c === -//--- file1.c -#pragma comment(copyright, "Copyright 2025 TU A") -void func1(void) {} - -//=== file2.c === -//--- file2.c -#pragma comment(copyright, "Copyright 2025 TU B") -void func2(void) {} - -//=== file3.c === -//--- file3.c -#pragma comment(copyright, "Copyright 2025 TU C") -void func3(void) {} - -//=== main.c === -//--- main.c -#pragma comment(copyright, "Copyright 2025 Main Program") -void func1(void); -void func2(void); -void func3(void); -int main(void) { - func1(); - func2(); - func3(); - return 0; -} diff --git a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c index 43f085f3cf459..68e599ca577ce 100644 --- a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c +++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c @@ -1,4 +1,3 @@ -// REQUIRES: powerpc-registered-target, system-aix // RUN: %clang_cc1 %s -triple powerpc-ibm-aix -O0 -disable-llvm-passes -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 %s -triple powerpc64-ibm-aix -O0 -disable-llvm-passes -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 %s -triple powerpc-ibm-aix -verify @@ -16,7 +15,7 @@ #pragma comment(copyright, "@(#) Copyright") // Test duplicate copyright - should warn and ignore -#pragma comment(copyright, "Duplicate Copyright") // expected-warning {{'#pragma comment copyright' can be specified only once per source file - ignored}} +#pragma comment(copyright, "Duplicate Copyright") // expected-warning {{'#pragma comment copyright' can be specified only once per translation unit - ignored}} int main() { return 0; } diff --git a/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h b/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h index 2da265de81fd2..38b9d724905f9 100644 --- a/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h +++ b/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h @@ -5,24 +5,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -// -// The CopyrightMetadataPass lowers the module-level metadata emitted by Clang -// for `#pragma comment(copyright, "...")` on AIX: -// -// !aix.copyright.comment = !{!"Copyright ..."} -// -// into an internal constant string global that is preserved across all compiler -// and linker stages. Each translation unit produces one TU-local string symbol -// (`__aix_copyright_str`), and the pass attaches `!implicit.ref` metadata to -// defined functions referencing this symbol. The PowerPC AIX backend recognizes -// this metadata and emits `.ref` directives in the XCOFF assembly, ensuring the -// copyright strings: -// -// • survive optimization and LTO, -// • are not removed by linker garbage collection, and -// • remain visible in the final binary. -// -//===----------------------------------------------------------------------===// #ifndef LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H #define LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H @@ -40,4 +22,4 @@ class CopyrightMetadataPass : public PassInfoMixin { } // namespace llvm -#endif // LLVM_TRANSFORMS_UTILS_WYVERN_COPYRIGHTMETADATAPASS_H \ No newline at end of file +#endif // LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H \ No newline at end of file diff --git a/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp b/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp index 4d594f7ba5936..55f1ee6e048cf 100644 --- a/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp +++ b/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp @@ -6,21 +6,22 @@ // //===----------------------------------------------------------------------===// // -// This pass lowers module-level copyright metadata emitted by Clang: +// CopyrightMetadataPass pass lowers module-level copyright metadata emitted by +// Clang: // // !aix.copyright.comment = !{!"Copyright ..."} // // into concrete, translation-unit–local globals to ensure that copyright // strings: -// -// • survive all optimization and LTO pipelines, -// • are not removed by linker garbage collection, and -// • remain visible in the final XCOFF binary. +// - survive all optimization and LTO pipelines, +// - are not removed by linker garbage collection, and +// - remain visible in the final XCOFF binary. // // For each module (translation unit), the pass performs the following: // // 1. Creates a null-terminated, internal constant string global -// (`__aix_copyright_str`) containing the copyright text. +// (`__aix_copyright_str`) containing the copyright text in +// `__aix_copyright` section.. // // 2. Marks the string in `llvm.used` so it cannot be dropped by // optimization or LTO. @@ -29,11 +30,25 @@ // defined function in the module. The PowerPC AIX backend recognizes // this metadata and emits a `.ref` directive from the function to the // string, creating a concrete relocation that prevents the linker from -// discarding it. +// discarding it (as long as the referencing symbol is kept). +// +// Input IR: +// !aix.copyright.comment = !{!"Copyright"} +// Output IR: +// @__aix_copyright_str = internal constant [N x i8] c"Copyright\00", +// section "__aix_copyright" +// @llvm.used = appending global [1 x ptr] [ptr @__aix_copyright_str] // +// define i32 @func() !implicit.ref !5 { ... } +// !5 = !{ptr @__aix_copyright_str} +// +// The copyright string is placed in the "__aix_copyright" section (mapped to +// an XCOFF csect with [RO] storage class), making it easily identifiable in +// object files and executables. The R_REF relocation prevents the linker +// from discarding this section during garbage collection. Copyright string (if +// kept by the linker) is expected to be loaded at run time. //===----------------------------------------------------------------------===// - #include "llvm/Transforms/Utils/CopyrightMetadataPass.h" #include "llvm/ADT/SmallVector.h" @@ -44,7 +59,6 @@ #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/IRBuilder.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" @@ -60,8 +74,6 @@ using namespace llvm; -namespace llvm { - static cl::opt DisableCopyrightMetadata("disable-copyright-metadata", cl::ReallyHidden, cl::desc("Disable copyright metadata pass."), @@ -106,22 +118,28 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, /*isConstant=*/true, GlobalValue::InternalLinkage, StrInit, /*Name=*/"__aix_copyright_str"); + // Set unnamed_addr to allow the linker to merge identical strings StrGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); StrGV->setAlignment(Align(1)); - StrGV->setSection("__llvm_copyright"); - - // 2. Ensure LLVM doesn't delete it (through all pipelines/LTO). + // Place in the "__aix_copyright" section. + // Backend maps this to an appropriate XCOFF csect (typically [RO]) + // The section will appear in assembly as: + // .csect __aix_copyright[RO],2 + StrGV->setSection("__aix_copyright"); + + // 2. Add the string to llvm.used to prevent LLVM optimization/LTO passes from + // removing it. appendToUsed(M, {StrGV}); - // appendToCompilerUsed(M, {StrGV}); // 3. Attach !implicit ref to every defined function // Create a metadata node pointing to the copyright string: // !N = !{ptr @__aix_copyright_str} Metadata *Ops[] = {ConstantAsMetadata::get(StrGV)}; - auto *ValMD = ValueAsMetadata::get(StrGV); MDNode *ImplicitRefMD = MDNode::get(Ctx, Ops); - auto addImplicitRef = [&](Function &F) { + // Lambda to attach implicit.ref metadata to a function. + // The backend will translate this into .ref assembly directives. + auto AddImplicitRef = [&](Function &F) { if (F.isDeclaration()) return; // Attach the implicit.ref metadata to the function @@ -130,15 +148,13 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, << F.getName() << "\n"); }; + // Process all functions in the module for (Function &F : M) - addImplicitRef(F); + AddImplicitRef(F); - // Remove the original metadata since we've processed it - // This prevents reprocessing if the pass runs multiple times + // Cleanup the processed metadata. MD->eraseFromParent(); LLVM_DEBUG(dbgs() << "[copyright] created string and anchor for module\n"); return PreservedAnalyses::all(); } - -} // namespace llvm \ No newline at end of file diff --git a/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll b/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll deleted file mode 100644 index d73a5642c107e..0000000000000 --- a/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll +++ /dev/null @@ -1,51 +0,0 @@ -; REQUIRES: powerpc-registered-target, system-aix - -; Ensure the CopyrightMetadataPass (direct-byte variant) materializes -; a TU-local string and forces a text→data relocation via a tiny ctor, -; so the AIX/XCOFF linker keeps the string alive. - -; Build IR with the pass: -; RUN: opt -passes=copyright-metadata %s -o %t.bc - -; ---------------- 32-bit AIX ---------------- -; RUN: llc -mtriple=powerpc-ibm-aix -filetype=obj -o %t32.o %t.bc -; RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t.bc -o - | FileCheck %s --check-prefix=CHECK-ASM - -; Symbol table should show our TU-local names (locals are listed with -t). -; RUN: llvm-objdump -t %t32.o | FileCheck %s --check-prefix=CHECK-SYMS - -; Relocations should reference the string (due to the volatile byte load). -; RUN: llvm-objdump -r %t32.o | FileCheck %s --check-prefix=CHECK-REL - -; ---------------- 64-bit AIX ---------------- -; RUN: llc -mtriple=powerpc64-ibm-aix -filetype=obj -o %t64.o %t.bc -; RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t.bc -o - | FileCheck %s --check-prefix=CHECK-ASM -; RUN: llvm-objdump -t %t64.o | FileCheck %s --check-prefix=CHECK-SYMS -; RUN: llvm-objdump -r %t64.o | FileCheck %s --check-prefix=CHECK-REL - -target triple = "powerpc-ibm-aix" - -define i32 @main() { entry: ret i32 0 } - -!llvm.module.flags = !{!0} -!0 = !{i32 1, !"wchar_size", i32 2} -!aix.copyright.comment = !{!1} -!1 = !{!"Copyright IBM"} - -; Assembly Checks (for a single TU) -; Verify that the backend: -; - Emits a `.ref` directive to tie the string to the TU -; - Emits the string in a dedicated read-only csect -; -; CHECK-ASM: .ref __aix_copyright_str -; CHECK-ASM: .csect __llvm_copyright[RO],2 -; CHECK-ASM-NEXT: .lglobl __aix_copyright_str -; CHECK-ASM: __aix_copyright_str -; CHECK-ASM: .string "Copyright IBM" - -; TU-local globals/functions should be present in the symbol table -; CHECK-SYMS: __aix_copyright_str - -; Relocation in the object should target the string (from the ctor’s volatile load) -; CHECK-LABEL: RELOCATION RECORDS FOR [.text] -; CHECK-REL: __aix_copyright_str \ No newline at end of file diff --git a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll index 5ddcd84e97ca3..f0dc46f66b809 100644 --- a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll +++ b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll @@ -1,9 +1,27 @@ -; RUN: opt -passes=copyright-metadata -S %s -o - | FileCheck %s - -; Verify the pass converts !aix.copyright.comment into: -; - internal constant string global -; - marks it in llvm.used and llvm.compiler.used -; - creates an internal anchor function and registers it in llvm.global_ctors +; RUN: opt -passes=copyright-metadata -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0 + +; Verify that copyright-metadata is enabled by default on all opt pipelines. +; RUN: opt --O0 -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0 +; RUN: opt --O1 -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-ON +; RUN: opt --O2 -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-ON +; RUN: opt --O3 -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-ON + +; Verify that CopyrightMetadataPass lowers !aix.copyright.comment +; into concrete, translation-unit–local globals. +; +; For each module (translation unit), the pass performs the following: +; +; 1. Creates a null-terminated, internal constant string global +; (`__aix_copyright_str`) containing the copyright text. +; +; 2. Marks the string in `llvm.used` so it cannot be dropped by +; optimization or LTO. +; +; 3. Attaches `!implicit.ref` metadata referencing the string to every +; defined function in the module. The PowerPC AIX backend recognizes +; this metadata and emits a `.ref` directive from the function to the +; string, creating a concrete relocation that prevents the linker from +; discarding it. target triple = "powerpc-ibm-aix" @@ -24,12 +42,17 @@ entry: ; ---- Globals-------------------------------------------- -; CHECK: @__aix_copyright_str = internal unnamed_addr constant [24 x i8] c"@(#) Copyright IBM 2025\00", section "__llvm_copyright", align 1 -; Preservation in used sets +; CHECK: @__aix_copyright_str = internal unnamed_addr constant [24 x i8] c"@(#) Copyright IBM 2025\00", section "__aix_copyright", align 1 +; Preservation in llvm.used sets ; CHECK-NEXT: @llvm.used = appending global [1 x ptr] [ptr @__aix_copyright_str], section "llvm.metadata" ; CHECK-NOT: ![[copyright:[0-9]+]] = !{!"@(#) Copyright IBM 2025"} ; Function has an implicit ref MD pointing at the string: -; CHECK: define void @f0() !implicit.ref ![[MD:[0-9]+]] -; CHECK: define i32 @main() !implicit.ref ![[MD]] -; CHECK: ![[MD]] = !{ptr @__aix_copyright_str} \ No newline at end of file +; CHECK-O0: define void @f0() !implicit.ref ![[MD:[0-9]+]] +; CHECK-ON: define void @f0() local_unnamed_addr #0 !implicit.ref ![[MD:[0-9]+]] +; CHECK-O0: define i32 @main() !implicit.ref ![[MD]] +; CHECK-ON: define noundef i32 @main() local_unnamed_addr #0 !implicit.ref ![[MD]] + +; Verify metadata content +; CHECK-O0: ![[MD]] = !{ptr @__aix_copyright_str} +; CHECK-ON: ![[MD]] = !{ptr @__aix_copyright_str} \ No newline at end of file From f47b0d4dc6e58bd41c3f9b4470824c6e9809a502 Mon Sep 17 00:00:00 2001 From: Tony Varghese Date: Wed, 22 Oct 2025 07:52:13 -0400 Subject: [PATCH 3/7] Pragmas from imported C++20 modules are ignored in the importing translation unit, add backend tests --- clang/lib/CodeGen/CodeGenModule.cpp | 5 +- .../pragma-comment-copyright-aix-modules.cpp | 26 ++++++++ .../PowerPC/pragma-comment-copyright-aix.ll | 61 +++++++++++++++++++ .../CopyrightMetadata/copyright-metadata.ll | 2 +- 4 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp create mode 100644 llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 38d6447e7e0df..1986ea0f0834e 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7600,7 +7600,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case PCK_Lib: AddDependentLib(PCD->getArg()); break; - case PCK_Copyright: + case PCK_Copyright: + // Skip pragmas deserialized from modules/PCHs + if (PCD->isFromASTFile()) + break; ProcessPragmaCommentCopyright(PCD->getArg()); break; case PCK_Compiler: diff --git a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp new file mode 100644 index 0000000000000..e1fc99796f867 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp @@ -0,0 +1,26 @@ +// RUN: split-file %s %t + +// Build the module interface to a PCM +// RUN: %clang_cc1 -std=c++20 -triple powerpc-ibm-aix \ +// RUN: -emit-module-interface %t/copymod.cppm -o %t/copymod.pcm + +// verify that module interface emit copyright string when compiled to assembly +// RUN: %clang_cc1 -std=c++20 -triple powerpc-ibm-aix -S %t/copymod.cppm -o - \ +// RUN: | FileCheck %s --check-prefix=CHECK-MOD +// CHECK-MOD: .string "module me" + +// Compile an importing TU that uses the prebuilt module and verify that it +// does NOT re-emit the module's copyright string. +// RUN: %clang_cc1 -std=c++20 -triple powerpc-ibm-aix \ +// RUN: -fprebuilt-module-path=%t -S %t/importmod.cc -o - \ +// RUN: | FileCheck %s +// CHECK-NOT: .string "module me" + +//--- copymod.cppm +export module copymod; +#pragma comment(copyright, "module me") +export inline void f() {} + +//--- importmod.cc +import copymod; +void g() { f(); } diff --git a/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll b/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll new file mode 100644 index 0000000000000..15be40f0d8525 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll @@ -0,0 +1,61 @@ +; REQUIRES: powerpc-registered-target, system-aix + +; This test verify that the CopyrightMetadataPass and the PowerPC AIX backend +; correctly lower and preserve copyright metadata emitted by Clang +; from `#pragma comment(copyright, "...")`. + +; Build IR with the pass: +; RUN: opt -passes=copyright-metadata %s -o %t.bc + +; ---------------- 32-bit AIX ---------------- +; RUN: llc -mtriple=powerpc-ibm-aix -filetype=obj -o %t32.o %t.bc +; RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t.bc -o - | FileCheck %s --check-prefix=CHECK-ASM + +; Verify that TU-local symbols and relocations reference the string. +; RUN: llvm-objdump -t %t32.o | FileCheck %s --check-prefix=CHECK-SYMS +; RUN: llvm-objdump -r %t32.o | FileCheck %s --check-prefix=CHECK-REL + +; ---------------- 64-bit AIX ---------------- +; RUN: llc -mtriple=powerpc64-ibm-aix -filetype=obj -o %t64.o %t.bc +; RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t.bc -o - | FileCheck %s --check-prefix=CHECK-ASM +; RUN: llvm-objdump -t %t64.o | FileCheck %s --check-prefix=CHECK-SYMS +; RUN: llvm-objdump -r %t64.o | FileCheck %s --check-prefix=CHECK-REL + +target triple = "powerpc-ibm-aix" + +define void @f0() { +entry: + ret void +} + +define i32 @main() { +entry: + ret i32 0 +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"wchar_size", i32 2} + +!aix.copyright.comment = !{!1} +!1 = !{!"Copyright IBM"} + +; ---------------- Assembly checks ---------------- +; Verify that the backend: +; - Emits a `.ref` directive for the string +; - Emits the string in a dedicated read-only csect +; +; CHECK-ASM: .ref __aix_copyright_str +; CHECK-ASM: .csect __aix_copyright[RO],2 +; CHECK-ASM-NEXT: .lglobl __aix_copyright_str +; CHECK-ASM: __aix_copyright_str +; CHECK-ASM: .string "Copyright IBM" + +; ---------------- Symbol table checks ---------------- +; TU-local globals/functions should be present in the symbol table +; CHECK-SYMS: __aix_copyright_str + +; ---------------- Relocation checks ---------------- +; The object should contain a relocation in the text section +; that references the copyright string. +; CHECK-LABEL: RELOCATION RECORDS FOR [.text] +; CHECK-REL: __aix_copyright_str \ No newline at end of file diff --git a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll index f0dc46f66b809..df10534347b19 100644 --- a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll +++ b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll @@ -21,7 +21,7 @@ ; defined function in the module. The PowerPC AIX backend recognizes ; this metadata and emits a `.ref` directive from the function to the ; string, creating a concrete relocation that prevents the linker from -; discarding it. +; discarding it (as long as the referencing symbol is kept). target triple = "powerpc-ibm-aix" From 696ca9ff4551e84725146129b5f356726c92aa3a Mon Sep 17 00:00:00 2001 From: Tony Varghese Date: Wed, 29 Oct 2025 02:54:53 -0400 Subject: [PATCH 4/7] Chnaged to platform agnostic names for llvm metadata and variables used --- clang/lib/CodeGen/CodeGenModule.cpp | 22 ++++--- clang/lib/CodeGen/CodeGenModule.h | 8 +-- clang/lib/Parse/ParsePragma.cpp | 52 +++++++++------- .../PowerPC/pragma-comment-copyright-aix.c | 2 +- .../Utils/CopyrightMetadataPass.cpp | 36 +++++------ .../PowerPC/pragma-comment-copyright-aix.ll | 61 ------------------- .../CopyrightMetadata/copyright-metadata.ll | 15 ++--- 7 files changed, 75 insertions(+), 121 deletions(-) delete mode 100644 llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 1986ea0f0834e..5257a8fcff11a 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -42,6 +42,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/Module.h" +#include "clang/Basic/PragmaKinds.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" @@ -1569,10 +1570,10 @@ void CodeGenModule::Release() { EmitBackendOptionsMetadata(getCodeGenOpts()); - // Emit copyright metadata for AIX - if (AIXCopyrightComment) { - auto *NMD = getModule().getOrInsertNamedMetadata("aix.copyright.comment"); - NMD->addOperand(AIXCopyrightComment); + // Emit copyright metadata + if (CopyrightCommentInTU) { + auto *NMD = getModule().getOrInsertNamedMetadata("loadtime.copyright.comment"); + NMD->addOperand(CopyrightCommentInTU); } // If there is device offloading code embed it in the host now. @@ -3410,17 +3411,20 @@ void CodeGenModule::AddDependentLib(StringRef Lib) { /// Process the #pragma comment(copyright, "copyright string ") /// and create llvm metadata for the copyright -void CodeGenModule::ProcessPragmaCommentCopyright(StringRef Comment) { +void CodeGenModule::ProcessPragmaComment(PragmaMSCommentKind Kind, + StringRef Comment) { - if (!getTriple().isOSAIX()) + if (!getTriple().isOSAIX() || Kind != PCK_Copyright) return; + assert( + !CopyrightCommentInTU && + "Only one copyright comment should be present in the Translation Unit"); // Create llvm metadata with the comment string auto &C = getLLVMContext(); llvm::Metadata *Ops[] = {llvm::MDString::get(C, Comment.str())}; auto *Node = llvm::MDNode::get(C, Ops); - if(!AIXCopyrightComment) - AIXCopyrightComment = Node; + CopyrightCommentInTU = Node; } /// Add link options implied by the given module, including modules @@ -7604,7 +7608,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { // Skip pragmas deserialized from modules/PCHs if (PCD->isFromASTFile()) break; - ProcessPragmaCommentCopyright(PCD->getArg()); + ProcessPragmaComment(PCD->getCommentKind(), PCD->getArg()); break; case PCK_Compiler: case PCK_ExeStr: diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index bb71575309b6e..6ff3281e5df48 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -587,9 +587,9 @@ class CodeGenModule : public CodeGenTypeCache { /// A vector of metadata strings for dependent libraries for ELF. SmallVector ELFDependentLibraries; - /// Single module-level copyright comment for AIX (if any). + /// Single module-level copyright comment (if any). /// We only ever accept one per TU. - llvm::MDNode *AIXCopyrightComment = nullptr; + llvm::MDNode *CopyrightCommentInTU = nullptr; /// @name Cache for Objective-C runtime types /// @{ @@ -1462,8 +1462,8 @@ class CodeGenModule : public CodeGenTypeCache { /// Appends a dependent lib to the appropriate metadata value. void AddDependentLib(StringRef Lib); - /// Record the AIX copyright comment in module-level metadata. - void ProcessPragmaCommentCopyright(StringRef Comment); + /// Process pragma comment + void ProcessPragmaComment(PragmaMSCommentKind Kind, StringRef Comment); llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD); diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 6bcc799402e07..e0e05ae0f97b3 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -236,7 +236,7 @@ struct PragmaCommentHandler : public PragmaHandler { private: Sema &Actions; - bool SeenAIXCopyright = false; // TU-scoped + bool SeenCopyrightInTU = false; // TU-scoped }; struct PragmaDetectMismatchHandler : public PragmaHandler { @@ -3205,14 +3205,26 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, // Verify that this is one of the 5 explicitly listed options. IdentifierInfo *II = Tok.getIdentifierInfo(); PragmaMSCommentKind Kind = - llvm::StringSwitch(II->getName()) - .Case("linker", PCK_Linker) - .Case("lib", PCK_Lib) - .Case("compiler", PCK_Compiler) - .Case("exestr", PCK_ExeStr) - .Case("user", PCK_User) - .Case("copyright", PCK_Copyright) - .Default(PCK_Unknown); + llvm::StringSwitch(II->getName()) + .Case("linker", PCK_Linker) + .Case("lib", PCK_Lib) + .Case("compiler", PCK_Compiler) + .Case("exestr", PCK_ExeStr) + .Case("user", PCK_User) + .Case("copyright", PCK_Copyright) + .Default(PCK_Unknown); + + // Restrict copyright to AIX targets only + if (!PP.getTargetInfo().getTriple().isOSAIX()) { + switch (Kind) { + case PCK_Copyright: + Kind = PCK_Unknown; + break; + default: + break; + } + } + if (Kind == PCK_Unknown) { PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); return; @@ -3225,13 +3237,13 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, } // On AIX, pragma comment copyright can each appear only once in a TU. - if (PP.getTargetInfo().getTriple().isOSAIX() && Kind == PCK_Copyright) { - if (SeenAIXCopyright) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_once) - << II->getName(); - return; - } - SeenAIXCopyright = true; + if (Kind == PCK_Copyright) { + if (SeenCopyrightInTU) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_once) + << II->getName(); + return; + } + SeenCopyrightInTU = true; } // Read the optional string if present. @@ -3260,11 +3272,9 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, return; } - if (PP.getTargetInfo().getTriple().isOSAIX()) { - // Accept and ignore well-formed copyright with empty string. - if(Kind == PCK_Copyright && ArgumentString.empty()) - return; - } + // Accept and ignore well-formed copyright with empty string. + if (Kind == PCK_Copyright && ArgumentString.empty()) + return; // If the pragma is lexically sound, notify any interested PPCallbacks. if (PP.getPPCallbacks()) diff --git a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c index 68e599ca577ce..5ace127629dda 100644 --- a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c +++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c @@ -20,7 +20,7 @@ int main() { return 0; } // Check that both metadata sections are present -// CHECK: !aix.copyright.comment = !{![[copyright:[0-9]+]]} +// CHECK: !loadtime.copyright.comment = !{![[copyright:[0-9]+]]} // Check individual metadata content // CHECK: ![[copyright]] = !{!"@(#) Copyright"} diff --git a/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp b/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp index 55f1ee6e048cf..edba4b479df06 100644 --- a/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp +++ b/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp @@ -1,15 +1,15 @@ -//===-- CopyrightMetadataPass.cpp - Lower AIX copyright metadata ----------===// +//===-- CopyrightMetadataPass.cpp - Lower copyright metadata -------------===// // // 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 // -//===----------------------------------------------------------------------===// +//===---------------------------------------------------------------------===// // // CopyrightMetadataPass pass lowers module-level copyright metadata emitted by // Clang: // -// !aix.copyright.comment = !{!"Copyright ..."} +// !loadtime.copyright.comment = !{!"Copyright ..."} // // into concrete, translation-unit–local globals to ensure that copyright // strings: @@ -20,8 +20,8 @@ // For each module (translation unit), the pass performs the following: // // 1. Creates a null-terminated, internal constant string global -// (`__aix_copyright_str`) containing the copyright text in -// `__aix_copyright` section.. +// (`__loadtime_copyright_str`) containing the copyright text in +// `__copyright_comment` section. // // 2. Marks the string in `llvm.used` so it cannot be dropped by // optimization or LTO. @@ -33,16 +33,16 @@ // discarding it (as long as the referencing symbol is kept). // // Input IR: -// !aix.copyright.comment = !{!"Copyright"} +// !loadtime.copyright.comment = !{!"Copyright"} // Output IR: -// @__aix_copyright_str = internal constant [N x i8] c"Copyright\00", -// section "__aix_copyright" -// @llvm.used = appending global [1 x ptr] [ptr @__aix_copyright_str] +// @__loadtime_copyright_str = internal constant [N x i8] c"Copyright\00", +// section "__copyright_comment" +// @llvm.used = appending global [1 x ptr] [ptr @__loadtime_copyright_str] // // define i32 @func() !implicit.ref !5 { ... } -// !5 = !{ptr @__aix_copyright_str} +// !5 = !{ptr @__loadtime_copyright_str} // -// The copyright string is placed in the "__aix_copyright" section (mapped to +// The copyright string is placed in the "__copyright_comment" section (mapped to // an XCOFF csect with [RO] storage class), making it easily identifiable in // object files and executables. The R_REF relocation prevents the linker // from discarding this section during garbage collection. Copyright string (if @@ -90,9 +90,9 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, LLVMContext &Ctx = M.getContext(); - // Single-metadata: !aix.copyright.comment = !{!0} + // Single-metadata: !loadtime.copyright.comment = !{!0} // Each operand node is expected to have one MDString operand. - NamedMDNode *MD = M.getNamedMetadata("aix.copyright.comment"); + NamedMDNode *MD = M.getNamedMetadata("loadtime.copyright.comment"); if (!MD || MD->getNumOperands() == 0) return PreservedAnalyses::all(); @@ -117,15 +117,15 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, auto *StrGV = new GlobalVariable(M, StrInit->getType(), /*isConstant=*/true, GlobalValue::InternalLinkage, StrInit, - /*Name=*/"__aix_copyright_str"); + /*Name=*/"__loadtime_copyright_str"); // Set unnamed_addr to allow the linker to merge identical strings StrGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); StrGV->setAlignment(Align(1)); - // Place in the "__aix_copyright" section. + // Place in the "__copyright_comment" section. // Backend maps this to an appropriate XCOFF csect (typically [RO]) // The section will appear in assembly as: - // .csect __aix_copyright[RO],2 - StrGV->setSection("__aix_copyright"); + // .csect __copyright_comment[RO],2 + StrGV->setSection("__copyright_comment"); // 2. Add the string to llvm.used to prevent LLVM optimization/LTO passes from // removing it. @@ -133,7 +133,7 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, // 3. Attach !implicit ref to every defined function // Create a metadata node pointing to the copyright string: - // !N = !{ptr @__aix_copyright_str} + // !N = !{ptr @__loadtime_copyright_str} Metadata *Ops[] = {ConstantAsMetadata::get(StrGV)}; MDNode *ImplicitRefMD = MDNode::get(Ctx, Ops); diff --git a/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll b/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll deleted file mode 100644 index 15be40f0d8525..0000000000000 --- a/llvm/test/CodeGen/PowerPC/pragma-comment-copyright-aix.ll +++ /dev/null @@ -1,61 +0,0 @@ -; REQUIRES: powerpc-registered-target, system-aix - -; This test verify that the CopyrightMetadataPass and the PowerPC AIX backend -; correctly lower and preserve copyright metadata emitted by Clang -; from `#pragma comment(copyright, "...")`. - -; Build IR with the pass: -; RUN: opt -passes=copyright-metadata %s -o %t.bc - -; ---------------- 32-bit AIX ---------------- -; RUN: llc -mtriple=powerpc-ibm-aix -filetype=obj -o %t32.o %t.bc -; RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t.bc -o - | FileCheck %s --check-prefix=CHECK-ASM - -; Verify that TU-local symbols and relocations reference the string. -; RUN: llvm-objdump -t %t32.o | FileCheck %s --check-prefix=CHECK-SYMS -; RUN: llvm-objdump -r %t32.o | FileCheck %s --check-prefix=CHECK-REL - -; ---------------- 64-bit AIX ---------------- -; RUN: llc -mtriple=powerpc64-ibm-aix -filetype=obj -o %t64.o %t.bc -; RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t.bc -o - | FileCheck %s --check-prefix=CHECK-ASM -; RUN: llvm-objdump -t %t64.o | FileCheck %s --check-prefix=CHECK-SYMS -; RUN: llvm-objdump -r %t64.o | FileCheck %s --check-prefix=CHECK-REL - -target triple = "powerpc-ibm-aix" - -define void @f0() { -entry: - ret void -} - -define i32 @main() { -entry: - ret i32 0 -} - -!llvm.module.flags = !{!0} -!0 = !{i32 1, !"wchar_size", i32 2} - -!aix.copyright.comment = !{!1} -!1 = !{!"Copyright IBM"} - -; ---------------- Assembly checks ---------------- -; Verify that the backend: -; - Emits a `.ref` directive for the string -; - Emits the string in a dedicated read-only csect -; -; CHECK-ASM: .ref __aix_copyright_str -; CHECK-ASM: .csect __aix_copyright[RO],2 -; CHECK-ASM-NEXT: .lglobl __aix_copyright_str -; CHECK-ASM: __aix_copyright_str -; CHECK-ASM: .string "Copyright IBM" - -; ---------------- Symbol table checks ---------------- -; TU-local globals/functions should be present in the symbol table -; CHECK-SYMS: __aix_copyright_str - -; ---------------- Relocation checks ---------------- -; The object should contain a relocation in the text section -; that references the copyright string. -; CHECK-LABEL: RELOCATION RECORDS FOR [.text] -; CHECK-REL: __aix_copyright_str \ No newline at end of file diff --git a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll index df10534347b19..53140489a34f2 100644 --- a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll +++ b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll @@ -6,13 +6,14 @@ ; RUN: opt --O2 -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-ON ; RUN: opt --O3 -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-ON -; Verify that CopyrightMetadataPass lowers !aix.copyright.comment +; Verify that CopyrightMetadataPass lowers !loadtime.copyright.comment ; into concrete, translation-unit–local globals. ; ; For each module (translation unit), the pass performs the following: ; ; 1. Creates a null-terminated, internal constant string global -; (`__aix_copyright_str`) containing the copyright text. +; (`__loadtime_copyright_str`) containing the copyright text in +; `__copyright_comment` section. ; ; 2. Marks the string in `llvm.used` so it cannot be dropped by ; optimization or LTO. @@ -37,14 +38,14 @@ entry: !llvm.module.flags = !{!0} !0 = !{i32 1, !"wchar_size", i32 2} -!aix.copyright.comment = !{!1} +!loadtime.copyright.comment = !{!1} !1 = !{!"@(#) Copyright IBM 2025"} ; ---- Globals-------------------------------------------- -; CHECK: @__aix_copyright_str = internal unnamed_addr constant [24 x i8] c"@(#) Copyright IBM 2025\00", section "__aix_copyright", align 1 +; CHECK: @__loadtime_copyright_str = internal unnamed_addr constant [24 x i8] c"@(#) Copyright IBM 2025\00", section "__copyright_comment", align 1 ; Preservation in llvm.used sets -; CHECK-NEXT: @llvm.used = appending global [1 x ptr] [ptr @__aix_copyright_str], section "llvm.metadata" +; CHECK-NEXT: @llvm.used = appending global [1 x ptr] [ptr @__loadtime_copyright_str], section "llvm.metadata" ; CHECK-NOT: ![[copyright:[0-9]+]] = !{!"@(#) Copyright IBM 2025"} ; Function has an implicit ref MD pointing at the string: @@ -54,5 +55,5 @@ entry: ; CHECK-ON: define noundef i32 @main() local_unnamed_addr #0 !implicit.ref ![[MD]] ; Verify metadata content -; CHECK-O0: ![[MD]] = !{ptr @__aix_copyright_str} -; CHECK-ON: ![[MD]] = !{ptr @__aix_copyright_str} \ No newline at end of file +; CHECK-O0: ![[MD]] = !{ptr @__loadtime_copyright_str} +; CHECK-ON: ![[MD]] = !{ptr @__loadtime_copyright_str} \ No newline at end of file From c21153eefcdbb6118307e41ddc75e56fe68cbca4 Mon Sep 17 00:00:00 2001 From: Tony Varghese Date: Wed, 3 Dec 2025 13:55:15 -0500 Subject: [PATCH 5/7] Changed the name to comment_string.loadtime - Fix test failures: Update pipeline tests for CopyrightMetadataPass - Fixed pragma comment copyright test expectations --- clang/lib/CodeGen/CodeGenModule.cpp | 41 +++++++++++-------- clang/lib/CodeGen/CodeGenModule.h | 5 +-- clang/lib/Parse/ParsePragma.cpp | 13 +++--- .../PowerPC/pragma-comment-copyright-aix.c | 2 +- clang/test/CodeGen/lto-newpm-pipeline.c | 2 + .../Utils/CopyrightMetadataPass.cpp | 28 ++++--------- .../CodeGen/AArch64/print-pipeline-passes.ll | 2 +- llvm/test/Other/new-pm-defaults.ll | 1 + .../Other/new-pm-thinlto-postlink-defaults.ll | 1 + .../new-pm-thinlto-postlink-pgo-defaults.ll | 1 + ...-pm-thinlto-postlink-samplepgo-defaults.ll | 1 + .../CopyrightMetadata/copyright-metadata.ll | 2 +- 12 files changed, 48 insertions(+), 51 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 5257a8fcff11a..07b5daaa5f98f 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -40,7 +40,7 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticFrontend.h" +// #include "clang/Basic/DiagnosticParse.h" #include "clang/Basic/Module.h" #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/SourceManager.h" @@ -1571,9 +1571,9 @@ void CodeGenModule::Release() { EmitBackendOptionsMetadata(getCodeGenOpts()); // Emit copyright metadata - if (CopyrightCommentInTU) { - auto *NMD = getModule().getOrInsertNamedMetadata("loadtime.copyright.comment"); - NMD->addOperand(CopyrightCommentInTU); + if (LoadTimeComment) { + auto *NMD = getModule().getOrInsertNamedMetadata("comment_string.loadtime"); + NMD->addOperand(LoadTimeComment); } // If there is device offloading code embed it in the host now. @@ -3409,22 +3409,29 @@ void CodeGenModule::AddDependentLib(StringRef Lib) { LinkerOptionsMetadata.push_back(llvm::MDNode::get(C, MDOpts)); } -/// Process the #pragma comment(copyright, "copyright string ") -/// and create llvm metadata for the copyright +/// Process AIX copyright pragma and create LLVM metadata. +/// #pragma comment(copyright, "string") embed copyright +/// information into the object file's loader section. +/// +/// Example: #pragma comment(copyright, "Copyright IBM Corp. 2024") +/// +/// This should only be called once per translation unit. void CodeGenModule::ProcessPragmaComment(PragmaMSCommentKind Kind, StringRef Comment) { + // Ensure we are only processing Copyright Pragmas + assert(Kind == PCK_Copyright && + "Unexpected pragma comment kind, ProcessPragmaComment should only be " + "called for PCK_Copyright"); - if (!getTriple().isOSAIX() || Kind != PCK_Copyright) + // Only one copyright pragma allowed per translation unit + if (LoadTimeComment) { return; + } - assert( - !CopyrightCommentInTU && - "Only one copyright comment should be present in the Translation Unit"); // Create llvm metadata with the comment string auto &C = getLLVMContext(); - llvm::Metadata *Ops[] = {llvm::MDString::get(C, Comment.str())}; - auto *Node = llvm::MDNode::get(C, Ops); - CopyrightCommentInTU = Node; + llvm::Metadata *Ops[] = {llvm::MDString::get(C, Comment)}; + LoadTimeComment = llvm::MDNode::get(C, Ops); } /// Add link options implied by the given module, including modules @@ -7605,10 +7612,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { AddDependentLib(PCD->getArg()); break; case PCK_Copyright: - // Skip pragmas deserialized from modules/PCHs - if (PCD->isFromASTFile()) - break; - ProcessPragmaComment(PCD->getCommentKind(), PCD->getArg()); + // Skip pragmas deserialized from modules/PCHs. Process the pragma comment + // only if it originated in this TU and the target OS is AIX. + if (!PCD->isFromASTFile() && getTriple().isOSAIX()) + ProcessPragmaComment(PCD->getCommentKind(), PCD->getArg()); break; case PCK_Compiler: case PCK_ExeStr: diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 6ff3281e5df48..895f91691cae3 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -587,9 +587,8 @@ class CodeGenModule : public CodeGenTypeCache { /// A vector of metadata strings for dependent libraries for ELF. SmallVector ELFDependentLibraries; - /// Single module-level copyright comment (if any). - /// We only ever accept one per TU. - llvm::MDNode *CopyrightCommentInTU = nullptr; + /// Metadata for copyright pragma comment (if present). + llvm::MDNode *LoadTimeComment = nullptr; /// @name Cache for Objective-C runtime types /// @{ diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index e0e05ae0f97b3..81cb3fb6efe44 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -3214,15 +3214,10 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, .Case("copyright", PCK_Copyright) .Default(PCK_Unknown); - // Restrict copyright to AIX targets only - if (!PP.getTargetInfo().getTriple().isOSAIX()) { - switch (Kind) { - case PCK_Copyright: + // Restrict copyright to AIX targets only. This could be applied for z/OS + // and extended with other IBM pragma comment kinds. + if (!PP.getTargetInfo().getTriple().isOSAIX() && Kind == PCK_Copyright) { Kind = PCK_Unknown; - break; - default: - break; - } } if (Kind == PCK_Unknown) { @@ -3238,6 +3233,8 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, // On AIX, pragma comment copyright can each appear only once in a TU. if (Kind == PCK_Copyright) { + assert(PP.getTargetInfo().getTriple().isOSAIX() && + "Pragma Comment Copyright is supported only on AIX"); if (SeenCopyrightInTU) { PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_once) << II->getName(); diff --git a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c index 5ace127629dda..ad682825954fa 100644 --- a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c +++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c @@ -20,7 +20,7 @@ int main() { return 0; } // Check that both metadata sections are present -// CHECK: !loadtime.copyright.comment = !{![[copyright:[0-9]+]]} +// CHECK: !comment_string.loadtime = !{![[copyright:[0-9]+]]} // Check individual metadata content // CHECK: ![[copyright]] = !{!"@(#) Copyright"} diff --git a/clang/test/CodeGen/lto-newpm-pipeline.c b/clang/test/CodeGen/lto-newpm-pipeline.c index ea9784a76f923..28f291aff052e 100644 --- a/clang/test/CodeGen/lto-newpm-pipeline.c +++ b/clang/test/CodeGen/lto-newpm-pipeline.c @@ -27,6 +27,7 @@ // CHECK-FULL-O0: Running pass: VerifierPass // CHECK-FULL-O0-NEXT: Running analysis: VerifierAnalysis +// CHECK-FULL-O0-NEXT: Running pass: CopyrightMetadataPass // CHECK-FULL-O0-NEXT: Running analysis: InnerAnalysisManagerProxy // CHECK-FULL-O0-NEXT: Running pass: EntryExitInstrumenterPass // CHECK-FULL-O0-NEXT: Running pass: AlwaysInlinerPass @@ -41,6 +42,7 @@ // CHECK-THIN-O0: Running pass: VerifierPass // CHECK-THIN-O0-NEXT: Running analysis: VerifierAnalysis +// CHECK-THIN-O0-NEXT: Running pass: CopyrightMetadataPass // CHECK-THIN-O0-NEXT: Running analysis: InnerAnalysisManagerProxy // CHECK-THIN-O0-NEXT: Running pass: EntryExitInstrumenterPass // CHECK-THIN-O0-NEXT: Running pass: AlwaysInlinerPass diff --git a/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp b/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp index edba4b479df06..08768e05b42ee 100644 --- a/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp +++ b/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp @@ -9,14 +9,10 @@ // CopyrightMetadataPass pass lowers module-level copyright metadata emitted by // Clang: // -// !loadtime.copyright.comment = !{!"Copyright ..."} -// -// into concrete, translation-unit–local globals to ensure that copyright -// strings: -// - survive all optimization and LTO pipelines, -// - are not removed by linker garbage collection, and -// - remain visible in the final XCOFF binary. +// !comment_string.loadtime = !{!"Copyright ..."} // +// into concrete, translation-unit–local globals. +// This Pass is enabled only for AIX. // For each module (translation unit), the pass performs the following: // // 1. Creates a null-terminated, internal constant string global @@ -33,7 +29,7 @@ // discarding it (as long as the referencing symbol is kept). // // Input IR: -// !loadtime.copyright.comment = !{!"Copyright"} +// !comment_string.loadtime = !{!"Copyright"} // Output IR: // @__loadtime_copyright_str = internal constant [N x i8] c"Copyright\00", // section "__copyright_comment" @@ -42,11 +38,6 @@ // define i32 @func() !implicit.ref !5 { ... } // !5 = !{ptr @__loadtime_copyright_str} // -// The copyright string is placed in the "__copyright_comment" section (mapped to -// an XCOFF csect with [RO] storage class), making it easily identifiable in -// object files and executables. The R_REF relocation prevents the linker -// from discarding this section during garbage collection. Copyright string (if -// kept by the linker) is expected to be loaded at run time. //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/CopyrightMetadataPass.h" @@ -90,9 +81,9 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, LLVMContext &Ctx = M.getContext(); - // Single-metadata: !loadtime.copyright.comment = !{!0} + // Single-metadata: !comment_string.loadtime = !{!0} // Each operand node is expected to have one MDString operand. - NamedMDNode *MD = M.getNamedMetadata("loadtime.copyright.comment"); + NamedMDNode *MD = M.getNamedMetadata("comment_string.loadtime"); if (!MD || MD->getNumOperands() == 0) return PreservedAnalyses::all(); @@ -113,7 +104,7 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, // 1. Create a single NULL-terminated string global Constant *StrInit = ConstantDataArray::getString(Ctx, Text, /*AddNull=*/true); - // Internal, constant, TU-local — avoids duplicate symbol issues across TUs. + // Internal, constant, TU-local--avoids duplicate symbol issues across TUs. auto *StrGV = new GlobalVariable(M, StrInit->getType(), /*isConstant=*/true, GlobalValue::InternalLinkage, StrInit, @@ -122,9 +113,7 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, StrGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); StrGV->setAlignment(Align(1)); // Place in the "__copyright_comment" section. - // Backend maps this to an appropriate XCOFF csect (typically [RO]) - // The section will appear in assembly as: - // .csect __copyright_comment[RO],2 + // The GV is constant, so we expect a read-only section. StrGV->setSection("__copyright_comment"); // 2. Add the string to llvm.used to prevent LLVM optimization/LTO passes from @@ -138,7 +127,6 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, MDNode *ImplicitRefMD = MDNode::get(Ctx, Ops); // Lambda to attach implicit.ref metadata to a function. - // The backend will translate this into .ref assembly directives. auto AddImplicitRef = [&](Function &F) { if (F.isDeclaration()) return; diff --git a/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll b/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll index 86090324c770c..f3600bc2ded8d 100644 --- a/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll +++ b/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll @@ -2,7 +2,7 @@ ; RUN: opt -mtriple=aarch64 -S -passes='default' -print-pipeline-passes < %s | FileCheck %s ; CHECK: loop-idiom-vectorize -; O0: {{^}}function(ee-instrument<>),always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),alloc-token,function(annotation-remarks),verify,print{{$}} +; O0: {{^}}copyright-metadata,function(ee-instrument<>),always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),function(annotation-remarks),verify,print{{$}} define void @foo() { entry: diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll index f074b2fdd3ab8..c690c2df1af82 100644 --- a/llvm/test/Other/new-pm-defaults.ll +++ b/llvm/test/Other/new-pm-defaults.ll @@ -238,6 +238,7 @@ ; CHECK-O-NEXT: Running pass: CoroCleanupPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: GlobalDCEPass +; CHECK-O-NEXT: Running pass: CopyrightMetadataPass ; CHECK-DEFAULT-NEXT: Running pass: EliminateAvailableExternallyPass ; CHECK-LTO-NOT: Running pass: EliminateAvailableExternallyPass ; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll index b0d08316de4f0..0f9f9abfdac28 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll @@ -162,6 +162,7 @@ ; CHECK-O-NEXT: Running pass: CoroCleanupPass ; CHECK-POSTLINK-O-NEXT: Running pass: GlobalOptPass ; CHECK-POSTLINK-O-NEXT: Running pass: GlobalDCEPass +; CHECK-POSTLINK-O-NEXT: Running pass: CopyrightMetadataPass ; CHECK-POSTLINK-O-NEXT: Running pass: EliminateAvailableExternallyPass ; CHECK-POSTLINK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-POSTLINK-O-NEXT: Running pass: RecomputeGlobalsAAPass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll index 6b3e82a752899..528d7105a0516 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll @@ -146,6 +146,7 @@ ; CHECK-O-NEXT: Running pass: CoroCleanupPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: GlobalDCEPass +; CHECK-O-NEXT: Running pass: CopyrightMetadataPass ; CHECK-O-NEXT: Running pass: EliminateAvailableExternallyPass ; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RecomputeGlobalsAAPass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll index 88dc18f605ce2..2e07520462912 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll @@ -155,6 +155,7 @@ ; CHECK-O-NEXT: Running pass: CoroCleanupPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: GlobalDCEPass +; CHECK-O-NEXT: Running pass: CopyrightMetadataPass ; CHECK-O-NEXT: Running pass: EliminateAvailableExternallyPass ; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RecomputeGlobalsAAPass diff --git a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll index 53140489a34f2..2a950a69fb5c6 100644 --- a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll +++ b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll @@ -38,7 +38,7 @@ entry: !llvm.module.flags = !{!0} !0 = !{i32 1, !"wchar_size", i32 2} -!loadtime.copyright.comment = !{!1} +!comment_string.loadtime = !{!1} !1 = !{!"@(#) Copyright IBM 2025"} From a2904bae723c0eb0aa9094ddc76e6e5e1eeba828 Mon Sep 17 00:00:00 2001 From: Tony Varghese Date: Wed, 3 Dec 2025 15:07:01 -0500 Subject: [PATCH 6/7] Update clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp to be an llvm based test --- clang/lib/CodeGen/CodeGenModule.cpp | 2 +- .../pragma-comment-copyright-aix-modules.cpp | 16 +++++++++------- .../PowerPC/pragma-comment-copyright-aix.c | 2 +- .../Transforms/Utils/CopyrightMetadataPass.h | 2 +- .../CodeGen/AArch64/print-pipeline-passes.ll | 3 +-- .../CopyrightMetadata/copyright-metadata.ll | 2 +- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 07b5daaa5f98f..9047eaa400b72 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -40,7 +40,7 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/Diagnostic.h" -// #include "clang/Basic/DiagnosticParse.h" +#include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/Module.h" #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/SourceManager.h" diff --git a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp index e1fc99796f867..fa8482db94e7a 100644 --- a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp +++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp @@ -4,17 +4,19 @@ // RUN: %clang_cc1 -std=c++20 -triple powerpc-ibm-aix \ // RUN: -emit-module-interface %t/copymod.cppm -o %t/copymod.pcm -// verify that module interface emit copyright string when compiled to assembly -// RUN: %clang_cc1 -std=c++20 -triple powerpc-ibm-aix -S %t/copymod.cppm -o - \ +// Verify that module interface emits copyright global when compiled to IR +// RUN: %clang_cc1 -std=c++20 -triple powerpc-ibm-aix -emit-llvm %t/copymod.cppm -o - \ // RUN: | FileCheck %s --check-prefix=CHECK-MOD -// CHECK-MOD: .string "module me" +// CHECK-MOD: @__loadtime_copyright_str = internal unnamed_addr constant [10 x i8] c"module me\00", section "__copyright_comment" +// CHECK-MOD: @llvm.used = appending global {{.*}} @__loadtime_copyright_str // Compile an importing TU that uses the prebuilt module and verify that it -// does NOT re-emit the module's copyright string. +// does NOT re-emit the module's copyright global. // RUN: %clang_cc1 -std=c++20 -triple powerpc-ibm-aix \ -// RUN: -fprebuilt-module-path=%t -S %t/importmod.cc -o - \ -// RUN: | FileCheck %s -// CHECK-NOT: .string "module me" +// RUN: -fprebuilt-module-path=%t -emit-llvm %t/importmod.cc -o - \ +// RUN: | FileCheck %s --check-prefix=CHECK-IMPORT +// CHECK-IMPORT-NOT: @__loadtime_copyright_str +// CHECK-IMPORT-NOT: c"module me\00" //--- copymod.cppm export module copymod; diff --git a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c index ad682825954fa..98d2db416496e 100644 --- a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c +++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c @@ -31,4 +31,4 @@ int main() { return 0; } int main() { return 0; } -#endif \ No newline at end of file +#endif diff --git a/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h b/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h index 38b9d724905f9..894cbfdcb8dc3 100644 --- a/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h +++ b/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h @@ -22,4 +22,4 @@ class CopyrightMetadataPass : public PassInfoMixin { } // namespace llvm -#endif // LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H \ No newline at end of file +#endif // LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H diff --git a/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll b/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll index f3600bc2ded8d..27e9552d35ef5 100644 --- a/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll +++ b/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll @@ -2,8 +2,7 @@ ; RUN: opt -mtriple=aarch64 -S -passes='default' -print-pipeline-passes < %s | FileCheck %s ; CHECK: loop-idiom-vectorize -; O0: {{^}}copyright-metadata,function(ee-instrument<>),always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),function(annotation-remarks),verify,print{{$}} - +; O0: {{^}}copyright-metadata,function(ee-instrument<>),always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),alloc-token,function(annotation-remarks),verify,print{{$}} define void @foo() { entry: ret void diff --git a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll index 2a950a69fb5c6..e613f2cdd4d5c 100644 --- a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll +++ b/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll @@ -56,4 +56,4 @@ entry: ; Verify metadata content ; CHECK-O0: ![[MD]] = !{ptr @__loadtime_copyright_str} -; CHECK-ON: ![[MD]] = !{ptr @__loadtime_copyright_str} \ No newline at end of file +; CHECK-ON: ![[MD]] = !{ptr @__loadtime_copyright_str} From 0402627f1bb2d58525eb0b10ebb6e9797f494821 Mon Sep 17 00:00:00 2001 From: Tony Varghese Date: Fri, 5 Dec 2025 13:11:14 -0500 Subject: [PATCH 7/7] Changed the name of the pass to LowerCommentStringPass --- .../pragma-comment-copyright-aix-modules.cpp | 6 ++-- clang/test/CodeGen/lto-newpm-pipeline.c | 4 +-- ...etadataPass.h => LowerCommentStringPass.h} | 10 +++--- llvm/lib/Passes/PassBuilder.cpp | 2 +- llvm/lib/Passes/PassBuilderPipelines.cpp | 6 ++-- llvm/lib/Passes/PassRegistry.def | 2 +- llvm/lib/Transforms/Utils/CMakeLists.txt | 2 +- ...ataPass.cpp => LowerCommentStringPass.cpp} | 36 +++++++++---------- .../CodeGen/AArch64/print-pipeline-passes.ll | 2 +- llvm/test/Other/new-pm-defaults.ll | 2 +- .../Other/new-pm-thinlto-postlink-defaults.ll | 2 +- .../new-pm-thinlto-postlink-pgo-defaults.ll | 2 +- ...-pm-thinlto-postlink-samplepgo-defaults.ll | 2 +- .../lower-comment-string.ll} | 18 +++++----- 14 files changed, 48 insertions(+), 48 deletions(-) rename llvm/include/llvm/Transforms/Utils/{CopyrightMetadataPass.h => LowerCommentStringPass.h} (59%) rename llvm/lib/Transforms/Utils/{CopyrightMetadataPass.cpp => LowerCommentStringPass.cpp} (82%) rename llvm/test/Transforms/{CopyrightMetadata/copyright-metadata.ll => LowerCommentString/lower-comment-string.ll} (73%) diff --git a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp index fa8482db94e7a..9020df6e737d6 100644 --- a/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp +++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp @@ -7,15 +7,15 @@ // Verify that module interface emits copyright global when compiled to IR // RUN: %clang_cc1 -std=c++20 -triple powerpc-ibm-aix -emit-llvm %t/copymod.cppm -o - \ // RUN: | FileCheck %s --check-prefix=CHECK-MOD -// CHECK-MOD: @__loadtime_copyright_str = internal unnamed_addr constant [10 x i8] c"module me\00", section "__copyright_comment" -// CHECK-MOD: @llvm.used = appending global {{.*}} @__loadtime_copyright_str +// CHECK-MOD: @__loadtime_comment_str = internal unnamed_addr constant [10 x i8] c"module me\00", section "__loadtime_comment" +// CHECK-MOD: @llvm.used = appending global {{.*}} @__loadtime_comment_str // Compile an importing TU that uses the prebuilt module and verify that it // does NOT re-emit the module's copyright global. // RUN: %clang_cc1 -std=c++20 -triple powerpc-ibm-aix \ // RUN: -fprebuilt-module-path=%t -emit-llvm %t/importmod.cc -o - \ // RUN: | FileCheck %s --check-prefix=CHECK-IMPORT -// CHECK-IMPORT-NOT: @__loadtime_copyright_str +// CHECK-IMPORT-NOT: @__loadtime_comment_str // CHECK-IMPORT-NOT: c"module me\00" //--- copymod.cppm diff --git a/clang/test/CodeGen/lto-newpm-pipeline.c b/clang/test/CodeGen/lto-newpm-pipeline.c index 28f291aff052e..b9466b9558b06 100644 --- a/clang/test/CodeGen/lto-newpm-pipeline.c +++ b/clang/test/CodeGen/lto-newpm-pipeline.c @@ -27,7 +27,7 @@ // CHECK-FULL-O0: Running pass: VerifierPass // CHECK-FULL-O0-NEXT: Running analysis: VerifierAnalysis -// CHECK-FULL-O0-NEXT: Running pass: CopyrightMetadataPass +// CHECK-FULL-O0-NEXT: Running pass: LowerCommentStringPass // CHECK-FULL-O0-NEXT: Running analysis: InnerAnalysisManagerProxy // CHECK-FULL-O0-NEXT: Running pass: EntryExitInstrumenterPass // CHECK-FULL-O0-NEXT: Running pass: AlwaysInlinerPass @@ -42,7 +42,7 @@ // CHECK-THIN-O0: Running pass: VerifierPass // CHECK-THIN-O0-NEXT: Running analysis: VerifierAnalysis -// CHECK-THIN-O0-NEXT: Running pass: CopyrightMetadataPass +// CHECK-THIN-O0-NEXT: Running pass: LowerCommentStringPass // CHECK-THIN-O0-NEXT: Running analysis: InnerAnalysisManagerProxy // CHECK-THIN-O0-NEXT: Running pass: EntryExitInstrumenterPass // CHECK-THIN-O0-NEXT: Running pass: AlwaysInlinerPass diff --git a/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h b/llvm/include/llvm/Transforms/Utils/LowerCommentStringPass.h similarity index 59% rename from llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h rename to llvm/include/llvm/Transforms/Utils/LowerCommentStringPass.h index 894cbfdcb8dc3..567c42ddd3714 100644 --- a/llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h +++ b/llvm/include/llvm/Transforms/Utils/LowerCommentStringPass.h @@ -1,4 +1,4 @@ -//===-- CopyrightMetadataPass.h - Lower AIX copyright metadata -*- C++ -*-===// +//===-- LowerCommentStringPass.h - Lower Comment string metadata -*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H -#define LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H +#ifndef LLVM_TRANSFORMS_UTILS_LOWERCOMMENTSTRINGPASS_H +#define LLVM_TRANSFORMS_UTILS_LOWERCOMMENTSTRINGPASS_H #include "llvm/IR/PassManager.h" namespace llvm { -class CopyrightMetadataPass : public PassInfoMixin { +class LowerCommentStringPass : public PassInfoMixin { public: PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); @@ -22,4 +22,4 @@ class CopyrightMetadataPass : public PassInfoMixin { } // namespace llvm -#endif // LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H +#endif // LLVM_TRANSFORMS_UTILS_LOWERCOMMENTSTRINGPASS_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 24526d9f973ff..df95d76bfc1b1 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -347,7 +347,7 @@ #include "llvm/Transforms/Utils/BreakCriticalEdges.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h" -#include "llvm/Transforms/Utils/CopyrightMetadataPass.h" +#include "llvm/Transforms/Utils/LowerCommentStringPass.h" #include "llvm/Transforms/Utils/CountVisits.h" #include "llvm/Transforms/Utils/DXILUpgrade.h" #include "llvm/Transforms/Utils/Debugify.h" diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index cd6cd126ef2bb..99764994bfcc3 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -135,7 +135,7 @@ #include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/AssumeBundleBuilder.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" -#include "llvm/Transforms/Utils/CopyrightMetadataPass.h" +#include "llvm/Transforms/Utils/LowerCommentStringPass.h" #include "llvm/Transforms/Utils/CountVisits.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/ExtraPassManager.h" @@ -1456,7 +1456,7 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, ModulePassManager MPM; // Process copyright metadata early, before any optimizations - MPM.addPass(CopyrightMetadataPass()); + MPM.addPass(LowerCommentStringPass()); // Run partial inlining pass to partially inline functions that have // large bodies. @@ -2279,7 +2279,7 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level, ModulePassManager MPM; // Process copyright metadata at O0 before any other transformations - MPM.addPass(CopyrightMetadataPass()); + MPM.addPass(LowerCommentStringPass()); // Perform pseudo probe instrumentation in O0 mode. This is for the // consistency between different build modes. For example, a LTO build can be diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 3f60ce0734a33..16f5cdb8f58fb 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -61,7 +61,7 @@ MODULE_PASS("check-debugify", NewPMCheckDebugifyPass()) MODULE_PASS("constmerge", ConstantMergePass()) MODULE_PASS("coro-cleanup", CoroCleanupPass()) MODULE_PASS("coro-early", CoroEarlyPass()) -MODULE_PASS("copyright-metadata", CopyrightMetadataPass()) +MODULE_PASS("lower-comment-string", LowerCommentStringPass()) MODULE_PASS("cross-dso-cfi", CrossDSOCFIPass()) MODULE_PASS("ctx-instr-gen", PGOInstrumentationGen(PGOInstrumentationType::CTXPROF)) diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt index 13643e9f411b9..943add58cca5d 100644 --- a/llvm/lib/Transforms/Utils/CMakeLists.txt +++ b/llvm/lib/Transforms/Utils/CMakeLists.txt @@ -17,7 +17,7 @@ add_llvm_component_library(LLVMTransformUtils CodeLayout.cpp CodeMoverUtils.cpp ControlFlowUtils.cpp - CopyrightMetadataPass.cpp + LowerCommentStringPass.cpp CtorUtils.cpp CountVisits.cpp Debugify.cpp diff --git a/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp b/llvm/lib/Transforms/Utils/LowerCommentStringPass.cpp similarity index 82% rename from llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp rename to llvm/lib/Transforms/Utils/LowerCommentStringPass.cpp index 08768e05b42ee..5173a29adcaf3 100644 --- a/llvm/lib/Transforms/Utils/CopyrightMetadataPass.cpp +++ b/llvm/lib/Transforms/Utils/LowerCommentStringPass.cpp @@ -1,4 +1,4 @@ -//===-- CopyrightMetadataPass.cpp - Lower copyright metadata -------------===// +//===-- LowerCommentStringPass.cpp - Lower Comment string metadata -------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,8 @@ // //===---------------------------------------------------------------------===// // -// CopyrightMetadataPass pass lowers module-level copyright metadata emitted by -// Clang: +// LowerCommentStringPass pass lowers module-level comment string metadata +// emitted by Clang: // // !comment_string.loadtime = !{!"Copyright ..."} // @@ -16,8 +16,8 @@ // For each module (translation unit), the pass performs the following: // // 1. Creates a null-terminated, internal constant string global -// (`__loadtime_copyright_str`) containing the copyright text in -// `__copyright_comment` section. +// (`__loadtime_comment_str`) containing the copyright text in +// `__loadtime_comment` section. // // 2. Marks the string in `llvm.used` so it cannot be dropped by // optimization or LTO. @@ -31,16 +31,16 @@ // Input IR: // !comment_string.loadtime = !{!"Copyright"} // Output IR: -// @__loadtime_copyright_str = internal constant [N x i8] c"Copyright\00", -// section "__copyright_comment" -// @llvm.used = appending global [1 x ptr] [ptr @__loadtime_copyright_str] +// @__loadtime_comment_str = internal constant [N x i8] c"Copyright\00", +// section "__loadtime_comment" +// @llvm.used = appending global [1 x ptr] [ptr @__loadtime_comment_str] // // define i32 @func() !implicit.ref !5 { ... } -// !5 = !{ptr @__loadtime_copyright_str} +// !5 = !{ptr @__loadtime_comment_str} // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Utils/CopyrightMetadataPass.h" +#include "llvm/Transforms/Utils/LowerCommentStringPass.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -61,20 +61,20 @@ #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/ModuleUtils.h" -#define DEBUG_TYPE "copyright-metadata" +#define DEBUG_TYPE "lower-comment-string" using namespace llvm; static cl::opt - DisableCopyrightMetadata("disable-copyright-metadata", cl::ReallyHidden, - cl::desc("Disable copyright metadata pass."), + DisableCopyrightMetadata("disable-lower-comment-string", cl::ReallyHidden, + cl::desc("Disable LowerCommentString pass."), cl::init(false)); static bool isAIXTriple(const Module &M) { return Triple(M.getTargetTriple()).isOSAIX(); } -PreservedAnalyses CopyrightMetadataPass::run(Module &M, +PreservedAnalyses LowerCommentStringPass::run(Module &M, ModuleAnalysisManager &AM) { if (DisableCopyrightMetadata || !isAIXTriple(M)) return PreservedAnalyses::all(); @@ -108,13 +108,13 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, auto *StrGV = new GlobalVariable(M, StrInit->getType(), /*isConstant=*/true, GlobalValue::InternalLinkage, StrInit, - /*Name=*/"__loadtime_copyright_str"); + /*Name=*/"__loadtime_comment_str"); // Set unnamed_addr to allow the linker to merge identical strings StrGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); StrGV->setAlignment(Align(1)); - // Place in the "__copyright_comment" section. + // Place in the "__loadtime_comment" section. // The GV is constant, so we expect a read-only section. - StrGV->setSection("__copyright_comment"); + StrGV->setSection("__loadtime_comment"); // 2. Add the string to llvm.used to prevent LLVM optimization/LTO passes from // removing it. @@ -122,7 +122,7 @@ PreservedAnalyses CopyrightMetadataPass::run(Module &M, // 3. Attach !implicit ref to every defined function // Create a metadata node pointing to the copyright string: - // !N = !{ptr @__loadtime_copyright_str} + // !N = !{ptr @__loadtime_comment_str} Metadata *Ops[] = {ConstantAsMetadata::get(StrGV)}; MDNode *ImplicitRefMD = MDNode::get(Ctx, Ops); diff --git a/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll b/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll index 27e9552d35ef5..eaa4441029fff 100644 --- a/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll +++ b/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll @@ -2,7 +2,7 @@ ; RUN: opt -mtriple=aarch64 -S -passes='default' -print-pipeline-passes < %s | FileCheck %s ; CHECK: loop-idiom-vectorize -; O0: {{^}}copyright-metadata,function(ee-instrument<>),always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),alloc-token,function(annotation-remarks),verify,print{{$}} +; O0: {{^}}lower-comment-string,function(ee-instrument<>),always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),alloc-token,function(annotation-remarks),verify,print{{$}} define void @foo() { entry: ret void diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll index c690c2df1af82..979a7897b4c02 100644 --- a/llvm/test/Other/new-pm-defaults.ll +++ b/llvm/test/Other/new-pm-defaults.ll @@ -238,7 +238,7 @@ ; CHECK-O-NEXT: Running pass: CoroCleanupPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: GlobalDCEPass -; CHECK-O-NEXT: Running pass: CopyrightMetadataPass +; CHECK-O-NEXT: Running pass: LowerCommentStringPass ; CHECK-DEFAULT-NEXT: Running pass: EliminateAvailableExternallyPass ; CHECK-LTO-NOT: Running pass: EliminateAvailableExternallyPass ; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll index 0f9f9abfdac28..d03b15d276e0b 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll @@ -162,7 +162,7 @@ ; CHECK-O-NEXT: Running pass: CoroCleanupPass ; CHECK-POSTLINK-O-NEXT: Running pass: GlobalOptPass ; CHECK-POSTLINK-O-NEXT: Running pass: GlobalDCEPass -; CHECK-POSTLINK-O-NEXT: Running pass: CopyrightMetadataPass +; CHECK-POSTLINK-O-NEXT: Running pass: LowerCommentStringPass ; CHECK-POSTLINK-O-NEXT: Running pass: EliminateAvailableExternallyPass ; CHECK-POSTLINK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-POSTLINK-O-NEXT: Running pass: RecomputeGlobalsAAPass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll index 528d7105a0516..b5b0d55bf410c 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll @@ -146,7 +146,7 @@ ; CHECK-O-NEXT: Running pass: CoroCleanupPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: GlobalDCEPass -; CHECK-O-NEXT: Running pass: CopyrightMetadataPass +; CHECK-O-NEXT: Running pass: LowerCommentStringPass ; CHECK-O-NEXT: Running pass: EliminateAvailableExternallyPass ; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RecomputeGlobalsAAPass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll index 2e07520462912..57561975769d0 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll @@ -155,7 +155,7 @@ ; CHECK-O-NEXT: Running pass: CoroCleanupPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: GlobalDCEPass -; CHECK-O-NEXT: Running pass: CopyrightMetadataPass +; CHECK-O-NEXT: Running pass: LowerCommentStringPass ; CHECK-O-NEXT: Running pass: EliminateAvailableExternallyPass ; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RecomputeGlobalsAAPass diff --git a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll b/llvm/test/Transforms/LowerCommentString/lower-comment-string.ll similarity index 73% rename from llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll rename to llvm/test/Transforms/LowerCommentString/lower-comment-string.ll index e613f2cdd4d5c..ba7ad17f4c4b7 100644 --- a/llvm/test/Transforms/CopyrightMetadata/copyright-metadata.ll +++ b/llvm/test/Transforms/LowerCommentString/lower-comment-string.ll @@ -1,19 +1,19 @@ -; RUN: opt -passes=copyright-metadata -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0 +; RUN: opt -passes=lower-comment-string -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0 -; Verify that copyright-metadata is enabled by default on all opt pipelines. +; Verify that lower-comment-string is enabled by default on all opt pipelines. ; RUN: opt --O0 -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0 ; RUN: opt --O1 -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-ON ; RUN: opt --O2 -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-ON ; RUN: opt --O3 -S %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-ON -; Verify that CopyrightMetadataPass lowers !loadtime.copyright.comment +; Verify that LowerCommentStringPass lowers !loadtime.copyright.comment ; into concrete, translation-unit–local globals. ; ; For each module (translation unit), the pass performs the following: ; ; 1. Creates a null-terminated, internal constant string global -; (`__loadtime_copyright_str`) containing the copyright text in -; `__copyright_comment` section. +; (`__loadtime_comment_str`) containing the copyright text in +; `__loadtime_comment` section. ; ; 2. Marks the string in `llvm.used` so it cannot be dropped by ; optimization or LTO. @@ -43,9 +43,9 @@ entry: ; ---- Globals-------------------------------------------- -; CHECK: @__loadtime_copyright_str = internal unnamed_addr constant [24 x i8] c"@(#) Copyright IBM 2025\00", section "__copyright_comment", align 1 +; CHECK: @__loadtime_comment_str = internal unnamed_addr constant [24 x i8] c"@(#) Copyright IBM 2025\00", section "__loadtime_comment", align 1 ; Preservation in llvm.used sets -; CHECK-NEXT: @llvm.used = appending global [1 x ptr] [ptr @__loadtime_copyright_str], section "llvm.metadata" +; CHECK-NEXT: @llvm.used = appending global [1 x ptr] [ptr @__loadtime_comment_str], section "llvm.metadata" ; CHECK-NOT: ![[copyright:[0-9]+]] = !{!"@(#) Copyright IBM 2025"} ; Function has an implicit ref MD pointing at the string: @@ -55,5 +55,5 @@ entry: ; CHECK-ON: define noundef i32 @main() local_unnamed_addr #0 !implicit.ref ![[MD]] ; Verify metadata content -; CHECK-O0: ![[MD]] = !{ptr @__loadtime_copyright_str} -; CHECK-ON: ![[MD]] = !{ptr @__loadtime_copyright_str} +; CHECK-O0: ![[MD]] = !{ptr @__loadtime_comment_str} +; CHECK-ON: ![[MD]] = !{ptr @__loadtime_comment_str}