[PowerPC][AIX] Support #pragma comment copyright for AIX#178184
[PowerPC][AIX] Support #pragma comment copyright for AIX#178184tonykuttai wants to merge 4 commits into
Conversation
750cee4 to
527b870
Compare
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
552eba6 to
bcb075b
Compare
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
|
@llvm/pr-subscribers-lto @llvm/pr-subscribers-llvm-transforms Author: Tony Varghese (tonykuttai) Changes
This change builds on top of XCOFF associated metadata and was reviewed at [PowerPC][AIX] Support #pragma comment copyright for AIX Patch is 29.81 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/178184.diff 22 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 457d3644de35a..ede6a90a31cc6 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1358,6 +1358,10 @@ 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<IgnoredPragmas>;
+def warn_pragma_comment_once
+ : Warning<"'#pragma comment %0' "
+ "can be specified only once per translation unit - ignored">,
+ InGroup<IgnoredPragmas>;
// - #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 d50c9605a30b3..e63adc98a95aa 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1588,6 +1588,12 @@ void CodeGenModule::Release() {
EmitBackendOptionsMetadata(getCodeGenOpts());
+ // Emit copyright metadata
+ if (LoadTimeComment) {
+ auto *NMD = getModule().getOrInsertNamedMetadata("comment_string.loadtime");
+ NMD->addOperand(LoadTimeComment);
+ }
+
// If there is device offloading code embed it in the host now.
EmbedObject(&getModule(), CodeGenOpts, *getFileSystem(), getDiags());
@@ -3481,6 +3487,31 @@ void CodeGenModule::AddDependentLib(StringRef Lib) {
LinkerOptionsMetadata.push_back(llvm::MDNode::get(C, MDOpts));
}
+/// 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");
+
+ // Only one copyright pragma allowed per translation unit
+ if (LoadTimeComment) {
+ return;
+ }
+
+ // Create llvm metadata with the comment string
+ auto &C = getLLVMContext();
+ llvm::Metadata *Ops[] = {llvm::MDString::get(C, Comment)};
+ LoadTimeComment = llvm::MDNode::get(C, Ops);
+}
+
/// Add link options implied by the given module, including modules
/// it depends on, using a postorder walk.
static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod,
@@ -7683,6 +7714,12 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case PCK_Lib:
AddDependentLib(PCD->getArg());
break;
+ case PCK_Copyright:
+ // 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:
case PCK_User:
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index cc18e21d45759..21a75958dcc9d 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<llvm::MDNode *, 16> ELFDependentLibraries;
+ /// Metadata for copyright pragma comment (if present).
+ llvm::MDNode *LoadTimeComment = nullptr;
+
/// @name Cache for Objective-C runtime types
/// @{
@@ -1490,6 +1493,8 @@ class CodeGenModule : public CodeGenTypeCache {
/// Appends a dependent lib to the appropriate metadata value.
void AddDependentLib(StringRef Lib);
+ /// 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 def2817c930b2..5865319470511 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -237,6 +237,7 @@ struct PragmaCommentHandler : public PragmaHandler {
private:
Sema &Actions;
+ bool SeenCopyrightInTU = false; // TU-scoped
};
struct PragmaDetectMismatchHandler : public PragmaHandler {
@@ -480,7 +481,8 @@ void Parser::initializePragmaHandlers() {
PP.AddPragmaHandler(OpenACCHandler.get());
if (getLangOpts().MicrosoftExt ||
- getTargetInfo().getTriple().isOSBinFormatELF()) {
+ getTargetInfo().getTriple().isOSBinFormatELF() ||
+ getTargetInfo().getTriple().isOSAIX()) {
MSCommentHandler = std::make_unique<PragmaCommentHandler>(Actions);
PP.AddPragmaHandler(MSCommentHandler.get());
}
@@ -607,7 +609,8 @@ void Parser::resetPragmaHandlers() {
OpenACCHandler.reset();
if (getLangOpts().MicrosoftExt ||
- getTargetInfo().getTriple().isOSBinFormatELF()) {
+ getTargetInfo().getTriple().isOSBinFormatELF() ||
+ getTargetInfo().getTriple().isOSAIX()) {
PP.RemovePragmaHandler(MSCommentHandler.get());
MSCommentHandler.reset();
}
@@ -3287,13 +3290,21 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
// Verify that this is one of the 5 explicitly listed options.
IdentifierInfo *II = Tok.getIdentifierInfo();
PragmaMSCommentKind Kind =
- llvm::StringSwitch<PragmaMSCommentKind>(II->getName())
- .Case("linker", PCK_Linker)
- .Case("lib", PCK_Lib)
- .Case("compiler", PCK_Compiler)
- .Case("exestr", PCK_ExeStr)
- .Case("user", PCK_User)
- .Default(PCK_Unknown);
+ llvm::StringSwitch<PragmaMSCommentKind>(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. 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;
+ }
+
if (Kind == PCK_Unknown) {
PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind);
return;
@@ -3305,6 +3316,18 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
return;
}
+ // 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();
+ return;
+ }
+ SeenCopyrightInTU = true;
+ }
+
// Read the optional string if present.
PP.Lex(Tok);
std::string ArgumentString;
@@ -3331,6 +3354,10 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
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())
PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString);
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..9020df6e737d6
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp
@@ -0,0 +1,28 @@
+// 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 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_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_comment_str
+// CHECK-IMPORT-NOT: c"module me\00"
+
+//--- copymod.cppm
+export module copymod;
+#pragma comment(copyright, "module me")
+export inline void f() {}
+
+//--- importmod.cc
+import copymod;
+void g() { f(); }
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..98d2db416496e
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c
@@ -0,0 +1,34 @@
+// 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 translation unit - ignored}}
+
+int main() { return 0; }
+
+// Check that both metadata sections are present
+// CHECK: !comment_string.loadtime = !{![[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
diff --git a/clang/test/CodeGen/lto-newpm-pipeline.c b/clang/test/CodeGen/lto-newpm-pipeline.c
index ea9784a76f923..b9466b9558b06 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: LowerCommentStringPass
// 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: 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/LowerCommentStringPass.h b/llvm/include/llvm/Transforms/Utils/LowerCommentStringPass.h
new file mode 100644
index 0000000000000..4c6109e1176d3
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/LowerCommentStringPass.h
@@ -0,0 +1,24 @@
+//===-- LowerCommentStringPass.h - 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_LOWERCOMMENTSTRINGPASS_H
+#define LLVM_TRANSFORMS_UTILS_LOWERCOMMENTSTRINGPASS_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+class LowerCommentStringPass : public PassInfoMixin<LowerCommentStringPass> {
+public:
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+
+ static bool isRequired() { return true; }
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_LOWERCOMMENTSTRINGPASS_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 45955426d66a0..5c014644a6150 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -361,6 +361,7 @@
#include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
#include "llvm/Transforms/Utils/LoopSimplify.h"
#include "llvm/Transforms/Utils/LoopVersioning.h"
+#include "llvm/Transforms/Utils/LowerCommentStringPass.h"
#include "llvm/Transforms/Utils/LowerGlobalDtors.h"
#include "llvm/Transforms/Utils/LowerIFunc.h"
#include "llvm/Transforms/Utils/LowerInvoke.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 1584d30875570..e48833528c85a 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -142,6 +142,7 @@
#include "llvm/Transforms/Utils/ExtraPassManager.h"
#include "llvm/Transforms/Utils/InjectTLIMappings.h"
#include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
+#include "llvm/Transforms/Utils/LowerCommentStringPass.h"
#include "llvm/Transforms/Utils/Mem2Reg.h"
#include "llvm/Transforms/Utils/MoveAutoInit.h"
#include "llvm/Transforms/Utils/NameAnonGlobals.h"
@@ -1470,6 +1471,9 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
const bool LTOPreLink = isLTOPreLink(LTOPhase);
ModulePassManager MPM;
+ // Process copyright metadata early, before any optimizations
+ MPM.addPass(LowerCommentStringPass());
+
// Run partial inlining pass to partially inline functions that have
// large bodies.
if (RunPartialInlining)
@@ -2318,6 +2322,9 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level,
ModulePassManager MPM;
+ // Process copyright metadata at O0 before any other transformations
+ 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
// 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 2cfb5b2592601..05cc8775b8d71 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -62,6 +62,7 @@ MODULE_PASS("check-debugify", NewPMCheckDebugifyPass())
MODULE_PASS("constmerge", ConstantMergePass())
MODULE_PASS("coro-cleanup", CoroCleanupPass())
MODULE_PASS("coro-early", CoroEarlyPass())
+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 2b5f5cf344e60..28f86c5e96010 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -53,6 +53,7 @@ add_llvm_component_library(LLVMTransformUtils
LoopUtils.cpp
LoopVersioning.cpp
LowerAtomic.cpp
+ LowerCommentStringPass.cpp
LowerGlobalDtors.cpp
LowerIFunc.cpp
LowerInvoke.cpp
diff --git a/llvm/lib/Transforms/Utils/LowerCommentStringPass.cpp b/llvm/lib/Transforms/Utils/LowerCommentStringPass.cpp
new file mode 100644
index 0000000000000..6deef2f75e0a3
--- /dev/null
+++ b/llvm/lib/Transforms/Utils/LowerCommentStringPass.cpp
@@ -0,0 +1,148 @@
+//===-- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// LowerCommentStringPass pass lowers module-level comment string metadata
+// emitted by Clang:
+//
+// !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
+// (`__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.
+//
+// 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 (as long as the referencing symbol is kept).
+//
+// Input IR:
+// !comment_string.loadtime = !{!"Copyright"}
+// Output IR:
+// @__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_comment_str}
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Utils/LowerCommentStringPass.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/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 "lower-comment-string"
+
+using namespace llvm;
+
+static cl::opt<bool>
+ 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();
+}
+
+P...
[truncated]
|
|
@llvm/pr-subscribers-backend-aarch64 Author: Tony Varghese (tonykuttai) Changes
This change builds on top of XCOFF associated metadata and was reviewed at [PowerPC][AIX] Support #pragma comment copyright for AIX Patch is 29.81 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/178184.diff 22 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 457d3644de35a..ede6a90a31cc6 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1358,6 +1358,10 @@ 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<IgnoredPragmas>;
+def warn_pragma_comment_once
+ : Warning<"'#pragma comment %0' "
+ "can be specified only once per translation unit - ignored">,
+ InGroup<IgnoredPragmas>;
// - #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 d50c9605a30b3..e63adc98a95aa 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1588,6 +1588,12 @@ void CodeGenModule::Release() {
EmitBackendOptionsMetadata(getCodeGenOpts());
+ // Emit copyright metadata
+ if (LoadTimeComment) {
+ auto *NMD = getModule().getOrInsertNamedMetadata("comment_string.loadtime");
+ NMD->addOperand(LoadTimeComment);
+ }
+
// If there is device offloading code embed it in the host now.
EmbedObject(&getModule(), CodeGenOpts, *getFileSystem(), getDiags());
@@ -3481,6 +3487,31 @@ void CodeGenModule::AddDependentLib(StringRef Lib) {
LinkerOptionsMetadata.push_back(llvm::MDNode::get(C, MDOpts));
}
+/// 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");
+
+ // Only one copyright pragma allowed per translation unit
+ if (LoadTimeComment) {
+ return;
+ }
+
+ // Create llvm metadata with the comment string
+ auto &C = getLLVMContext();
+ llvm::Metadata *Ops[] = {llvm::MDString::get(C, Comment)};
+ LoadTimeComment = llvm::MDNode::get(C, Ops);
+}
+
/// Add link options implied by the given module, including modules
/// it depends on, using a postorder walk.
static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod,
@@ -7683,6 +7714,12 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case PCK_Lib:
AddDependentLib(PCD->getArg());
break;
+ case PCK_Copyright:
+ // 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:
case PCK_User:
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index cc18e21d45759..21a75958dcc9d 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<llvm::MDNode *, 16> ELFDependentLibraries;
+ /// Metadata for copyright pragma comment (if present).
+ llvm::MDNode *LoadTimeComment = nullptr;
+
/// @name Cache for Objective-C runtime types
/// @{
@@ -1490,6 +1493,8 @@ class CodeGenModule : public CodeGenTypeCache {
/// Appends a dependent lib to the appropriate metadata value.
void AddDependentLib(StringRef Lib);
+ /// 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 def2817c930b2..5865319470511 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -237,6 +237,7 @@ struct PragmaCommentHandler : public PragmaHandler {
private:
Sema &Actions;
+ bool SeenCopyrightInTU = false; // TU-scoped
};
struct PragmaDetectMismatchHandler : public PragmaHandler {
@@ -480,7 +481,8 @@ void Parser::initializePragmaHandlers() {
PP.AddPragmaHandler(OpenACCHandler.get());
if (getLangOpts().MicrosoftExt ||
- getTargetInfo().getTriple().isOSBinFormatELF()) {
+ getTargetInfo().getTriple().isOSBinFormatELF() ||
+ getTargetInfo().getTriple().isOSAIX()) {
MSCommentHandler = std::make_unique<PragmaCommentHandler>(Actions);
PP.AddPragmaHandler(MSCommentHandler.get());
}
@@ -607,7 +609,8 @@ void Parser::resetPragmaHandlers() {
OpenACCHandler.reset();
if (getLangOpts().MicrosoftExt ||
- getTargetInfo().getTriple().isOSBinFormatELF()) {
+ getTargetInfo().getTriple().isOSBinFormatELF() ||
+ getTargetInfo().getTriple().isOSAIX()) {
PP.RemovePragmaHandler(MSCommentHandler.get());
MSCommentHandler.reset();
}
@@ -3287,13 +3290,21 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
// Verify that this is one of the 5 explicitly listed options.
IdentifierInfo *II = Tok.getIdentifierInfo();
PragmaMSCommentKind Kind =
- llvm::StringSwitch<PragmaMSCommentKind>(II->getName())
- .Case("linker", PCK_Linker)
- .Case("lib", PCK_Lib)
- .Case("compiler", PCK_Compiler)
- .Case("exestr", PCK_ExeStr)
- .Case("user", PCK_User)
- .Default(PCK_Unknown);
+ llvm::StringSwitch<PragmaMSCommentKind>(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. 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;
+ }
+
if (Kind == PCK_Unknown) {
PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind);
return;
@@ -3305,6 +3316,18 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
return;
}
+ // 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();
+ return;
+ }
+ SeenCopyrightInTU = true;
+ }
+
// Read the optional string if present.
PP.Lex(Tok);
std::string ArgumentString;
@@ -3331,6 +3354,10 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
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())
PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString);
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..9020df6e737d6
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix-modules.cpp
@@ -0,0 +1,28 @@
+// 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 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_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_comment_str
+// CHECK-IMPORT-NOT: c"module me\00"
+
+//--- copymod.cppm
+export module copymod;
+#pragma comment(copyright, "module me")
+export inline void f() {}
+
+//--- importmod.cc
+import copymod;
+void g() { f(); }
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..98d2db416496e
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c
@@ -0,0 +1,34 @@
+// 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 translation unit - ignored}}
+
+int main() { return 0; }
+
+// Check that both metadata sections are present
+// CHECK: !comment_string.loadtime = !{![[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
diff --git a/clang/test/CodeGen/lto-newpm-pipeline.c b/clang/test/CodeGen/lto-newpm-pipeline.c
index ea9784a76f923..b9466b9558b06 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: LowerCommentStringPass
// 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: 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/LowerCommentStringPass.h b/llvm/include/llvm/Transforms/Utils/LowerCommentStringPass.h
new file mode 100644
index 0000000000000..4c6109e1176d3
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/LowerCommentStringPass.h
@@ -0,0 +1,24 @@
+//===-- LowerCommentStringPass.h - 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_LOWERCOMMENTSTRINGPASS_H
+#define LLVM_TRANSFORMS_UTILS_LOWERCOMMENTSTRINGPASS_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+class LowerCommentStringPass : public PassInfoMixin<LowerCommentStringPass> {
+public:
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+
+ static bool isRequired() { return true; }
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_LOWERCOMMENTSTRINGPASS_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 45955426d66a0..5c014644a6150 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -361,6 +361,7 @@
#include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
#include "llvm/Transforms/Utils/LoopSimplify.h"
#include "llvm/Transforms/Utils/LoopVersioning.h"
+#include "llvm/Transforms/Utils/LowerCommentStringPass.h"
#include "llvm/Transforms/Utils/LowerGlobalDtors.h"
#include "llvm/Transforms/Utils/LowerIFunc.h"
#include "llvm/Transforms/Utils/LowerInvoke.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 1584d30875570..e48833528c85a 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -142,6 +142,7 @@
#include "llvm/Transforms/Utils/ExtraPassManager.h"
#include "llvm/Transforms/Utils/InjectTLIMappings.h"
#include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
+#include "llvm/Transforms/Utils/LowerCommentStringPass.h"
#include "llvm/Transforms/Utils/Mem2Reg.h"
#include "llvm/Transforms/Utils/MoveAutoInit.h"
#include "llvm/Transforms/Utils/NameAnonGlobals.h"
@@ -1470,6 +1471,9 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
const bool LTOPreLink = isLTOPreLink(LTOPhase);
ModulePassManager MPM;
+ // Process copyright metadata early, before any optimizations
+ MPM.addPass(LowerCommentStringPass());
+
// Run partial inlining pass to partially inline functions that have
// large bodies.
if (RunPartialInlining)
@@ -2318,6 +2322,9 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level,
ModulePassManager MPM;
+ // Process copyright metadata at O0 before any other transformations
+ 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
// 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 2cfb5b2592601..05cc8775b8d71 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -62,6 +62,7 @@ MODULE_PASS("check-debugify", NewPMCheckDebugifyPass())
MODULE_PASS("constmerge", ConstantMergePass())
MODULE_PASS("coro-cleanup", CoroCleanupPass())
MODULE_PASS("coro-early", CoroEarlyPass())
+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 2b5f5cf344e60..28f86c5e96010 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -53,6 +53,7 @@ add_llvm_component_library(LLVMTransformUtils
LoopUtils.cpp
LoopVersioning.cpp
LowerAtomic.cpp
+ LowerCommentStringPass.cpp
LowerGlobalDtors.cpp
LowerIFunc.cpp
LowerInvoke.cpp
diff --git a/llvm/lib/Transforms/Utils/LowerCommentStringPass.cpp b/llvm/lib/Transforms/Utils/LowerCommentStringPass.cpp
new file mode 100644
index 0000000000000..6deef2f75e0a3
--- /dev/null
+++ b/llvm/lib/Transforms/Utils/LowerCommentStringPass.cpp
@@ -0,0 +1,148 @@
+//===-- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// LowerCommentStringPass pass lowers module-level comment string metadata
+// emitted by Clang:
+//
+// !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
+// (`__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.
+//
+// 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 (as long as the referencing symbol is kept).
+//
+// Input IR:
+// !comment_string.loadtime = !{!"Copyright"}
+// Output IR:
+// @__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_comment_str}
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Utils/LowerCommentStringPass.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/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 "lower-comment-string"
+
+using namespace llvm;
+
+static cl::opt<bool>
+ 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();
+}
+
+P...
[truncated]
|
|
The following tests had to be modified as we are keeping the |
2b44311 to
2abc275
Compare
hubert-reinterpretcast
left a comment
There was a problem hiding this comment.
Reviewed Clang changes (excluding tests).
2c769c5 to
06546f7
Compare
hubert-reinterpretcast
left a comment
There was a problem hiding this comment.
Next round of review of Clang changes (excluding tests).
08540ef to
0c36839
Compare
|
Addressed the review comments. |
| @@ -1472,6 +1473,9 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, | |||
| const bool LTOPreLink = isLTOPreLink(LTOPhase); | |||
| ModulePassManager MPM; | |||
|
|
|||
| // Process copyright metadata early, before any optimizations | |||
There was a problem hiding this comment.
why are we processing the metadata early rather than late (but not as late as link-time LTO)?
There was a problem hiding this comment.
The design rationale was to get an IR pass to replace the metadata with an IR definition and create the necessary .refs in the IR from the definitions in the IR. Thus by keeping the pass early per TU, the metadata only survives from the point of the front-end codegen until that IR pass. By the time LTO runs, the metadata is already consumed and concrete globals + .ref directives are already in the object file.
There was a problem hiding this comment.
I did say "not as late as link-time LTO".
I meant late in the IR-IR pipeline during prelink (-flto -c) LTO or regular nonLTO (-c) compilation.
Looking at the source, at the end of buildModuleOptimizationPipeline might be what I meant.
The advantage of doing it late is that any compiler generated functions will also have a .ref to the copyright variables.
There was a problem hiding this comment.
You are right. I have moved the pass to the end of the pipelines in buildO0DefaultPipeline, buildModuleOptimizationPipeline and buildThinLTOPreLinkDefaultPipeline.
29019ca to
865add9
Compare
hubert-reinterpretcast
left a comment
There was a problem hiding this comment.
I have limited my review to the front end (and front-end tests) only.
83acf57 to
7d468a5
Compare
f010482 to
9c2b2fe
Compare
|
@tonykuttai, for future reference, it is easier for reviewers to do incremental reviews if force pushes are avoided on the PR branch. Note also that for 9c2b2fe, the commit message for the squashed commit is out-of-date due to changes made during the PR review process. |
| // global and attach !implicit.ref to all defined functions. Running late | ||
| // ensures compiler-generated functions (e.g. from inlining, coroutines) | ||
| // are also anchored to the copyright string via .ref directives. | ||
| MPM.addPass(LowerCommentStringPass()); |
There was a problem hiding this comment.
Is this pass being added to the opt pipeline so that we can get early mapping from functions to the string with the implicit.ref? Since its AIX only I would have expected it to get put into the target specific pipeline we build for llc instead of getting run for all targets.
There was a problem hiding this comment.
Primary motivation was to convert !comment_string.loadtime metadata to LLVM IR earlier in the pipeline. Also it needs to run in both pre-link and post-link LTO phases, which is simpler in opt. The pass itself is bailed out early for non-aix targets. Having it in the general pipeline makes future extension much easier. update isSupportedTarget() when adding z/OS or other targets that need similar load-time comment functionality.
There was a problem hiding this comment.
LGTM (for the front-end) with specific suggestions to address code-style issues.
@tonykuttai, the general take-away from this round of review is that code comments should provide value to the understanding of the code where it appears and that said value needs to be balanced against the drafting, review, and maintenance burden of having the comment.
Especially for comments of a "design overview" nature, the information can instead be added to PR descriptions or separate documentation artifacts.
Edit: One thing that I did not state explicitly is that, among other issues, the comments were too AIX-specific.
9116b1e to
7464d43
Compare
- Emit !aix.copyright.comment from Clang for the pragma. - Lower it in LLVM to a TU-local string + llvm.used + !implicit.ref. - Add module-import and backend relocation tests.
Co-authored-by: Hubert Tong <hubert.reinterpretcast@gmail.com>
…imeComment() to the end of the class.
5b07f43 to
c089860
Compare
This change supports pragma comment copyright.
Signature:
#pragma comment (copyright, "token_sequence")commentdirective can appear only once in a translation unit.Implementation is done through:
!comment_string.loadtimefrom Clang for the pragma.llvm.compiler.used+!implicit.refbyLowerCommentStringPass!implicit.refand emits.refdirectives into the object fileThis change builds on top of XCOFF associated metadata and was reviewed at [PowerPC][AIX] Support #pragma comment copyright for AIX
here is the documentation for
#pragma commentdirectives : https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1.0?topic=descriptions-pragma-comment