Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1365,6 +1365,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<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 "
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/PragmaKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2523,6 +2523,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())
Expand Down
27 changes: 27 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1555,6 +1555,12 @@ void CodeGenModule::Release() {

EmitBackendOptionsMetadata(getCodeGenOpts());

// Emit copyright metadata for AIX
if (AIXCopyrightComment) {
auto *NMD = getModule().getOrInsertNamedMetadata("aix.copyright.comment");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rename "aix.copyright.comment" to be something generic so other platforms can use it. Something like "comment.module". Hubert had a better suggestion than the word "module". I'd use that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to loadtime.copyright.comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop copyright from the name. That reflects a use, not the purpose.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, it may be helpful (in case there are additional #pragma comment IR annotations in the future) to name it comment_string.loadtime so that we can have a family of comment_string.* annotations with the "high-order qualifier" first (assuming that the comments will uniformly be generated as strings out of the front-end).

NMD->addOperand(AIXCopyrightComment);
}

// If there is device offloading code embed it in the host now.
EmbedObject(&getModule(), CodeGenOpts, *getFileSystem(), getDiags());

Expand Down Expand Up @@ -3317,6 +3323,21 @@ 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
void CodeGenModule::ProcessPragmaCommentCopyright(StringRef Comment) {

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);
if(!AIXCopyrightComment)
AIXCopyrightComment = Node;
}

/// Add link options implied by the given module, including modules
/// it depends on, using a postorder walk.
static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod,
Expand Down Expand Up @@ -7453,6 +7474,12 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case PCK_Lib:
AddDependentLib(PCD->getArg());
break;
case PCK_Copyright:
// Skip pragmas deserialized from modules/PCHs
if (PCD->isFromASTFile())
break;
ProcessPragmaCommentCopyright(PCD->getArg());
break;
case PCK_Compiler:
case PCK_ExeStr:
case PCK_User:
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,10 @@ class CodeGenModule : public CodeGenTypeCache {
/// A vector of metadata strings for dependent libraries for ELF.
SmallVector<llvm::MDNode *, 16> ELFDependentLibraries;

/// Single module-level copyright comment for AIX (if any).
/// We only ever accept one per TU.
llvm::MDNode *AIXCopyrightComment = nullptr;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make this a SmallVector<> too. AIX might limit this to only one pragma, other platforms may not.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to evaluate the impact of making this a SmallVector. Will it cause the code that processes it to become a loop? If so, can that loop be truly tested in this PR? We should not be leaving "inoperative" code paths lying around.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with Hubert here, we can always change it to a vector if a need arises.


/// @name Cache for Objective-C runtime types
/// @{

Expand Down Expand Up @@ -1458,6 +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);

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

Expand Down
24 changes: 22 additions & 2 deletions clang/lib/Parse/ParsePragma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ struct PragmaCommentHandler : public PragmaHandler {

private:
Sema &Actions;
bool SeenAIXCopyright = false; // TU-scoped
};

struct PragmaDetectMismatchHandler : public PragmaHandler {
Expand Down Expand Up @@ -473,7 +474,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());
}
Expand Down Expand Up @@ -595,7 +597,8 @@ void Parser::resetPragmaHandlers() {
OpenACCHandler.reset();

if (getLangOpts().MicrosoftExt ||
getTargetInfo().getTriple().isOSBinFormatELF()) {
getTargetInfo().getTriple().isOSBinFormatELF() ||
getTargetInfo().getTriple().isOSAIX()) {
PP.RemovePragmaHandler(MSCommentHandler.get());
MSCommentHandler.reset();
}
Expand Down Expand Up @@ -3207,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);
Expand All @@ -3219,6 +3223,16 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
return;
}

// 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.
PP.Lex(Tok);
std::string ArgumentString;
Expand All @@ -3245,6 +3259,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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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"
Comment on lines +7 to +10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test can be written to check LLVM IR (to avoid the PowerPC backend requirement).


// 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(); }
34 changes: 34 additions & 0 deletions clang/test/CodeGen/PowerPC/pragma-comment-copyright-aix.c
Original file line number Diff line number Diff line change
@@ -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: !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
25 changes: 25 additions & 0 deletions llvm/include/llvm/Transforms/Utils/CopyrightMetadataPass.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===-- 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H
#define LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H

#include "llvm/IR/PassManager.h"

namespace llvm {
class CopyrightMetadataPass : public PassInfoMixin<CopyrightMetadataPass> {
public:
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);

static bool isRequired() { return true; }
};


} // namespace llvm

#endif // LLVM_TRANSFORMS_UTILS_COPYRIGHTMETADATAPASS_H
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,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"
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Passes/PassBuilderPipelines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,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"
Expand Down Expand Up @@ -1446,6 +1447,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)
Expand Down Expand Up @@ -2219,6 +2223,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
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,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))
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ add_llvm_component_library(LLVMTransformUtils
CodeLayout.cpp
CodeMoverUtils.cpp
ControlFlowUtils.cpp
CopyrightMetadataPass.cpp
CtorUtils.cpp
CountVisits.cpp
Debugify.cpp
Expand Down
Loading