Skip to content

Commit fbbb701

Browse files
author
Tony Varghese
committed
[PowerPC][AIX] Support #pragma comment copyright for AIX
1 parent e78226e commit fbbb701

File tree

16 files changed

+493
-3
lines changed

16 files changed

+493
-3
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,9 @@ def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">;
13651365
// PS4 recognizes only #pragma comment(lib)
13661366
def warn_pragma_comment_ignored : Warning<"'#pragma comment %0' ignored">,
13671367
InGroup<IgnoredPragmas>;
1368+
def warn_pragma_comment_once : Warning<"'#pragma comment %0' "
1369+
"can be specified only once per source file - ignored">,
1370+
InGroup<IgnoredPragmas>;
13681371
// - #pragma detect_mismatch
13691372
def err_pragma_detect_mismatch_malformed : Error<
13701373
"pragma detect_mismatch is malformed; it requires two comma-separated "

clang/include/clang/Basic/PragmaKinds.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ enum PragmaMSCommentKind {
1717
PCK_Lib, // #pragma comment(lib, ...)
1818
PCK_Compiler, // #pragma comment(compiler, ...)
1919
PCK_ExeStr, // #pragma comment(exestr, ...)
20-
PCK_User // #pragma comment(user, ...)
20+
PCK_User, // #pragma comment(user, ...)
21+
PCK_Copyright // #pragma comment(copyright, ...)
2122
};
2223

