1//===-- LowerCommentStringPass.cpp - Lower Comment string metadata -------===//
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// This pass processes copyright comment strings created by Clang for
10// #pragma comment(copyright, ...) implementation.
11//
12// Clang CodeGen creates weak_odr hidden constant string globals marked with
13// !loadtime_comment metadata and adds them to llvm.compiler.used. These globals
14// are placed in the __loadtime_comment section for better memory layout.
15//
16// This pass attaches !implicit.ref metadata from every defined function to
17// each copyright string global. The PowerPC AIX backend recognizes this
18// metadata and emits a .ref directive, creating a relocation that prevents
19// the linker from discarding the string as long as the function is kept.
20//
21// This pass is currently enabled for AIX targets only.
22//
23// Input IR (created by Clang):
24// @__loadtime_comment_str_HASH = weak_odr hidden unnamed_addr constant
25// [N x i8] c"Copyright\00", section "__loadtime_comment", align 1,
26// !loadtime_comment !0
27// @llvm.compiler.used = appending global [1 x ptr]
28// [ptr @__loadtime_comment_str_HASH], section "llvm.metadata"
29//
30// Output IR:
31// @__loadtime_comment_str_HASH = weak_odr hidden unnamed_addr constant
32// [N x i8] c"Copyright\00", section "__loadtime_comment", align 1,
33// !loadtime_comment !0
34// @llvm.compiler.used = appending global [1 x ptr]
35// [ptr @__loadtime_comment_str_HASH], section "llvm.metadata"
36//
37// define i32 @func() !implicit.ref !1 { ... }
38// !1 = !{ptr @__loadtime_comment_str_HASH}
39//
40//===----------------------------------------------------------------------===//
41
42#include "llvm/Transforms/Utils/LowerCommentStringPass.h"
43
44#include "llvm/ADT/SmallVector.h"
45#include "llvm/ADT/StringRef.h"
46#include "llvm/IR/Attributes.h"
47#include "llvm/IR/DerivedTypes.h"
48#include "llvm/IR/Function.h"
49#include "llvm/IR/GlobalValue.h"
50#include "llvm/IR/GlobalVariable.h"
51#include "llvm/IR/MDBuilder.h"
52#include "llvm/IR/Metadata.h"
53#include "llvm/IR/Module.h"
54#include "llvm/IR/Type.h"
55#include "llvm/IR/Value.h"
56#include "llvm/Support/CommandLine.h"
57#include "llvm/Support/Debug.h"
58#include "llvm/TargetParser/Triple.h"
59#include "llvm/Transforms/Utils/ModuleUtils.h"
60
61#define DEBUG_TYPE "lower-comment-string"
62
63using namespace llvm;
64
65static cl::opt<bool>
66 DisableCopyrightMetadata("disable-lower-comment-string", cl::ReallyHidden,
67 cl::desc("Disable LowerCommentString pass."),
68 cl::init(Val: false));
69
70static bool isSupportedTarget(const Module &M) {
71 Triple T{M.getTargetTriple()};
72 return T.isOSAIX();
73}
74
75PreservedAnalyses LowerCommentStringPass::run(Module &M,
76 ModuleAnalysisManager &AM) {
77 if (DisableCopyrightMetadata || !isSupportedTarget(M))
78 return PreservedAnalyses::all();
79
80 LLVMContext &Ctx = M.getContext();
81
82 // Collect all globals marked with !loadtime_comment metadata.
83 SmallVector<GlobalValue *, 4> LoadTimeCommentGlobals;
84 for (GlobalVariable &GV : M.globals()) {
85 if (GV.hasMetadata(Kind: "loadtime_comment"))
86 LoadTimeCommentGlobals.push_back(Elt: &GV);
87 }
88
89 if (LoadTimeCommentGlobals.empty())
90 return PreservedAnalyses::all();
91
92 // Add implicit.ref from every function to each loadtime comment global.
93 for (Function &F : M) {
94 if (F.isDeclaration())
95 continue;
96 for (GlobalValue *GV : LoadTimeCommentGlobals) {
97 Metadata *Ops[] = {ConstantAsMetadata::get(C: GV)};
98 MDNode *NewMD = MDNode::get(Context&: Ctx, MDs: Ops);
99 F.addMetadata(KindID: LLVMContext::MD_implicit_ref, MD&: *NewMD);
100
101 LLVM_DEBUG(
102 dbgs() << "[loadtime-comment] attached implicit.ref to function: "
103 << F.getName() << " for global: " << GV->getName() << "\n");
104 }
105 }
106
107 LLVM_DEBUG(dbgs() << "[loadtime-comment] processed "
108 << LoadTimeCommentGlobals.size()
109 << " loadtime comment globals\n");
110
111 return PreservedAnalyses::all();
112}
113