blob: e788e484518d5bbcb66a9aef67631788e31bcec4 [file]
//===-- 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
//
//===---------------------------------------------------------------------===//
//
// This pass processes copyright comment strings created by Clang for
// #pragma comment(copyright, ...) implementation.
//
// Clang CodeGen creates weak_odr hidden constant string globals marked with
// !loadtime_comment metadata and adds them to llvm.compiler.used. These globals
// are placed in the __loadtime_comment section for better memory layout.
//
// This pass attaches !implicit.ref metadata from every defined function to
// each copyright string global. The PowerPC AIX backend recognizes this
// metadata and emits a .ref directive, creating a relocation that prevents
// the linker from discarding the string as long as the function is kept.
//
// This pass is currently enabled for AIX targets only.
//
// Input IR (created by Clang):
// @__loadtime_comment_str_HASH = weak_odr hidden unnamed_addr constant
// [N x i8] c"Copyright\00", section "__loadtime_comment", align 1,
// !loadtime_comment !0
// @llvm.compiler.used = appending global [1 x ptr]
// [ptr @__loadtime_comment_str_HASH], section "llvm.metadata"
//
// Output IR:
// @__loadtime_comment_str_HASH = weak_odr hidden unnamed_addr constant
// [N x i8] c"Copyright\00", section "__loadtime_comment", align 1,
// !loadtime_comment !0
// @llvm.compiler.used = appending global [1 x ptr]
// [ptr @__loadtime_comment_str_HASH], section "llvm.metadata"
//
// define i32 @func() !implicit.ref !1 { ... }
// !1 = !{ptr @__loadtime_comment_str_HASH}
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/LowerCommentStringPass.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Attributes.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/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 isSupportedTarget(const Module &M) {
Triple T{M.getTargetTriple()};
return T.isOSAIX();
}
PreservedAnalyses LowerCommentStringPass::run(Module &M,
ModuleAnalysisManager &AM) {
if (DisableCopyrightMetadata || !isSupportedTarget(M))
return PreservedAnalyses::all();
LLVMContext &Ctx = M.getContext();
// Collect all globals marked with !loadtime_comment metadata.
SmallVector<GlobalValue *, 4> LoadTimeCommentGlobals;
for (GlobalVariable &GV : M.globals()) {
if (GV.hasMetadata("loadtime_comment"))
LoadTimeCommentGlobals.push_back(&GV);
}
if (LoadTimeCommentGlobals.empty())
return PreservedAnalyses::all();
// Add implicit.ref from every function to each loadtime comment global.
for (Function &F : M) {
if (F.isDeclaration())
continue;
for (GlobalValue *GV : LoadTimeCommentGlobals) {
Metadata *Ops[] = {ConstantAsMetadata::get(GV)};
MDNode *NewMD = MDNode::get(Ctx, Ops);
F.addMetadata(LLVMContext::MD_implicit_ref, *NewMD);
LLVM_DEBUG(
dbgs() << "[loadtime-comment] attached implicit.ref to function: "
<< F.getName() << " for global: " << GV->getName() << "\n");
}
}
LLVM_DEBUG(dbgs() << "[loadtime-comment] processed "
<< LoadTimeCommentGlobals.size()
<< " loadtime comment globals\n");
return PreservedAnalyses::all();
}