2324
enum PragmaMSStructKind {

clang/lib/AST/TextNodeDumper.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2523,6 +2523,9 @@ void TextNodeDumper::VisitPragmaCommentDecl(const PragmaCommentDecl *D) {
25232523
case PCK_User:
25242524
OS << "user";
25252525
break;
2526+
case PCK_Copyright:
2527+
OS << "copyright";
2528+
break;
25262529
}
25272530
StringRef Arg = D->getArg();
25282531
if (!Arg.empty())

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,6 +1555,14 @@ void CodeGenModule::Release() {
15551555

15561556
EmitBackendOptionsMetadata(getCodeGenOpts());
15571557

1558+
// Emit copyright metadata for AIX
1559+
if (!AIXCopyrightComment.empty()) {
1560+
auto *NMD =
1561+
getModule().getOrInsertNamedMetadata("aix.copyright.comment");
1562+
for (auto *MD : AIXCopyrightComment)
1563+
NMD->addOperand(MD);
1564+
}
1565+
15581566
// If there is device offloading code embed it in the host now.
15591567
EmbedObject(&getModule(), CodeGenOpts, *getFileSystem(), getDiags());
15601568

@@ -3317,6 +3325,23 @@ void CodeGenModule::AddDependentLib(StringRef Lib) {
33173325
LinkerOptionsMetadata.push_back(llvm::MDNode::get(C, MDOpts));
33183326
}
33193327

3328+
/// Process the #pragma comment(copyright, " copy right string ")
3329+
/// and create llvm metadata for the copyrgiht
3330+
void CodeGenModule::ProcessPragmaCommentCopyright(StringRef Comment) {
3331+
3332+
// Pragma Comment Copyright is enabled only when:
3333+
// - OS is AIX
3334+
// - Comment is non empty
3335+
if (!getTriple().isOSAIX() || Comment.empty())
3336+
return;
3337+
3338+
// Create llvm metadata with the comment string
3339+
auto &C = getLLVMContext();
3340+
llvm::Metadata *Ops[] = {llvm::MDString::get(C, Comment.str())};
3341+
auto *Node = llvm::MDNode::get(C, Ops);
3342+
AIXCopyrightComment.push_back(Node); // This should be available during the runtime
3343+
}
3344+
33203345
/// Add link options implied by the given module, including modules
33213346
/// it depends on, using a postorder walk.
33223347
static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod,
@@ -7453,6 +7478,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
74537478
case PCK_Lib:
74547479
AddDependentLib(PCD->getArg());
74557480
break;
7481+
case PCK_Copyright:
7482+
ProcessPragmaCommentCopyright(PCD->getArg());
7483+
break;
74567484
case PCK_Compiler:
74577485
case PCK_ExeStr:
74587486
case PCK_User:

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,9 @@ class CodeGenModule : public CodeGenTypeCache {
587587
/// A vector of metadata strings for dependent libraries for ELF.
588588
SmallVector<llvm::MDNode *, 16> ELFDependentLibraries;
589589

590+
/// A vector of metadata strings for copyright comment for AIX
591+
SmallVector<llvm::MDNode *, 16> AIXCopyrightComment;
592+
590593
/// @name Cache for Objective-C runtime types
591594
/// @{
592595

@@ -1458,6 +1461,8 @@ class CodeGenModule : public CodeGenTypeCache {
14581461
/// Appends a dependent lib to the appropriate metadata value.
14591462
void AddDependentLib(StringRef Lib);
14601463

1464+
/// Append AIX copyright comment to the module-level metadata.
1465+
void ProcessPragmaCommentCopyright(StringRef Comment);
14611466

14621467
llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD);
14631468

clang/lib/Parse/ParsePragma.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,8 @@ void Parser::initializePragmaHandlers() {
473473
PP.AddPragmaHandler(OpenACCHandler.get());
474474

475475
if (getLangOpts().MicrosoftExt ||
476-
getTargetInfo().getTriple().isOSBinFormatELF()) {
476+
getTargetInfo().getTriple().isOSBinFormatELF() ||
477+
getTargetInfo().getTriple().isOSAIX()) {
477478
MSCommentHandler = std::make_unique<PragmaCommentHandler>(Actions);
478479
PP.AddPragmaHandler(MSCommentHandler.get());
479480
}
@@ -595,7 +596,8 @@ void Parser::resetPragmaHandlers() {
595596
OpenACCHandler.reset();
596597

597598
if (getLangOpts().MicrosoftExt ||
598-
getTargetInfo().getTriple().isOSBinFormatELF()) {
599+
getTargetInfo().getTriple().isOSBinFormatELF() ||
600+
getTargetInfo().getTriple().isOSAIX()) {
599601
PP.RemovePragmaHandler(MSCommentHandler.get());
600602
MSCommentHandler.reset();
601603
}
@@ -3207,6 +3209,7 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
32073209
.Case("compiler", PCK_Compiler)
32083210
.Case("exestr", PCK_ExeStr)
32093211
.Case("user", PCK_User)
3212+
.Case("copyright", PCK_Copyright)
32103213
.Default(PCK_Unknown);
32113214
if (Kind == PCK_Unknown) {
32123215
PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind);
@@ -3219,6 +3222,19 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
32193222
return;
32203223
}
32213224

3225+
// pragma comment copyright can each appear only once in a TU.
3226+
if (PP.getTargetInfo().getTriple().isOSAIX()) {
3227+
static bool SeenAIXCopyright = false;
3228+
if (Kind == PCK_Copyright) {
3229+
if (SeenAIXCopyright) {
3230+
PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_once)
3231+
<< II->getName();
3232+
return;
3233+
}
3234+
SeenAIXCopyright = true;
3235+
}
3236+
}
3237+
32223238
// Read the optional string if present.
32233239
PP.Lex(Tok);
32243240
std::string ArgumentString;
@@ -3245,6 +3261,12 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
32453261
return;
32463262
}
32473263

3264+
if (PP.getTargetInfo().getTriple().isOSAIX()) {
3265+
// Accept and ignore well-formed copyright with empty string.
3266+
if(Kind == PCK_Copyright && ArgumentString.empty())
3267+
return;
3268+
}
3269+
32483270
// If the pragma is lexically sound, notify any interested PPCallbacks.
32493271
if (PP.getPPCallbacks())
32503272
PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString);
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// REQUIRES: powerpc-registered-target, system-aix, clang
2+
//
3+
// This test verifies correct handling of `#pragma comment(copyright, ...)`
4+
// on AIX for multiple Translation Units (TUs).
5+
//
6+
// Each TU defines one `#pragma comment(copyright, "...")` which should:
7+
// - Generate a unique read-only `__llvm_copyright` csect containing the string.
8+
// - Create a `.ref` directive from at least one function in that TU to the
9+
// corresponding copyright symbol.
10+
// - Preserve these copyright strings across LTO and ThinLTO linking.
11+
//
12+
// -----------------------------------------------------------------------------
13+
// Build WITHOUT LTO
14+
// -----------------------------------------------------------------------------
15+
// RUN: split-file %s %t
16+
//
17+
// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/file1.c -o %t/file1.bc
18+
// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/file2.c -o %t/file2.bc
19+
// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/file3.c -o %t/file3.bc
20+
// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm-bc %t/main.c -o %t/main.bc
21+
//
22+
// Compile each bitcode file to XCOFF object and link them together:
23+
// RUN: %clang -c %t/file1.bc -o %t/file1.o
24+
// RUN: %clang -c %t/file2.bc -o %t/file2.o
25+
// RUN: %clang -c %t/file3.bc -o %t/file3.o
26+
// RUN: %clang -c %t/main.bc -o %t/main.o
27+
// RUN: %clang %t/file1.o %t/file2.o %t/file3.o %t/main.o -o %t/nonlto.exe
28+
//
29+
// Verify assembly emission and linked outputs:
30+
// RUN: llc -mtriple=powerpc-ibm-aix -filetype=asm %t/file1.bc -o - | FileCheck %s --check-prefix=CHECK-ASM
31+
// RUN: /bin/strings -a %t/nonlto.exe | FileCheck %s --check-prefix=CHECK-STRINGS
32+
// RUN: llvm-nm %t/nonlto.exe | FileCheck %s --check-prefix=CHECK-NM
33+
// RUN: llvm-objdump -r %t/nonlto.exe | FileCheck %s --check-prefix=CHECK-OBJDUMP
34+
//
35+
// -----------------------------------------------------------------------------
36+
// Build WITH Full LTO
37+
// -----------------------------------------------------------------------------
38+
// RUN: %clang -flto %t/file1.bc %t/file2.bc %t/file3.bc %t/main.bc -o %t/lto.exe
39+
// RUN: /bin/strings -a %t/lto.exe | FileCheck %s --check-prefix=CHECK-STRINGS
40+
// RUN: llvm-nm %t/lto.exe | FileCheck %s --check-prefix=CHECK-NM
41+
// RUN: llvm-objdump -r %t/lto.exe | FileCheck %s --check-prefix=CHECK-OBJDUMP
42+
//
43+
// -----------------------------------------------------------------------------
44+
// Build WITH ThinLTO
45+
// -----------------------------------------------------------------------------
46+
// RUN: %clang -flto=thin %t/file1.bc %t/file2.bc %t/file3.bc %t/main.bc -o %t/lto-thin.exe
47+
// RUN: /bin/strings -a %t/lto-thin.exe | FileCheck %s --check-prefix=CHECK-STRINGS
48+
// RUN: llvm-nm %t/lto-thin.exe | FileCheck %s --check-prefix=CHECK-NM
49+
// RUN: llvm-objdump -r %t/lto-thin.exe | FileCheck %s --check-prefix=CHECK-OBJDUMP
50+
//
51+
// -----------------------------------------------------------------------------
52+
// Assembly Checks (for a single TU)
53+
// -----------------------------------------------------------------------------
54+
//
55+
// Verify that the backend:
56+
// - Emits a `.ref` directive to tie the string to the TU
57+
// - Emits the string in a dedicated read-only csect
58+
//
59+
// CHECK-ASM: .ref __aix_copyright_str
60+
// CHECK-ASM: .csect __llvm_copyright[RO],2
61+
// CHECK-ASM-NEXT: .lglobl __aix_copyright_str
62+
// CHECK-ASM: __aix_copyright_str
63+
// CHECK-ASM: .string "Copyright 2025 TU A"
64+
//
65+
// -----------------------------------------------------------------------------
66+
// Final Binary Checks
67+
// -----------------------------------------------------------------------------
68+
//
69+
// Ensure all TUs’ copyright strings are preserved.
70+
// CHECK-STRINGS-DAG: Copyright 2025 TU A
71+
// CHECK-STRINGS-DAG: Copyright 2025 TU B
72+
// CHECK-STRINGS-DAG: Copyright 2025 TU C
73+
// CHECK-STRINGS-DAG: Copyright 2025 Main Program
74+
//
75+
// Check that the symbols are visible in the binary symbol table.
76+
// CHECK-NM: t __aix_copyright_str
77+
// CHECK-NM: t __llvm_copyright
78+
//
79+
// Ensure there’s a relocation record referencing the copyright symbol.
80+
// CHECK-OBJDUMP-LABEL: RELOCATION RECORDS FOR [.text]
81+
// CHECK-OBJDUMP: R_REF __aix_copyright_str
82+
//
83+
84+
//=== file1.c ===
85+
//--- file1.c
86+
#pragma comment(copyright, "Copyright 2025 TU A")
87+
void func1(void) {}
88+
89+
//=== file2.c ===
90+
//--- file2.c
91+
#pragma comment(copyright, "Copyright 2025 TU B")
92+
void func2(void) {}
93+
94+
//=== file3.c ===
95+
//--- file3.c
96+
#pragma comment(copyright, "Copyright 2025 TU C")
97+
void func3(void) {}
98+
99+
//=== main.c ===
100+
//--- main.c
101+
#pragma comment(copyright, "Copyright 2025 Main Program")
102+
void func1(void);
103+
void func2(void);
104+
void func3(void);
105+
int main(void) {
106+
func1();
107+
func2();
108+
func3();
109+
return 0;
110+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// REQUIRES: powerpc-registered-target, system-aix
2+
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix -O0 -disable-llvm-passes -emit-llvm -o - | FileCheck %s
3+
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix -O0 -disable-llvm-passes -emit-llvm -o - | FileCheck %s
4+
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix -verify
5+
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix -verify
6+
// RUN: %clang_cc1 %s -DTEST_EMPTY_COPYRIGHT -triple powerpc-ibm-aix -verify
7+
8+
// RUN: %clang_cc1 %s -x c++ -triple powerpc-ibm-aix -O0 -disable-llvm-passes -emit-llvm -o - | FileCheck %s
9+
// RUN: %clang_cc1 %s -x c++ -triple powerpc64-ibm-aix -O0 -disable-llvm-passes -emit-llvm -o - | FileCheck %s
10+
// RUN: %clang_cc1 %s -x c++ -triple powerpc-ibm-aix -verify
11+
// RUN: %clang_cc1 %s -x c++ -triple powerpc64-ibm-aix -verify
12+
// RUN: %clang_cc1 %s -x c++ -DTEST_EMPTY_COPYRIGHT -triple powerpc-ibm-aix -verify
13+
14+
#ifndef TEST_EMPTY_COPYRIGHT
15+
// Test basic pragma comment types
16+
#pragma comment(copyright, "@(#) Copyright")
17+
18+
// Test duplicate copyright - should warn and ignore
19+
#pragma comment(copyright, "Duplicate Copyright") // expected-warning {{'#pragma comment copyright' can be specified only once per source file - ignored}}
20+
21+
int main() { return 0; }
22+
23+
// Check that both metadata sections are present
24+
// CHECK: !aix.copyright.comment = !{![[copyright:[0-9]+]]}
25+
26+
// Check individual metadata content
27+
// CHECK: ![[copyright]] = !{!"@(#) Copyright"}
28+
29+
#else
30+
// Test empty copyright string - valid with no warning
31+
#pragma comment(copyright, "") // expected-no-diagnostics
32+
33+
int main() { return 0; }
34+
35+
#endif
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===-- CopyrightMetadataPass.h - Lower AIX copyright metadata -*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// The CopyrightMetadataPass lowers the module-level metadata emitted by Clang
10+
// for `#pragma comment(copyright, "...")` on AIX:
11+
//
12+
// !aix.copyright.comment = !{!"Copyright ..."}
13+
//
14+
// into an internal constant string global that is preserved across all compiler
15+
// and linker stages. Each translation unit produces one TU-local string symbol
16+
// (`__aix_copyright_str`), and the pass attaches `!implicit.ref` metadata to
17+
// defined functions referencing this symbol. The PowerPC AIX backend recognizes
18+
// this metadata and emits `.ref` directives in the XCOFF assembly, ensuring the
19+
// copyright strings:
20+
//
21+
// • survive optimization and LTO,
22+
// • are not removed by linker garbage collection, and
23+
// • remain visible in the final binary.
24+
//
25+
//===----------------------------------------------------------------------===//
26+
27+
#ifndef LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H
28+
#define LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H
29+
30+
#include "llvm/IR/PassManager.h"
31+
32+
namespace llvm {
33+
class CopyrightMetadataPass : public PassInfoMixin<CopyrightMetadataPass> {
34+
public:
35+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
36+
37+
static bool isRequired() { return true; }
38+
};
39+
40+
41+
} // namespace llvm
42+
43+
#endif // LLVM_TRANSFORMS_UTILS_WYVERN_COPYRIGHTMETADATAPASS_H

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@
346346
#include "llvm/Transforms/Utils/BreakCriticalEdges.h"
347347
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
348348
#include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h"
349+
#include "llvm/Transforms/Utils/CopyrightMetadataPass.h"
349350
#include "llvm/Transforms/Utils/CountVisits.h"
350351
#include "llvm/Transforms/Utils/DXILUpgrade.h"
351352
#include "llvm/Transforms/Utils/Debugify.h"

0 commit comments

Comments
 (0)