MLIR-AIE 1.4.5.dev
AIELLVMLink.cpp
Go to the documentation of this file.
1//===- LLVMLink.cpp ---------------------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2021-2022 Xilinx, Inc.
4// Copyright (C) 2022-2023 Advanced Micro Devices, Inc.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// This is basically copy-pasta from llvm/tools/llvm-link/llvm-link.cpp but
10// rewritten to take strings as input instead of files. Comments are preserved
11// in case you need to go back to the source and compare/contrast.
12
14
15#include "mlir/Support/LogicalResult.h"
16
17#include "llvm/Bitcode/BitcodeReader.h"
18#include "llvm/IR/AutoUpgrade.h"
19#include "llvm/IR/DiagnosticInfo.h"
20#include "llvm/IR/DiagnosticPrinter.h"
21#include "llvm/IR/LLVMContext.h"
22#include "llvm/IR/Module.h"
23#include "llvm/IR/ModuleSummaryIndex.h"
24#include "llvm/IR/Verifier.h"
25#include "llvm/IRReader/IRReader.h"
26#include "llvm/Linker/Linker.h"
27#include "llvm/Object/Archive.h"
28#include "llvm/Support/FileSystem.h"
29#include "llvm/Support/SourceMgr.h"
30#include "llvm/Support/WithColor.h"
31#include "llvm/Transforms/IPO/Internalize.h"
32
33#include <memory>
34#include <utility>
35
36using namespace llvm;
37
38static std::unique_ptr<Module> loadFile(std::unique_ptr<MemoryBuffer> Buffer,
39 LLVMContext &Context, bool Verbose,
40 bool MaterializeMetadata = true) {
41 SMDiagnostic Err;
42 if (Verbose)
43 errs() << "Loading '" << Buffer->getBufferIdentifier() << "'\n";
44 std::unique_ptr<Module> Result;
45 Result = parseIR(*Buffer, Err, Context);
46 if (!Result) {
47 Err.print("aie-llvm-Link", errs());
48 return nullptr;
49 }
50
51 if (MaterializeMetadata) {
52 // this call return an error that convert true if there was in fact an
53 // error...
54 if (Result->materializeMetadata()) {
55 Err.print("aie-llvm-link", errs());
56 return nullptr;
57 }
58 UpgradeDebugInfo(*Result);
59 }
60
61 return Result;
62}
63
64static mlir::LogicalResult linkFiles(const std::vector<std::string> &Files,
65 LLVMContext &Context, Linker &L,
66 unsigned Flags, bool DisableDITypeMap,
67 bool NoVerify, bool Internalize,
68 bool Verbose) {
69 // Filter out flags that don't apply to the first file we load.
70 unsigned ApplicableFlags = Flags & Linker::Flags::OverrideFromSrc;
71 // Similar to some flags, internalization doesn't apply to the first file.
72 bool InternalizeLinkedSymbols = false;
73 for (const auto &File : Files) {
74 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBufferCopy(File);
75
76 std::unique_ptr<Module> maybeModule =
77 loadFile(std::move(Buffer), Context, Verbose);
78 if (!maybeModule) {
79 WithColor::error() << " loading file '" << File << "'\n";
80 return mlir::failure();
81 }
82
83 // Note that when ODR merging types cannot verify input files in here When
84 // doing that debug metadata in the src module might already be pointing to
85 // the destination.
86 if (DisableDITypeMap && !NoVerify && verifyModule(*maybeModule, &errs())) {
87 WithColor::error() << "input module is broken!\n";
88 return mlir::failure();
89 }
90
91 if (Verbose)
92 errs() << "Linking in '" << File << "'\n";
93
94 bool Err;
95 if (InternalizeLinkedSymbols)
96 Err = L.linkInModule(
97 std::move(maybeModule), ApplicableFlags,
98 [](Module &M, const StringSet<> &GVS) {
99 internalizeModule(M, [&GVS](const GlobalValue &GV) {
100 return !GV.hasName() || (GVS.count(GV.getName()) == 0);
101 });
102 });
103 else
104 Err = L.linkInModule(std::move(maybeModule), ApplicableFlags);
105
106 if (Err) {
107 errs() << "couldn't link.\n";
108 return mlir::failure();
109 }
110
111 // Internalization applies to linking of subsequent files.
112 InternalizeLinkedSymbols = Internalize;
113
114 // All linker flags apply to linking of subsequent files.
115 ApplicableFlags = Flags;
116 }
117
118 return mlir::success();
119}
120
121mlir::LogicalResult xilinx::AIE::AIELLVMLink(
122 llvm::raw_ostream &output, const std::vector<std::string> &Files,
123 bool DisableDITypeMap, bool NoVerify, bool Internalize, bool OnlyNeeded,
124 bool PreserveAssemblyUseListOrder, bool Verbose) {
125 LLVMContext Context;
126
127 if (!DisableDITypeMap)
128 Context.enableDebugTypeODRUniquing();
129
130 auto Composite = std::make_unique<Module>("aie-llvm-link", Context);
131 Linker L(*Composite);
132
133 unsigned Flags = Linker::Flags::None;
134 if (OnlyNeeded)
135 Flags |= Linker::Flags::LinkOnlyNeeded;
136
137 // First add all the regular input files
138 if (failed(linkFiles(Files, Context, L, Flags, DisableDITypeMap, NoVerify,
139 Internalize, Verbose)))
140 return mlir::failure();
141
142 Composite->print(output, nullptr, PreserveAssemblyUseListOrder);
143 return mlir::success();
144}
mlir::LogicalResult AIELLVMLink(llvm::raw_ostream &output, const std::vector< std::string > &Files, bool DisableDITypeMap=false, bool NoVerify=false, bool Internalize=false, bool OnlyNeeded=false, bool PreserveAssemblyUseListOrder=false, bool Verbose=false)