-
Notifications
You must be signed in to change notification settings - Fork 13.5k
LLVM Bitcode Linker: A self contained linker for nvptx and other targets #117458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+529
−25
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
ed252e9
LLVM_TOOLS: Include llvm-link as a llvm tool
222ce4f
LLVM Bitcode Linker: Added crate
af42d2a
NVPTX: Enable self-contained for the nvptx target
43f2055
LLVM Bitcode Linker: Add as a linker known to the compiler
6a50d05
Bootstrap: Add argument for building llvm bitcode linker
843dd28
NVPTX: Enable previously disabled tests
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "llvm-bitcode-linker" | ||
version = "0.0.1" | ||
description = "A self-contained linker for llvm bitcode" | ||
license = "MIT OR Apache-2.0" | ||
edition = "2021" | ||
publish = false | ||
|
||
[dependencies] | ||
anyhow = "1.0" | ||
tracing = "0.1" | ||
tracing-subscriber = {version = "0.3.0", features = ["std"] } | ||
clap = { version = "4.3", features = ["derive"] } | ||
thiserror = "1.0.24" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# LLVM Bitcode Linker | ||
The LLVM bitcode linker can be used to link targets without any dependency on system libraries. | ||
The code will be linked in llvm-bc before compiling to native code. For some of these targets | ||
(e.g. ptx) there does not exist a sensible way to link the native format at all. A bitcode linker | ||
is required to link code compiled for such targets. |
62 changes: 62 additions & 0 deletions
62
src/tools/llvm-bitcode-linker/src/bin/llvm-bitcode-linker.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
use std::path::PathBuf; | ||
|
||
use clap::Parser; | ||
|
||
use llvm_bitcode_linker::{Optimization, Session, Target}; | ||
|
||
#[derive(Debug, Parser)] | ||
/// Linker for embedded code without any system dependencies | ||
pub struct Args { | ||
/// Input files - objects, archives and static libraries. | ||
/// | ||
/// An archive can be, but not required to be, a Rust rlib. | ||
files: Vec<PathBuf>, | ||
|
||
/// A symbol that should be exported | ||
#[arg(long)] | ||
export_symbol: Vec<String>, | ||
|
||
/// Input files directory | ||
#[arg(short = 'L')] | ||
input_dir: Vec<PathBuf>, | ||
|
||
/// Target triple for which the code is compiled | ||
#[arg(long)] | ||
target: Target, | ||
|
||
/// The target cpu | ||
#[arg(long)] | ||
target_cpu: Option<String>, | ||
|
||
/// Write output to the filename | ||
#[arg(short, long)] | ||
output: PathBuf, | ||
|
||
// Enable link time optimization | ||
#[arg(long)] | ||
lto: bool, | ||
|
||
/// Emit debug information | ||
#[arg(long)] | ||
debug: bool, | ||
|
||
/// The optimization level | ||
#[arg(short = 'O', value_enum, default_value = "0")] | ||
optimization: Optimization, | ||
} | ||
|
||
fn main() -> anyhow::Result<()> { | ||
tracing_subscriber::FmtSubscriber::builder().with_max_level(tracing::Level::DEBUG).init(); | ||
|
||
let args = Args::parse(); | ||
|
||
let mut linker = Session::new(args.target, args.target_cpu, args.output); | ||
|
||
linker.add_exported_symbols(args.export_symbol); | ||
|
||
for rlib in args.files { | ||
linker.add_file(rlib); | ||
} | ||
|
||
linker.lto(args.optimization, args.debug) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
mod linker; | ||
mod opt; | ||
mod target; | ||
|
||
pub use linker::Session; | ||
pub use opt::Optimization; | ||
pub use target::Target; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
use std::path::PathBuf; | ||
|
||
use anyhow::Context; | ||
|
||
use crate::Optimization; | ||
use crate::Target; | ||
|
||
#[derive(Debug)] | ||
pub struct Session { | ||
target: Target, | ||
cpu: Option<String>, | ||
symbols: Vec<String>, | ||
|
||
/// A file that `llvm-link` supports, like a bitcode file or an archive. | ||
files: Vec<PathBuf>, | ||
|
||
// Output files | ||
link_path: PathBuf, | ||
opt_path: PathBuf, | ||
sym_path: PathBuf, | ||
out_path: PathBuf, | ||
} | ||
|
||
impl Session { | ||
pub fn new(target: crate::Target, cpu: Option<String>, out_path: PathBuf) -> Self { | ||
let link_path = out_path.with_extension("o"); | ||
let opt_path = out_path.with_extension("optimized.o"); | ||
let sym_path = out_path.with_extension("symbols.txt"); | ||
|
||
Session { | ||
target, | ||
cpu, | ||
symbols: Vec::new(), | ||
files: Vec::new(), | ||
link_path, | ||
opt_path, | ||
sym_path, | ||
out_path, | ||
} | ||
} | ||
|
||
/// Add a file, like an rlib or bitcode file that should be linked | ||
pub fn add_file(&mut self, path: PathBuf) { | ||
self.files.push(path); | ||
} | ||
|
||
/// Add a Vec of symbols to the list of exported symbols | ||
pub fn add_exported_symbols(&mut self, symbols: Vec<String>) { | ||
self.symbols.extend(symbols); | ||
} | ||
|
||
/// Reads every file that was added to the session and link them without optimization. | ||
/// | ||
/// The resulting artifact will be written to a file that can later be read to perform | ||
/// optimizations and/or compilation from bitcode to the final artifact. | ||
fn link(&mut self) -> anyhow::Result<()> { | ||
kjetilkjeka marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tracing::info!("Linking {} files using llvm-link", self.files.len()); | ||
|
||
let llvm_link_output = std::process::Command::new("llvm-link") | ||
kjetilkjeka marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.arg("--ignore-non-bitcode") | ||
.args(&self.files) | ||
.arg("-o") | ||
.arg(&self.link_path) | ||
.output() | ||
.unwrap(); | ||
|
||
if !llvm_link_output.status.success() { | ||
tracing::error!( | ||
"llvm-link returned with Exit status: {}\n stdout: {}\n stderr: {}", | ||
llvm_link_output.status, | ||
String::from_utf8(llvm_link_output.stdout).unwrap(), | ||
String::from_utf8(llvm_link_output.stderr).unwrap(), | ||
); | ||
anyhow::bail!("llvm-link failed to link files {:?}", self.files); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Optimize and compile to native format using `opt` and `llc` | ||
/// | ||
/// Before this can be called `link` needs to be called | ||
fn optimize(&mut self, optimization: Optimization, mut debug: bool) -> anyhow::Result<()> { | ||
let mut passes = format!("default<{}>", optimization); | ||
|
||
// FIXME(@kjetilkjeka) Debug symbol generation is broken for nvptx64 so we must remove them even in debug mode | ||
if debug && self.target == crate::Target::Nvptx64NvidiaCuda { | ||
tracing::warn!("nvptx64 target detected - stripping debug symbols"); | ||
debug = false; | ||
} | ||
|
||
// We add an internalize pass as the rust compiler as we require exported symbols to be explicitly marked | ||
passes.push_str(",internalize,globaldce"); | ||
let symbol_file_content = self.symbols.iter().fold(String::new(), |s, x| s + &x + "\n"); | ||
std::fs::write(&self.sym_path, symbol_file_content) | ||
.context(format!("Failed to write symbol file: {}", self.sym_path.display()))?; | ||
|
||
tracing::info!("optimizing bitcode with passes: {}", passes); | ||
let mut opt_cmd = std::process::Command::new("opt"); | ||
opt_cmd | ||
.arg(&self.link_path) | ||
.arg("-o") | ||
.arg(&self.opt_path) | ||
.arg(format!("--internalize-public-api-file={}", self.sym_path.display())) | ||
.arg(format!("--passes={}", passes)); | ||
|
||
if !debug { | ||
opt_cmd.arg("--strip-debug"); | ||
} | ||
|
||
let opt_output = opt_cmd.output().unwrap(); | ||
|
||
if !opt_output.status.success() { | ||
tracing::error!( | ||
"opt returned with Exit status: {}\n stdout: {}\n stderr: {}", | ||
opt_output.status, | ||
String::from_utf8(opt_output.stdout).unwrap(), | ||
String::from_utf8(opt_output.stderr).unwrap(), | ||
); | ||
anyhow::bail!("opt failed optimize bitcode: {}", self.link_path.display()); | ||
}; | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Compile the optimized bitcode file to native format using `llc` | ||
/// | ||
/// Before this can be called `optimize` needs to be called | ||
fn compile(&mut self) -> anyhow::Result<()> { | ||
let mut lcc_command = std::process::Command::new("llc"); | ||
|
||
if let Some(mcpu) = &self.cpu { | ||
lcc_command.arg("--mcpu").arg(mcpu); | ||
} | ||
|
||
let lcc_output = | ||
lcc_command.arg(&self.opt_path).arg("-o").arg(&self.out_path).output().unwrap(); | ||
|
||
if !lcc_output.status.success() { | ||
tracing::error!( | ||
"llc returned with Exit status: {}\n stdout: {}\n stderr: {}", | ||
lcc_output.status, | ||
String::from_utf8(lcc_output.stdout).unwrap(), | ||
String::from_utf8(lcc_output.stderr).unwrap(), | ||
); | ||
|
||
anyhow::bail!( | ||
"llc failed to compile {} into {}", | ||
self.opt_path.display(), | ||
self.out_path.display() | ||
); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Links, optimizes and compiles to the native format | ||
pub fn lto(&mut self, optimization: crate::Optimization, debug: bool) -> anyhow::Result<()> { | ||
self.link()?; | ||
self.optimize(optimization, debug)?; | ||
self.compile() | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
use std::fmt::Display; | ||
use std::fmt::Formatter; | ||
|
||
#[derive(Debug, Clone, Copy, Default, Hash, Eq, PartialEq, clap::ValueEnum)] | ||
pub enum Optimization { | ||
#[default] | ||
#[value(name = "0")] | ||
O0, | ||
#[value(name = "1")] | ||
O1, | ||
#[value(name = "2")] | ||
O2, | ||
#[value(name = "3")] | ||
O3, | ||
#[value(name = "s")] | ||
Os, | ||
#[value(name = "z")] | ||
Oz, | ||
} | ||
|
||
#[derive(Debug, Clone, Copy, thiserror::Error)] | ||
/// An invalid optimization level | ||
#[error("invalid optimization level")] | ||
pub struct InvalidOptimizationLevel; | ||
|
||
impl std::str::FromStr for Optimization { | ||
type Err = InvalidOptimizationLevel; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
match s { | ||
"0" | "O0" => Ok(Optimization::O0), | ||
"1" | "O1" => Ok(Optimization::O1), | ||
"2" | "O2" => Ok(Optimization::O2), | ||
"3" | "O3" => Ok(Optimization::O3), | ||
"s" | "Os" => Ok(Optimization::Os), | ||
"z" | "Oz" => Ok(Optimization::Oz), | ||
_ => Err(InvalidOptimizationLevel), | ||
} | ||
} | ||
} | ||
|
||
impl Display for Optimization { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
match *self { | ||
Optimization::O0 => write!(f, "O0"), | ||
Optimization::O1 => write!(f, "O1"), | ||
Optimization::O2 => write!(f, "O2"), | ||
Optimization::O3 => write!(f, "O3"), | ||
Optimization::Os => write!(f, "Os"), | ||
Optimization::Oz => write!(f, "Oz"), | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, clap::ValueEnum)] | ||
pub enum Target { | ||
Nvptx64NvidiaCuda, | ||
} | ||
|
||
#[derive(Debug, Clone, Copy, thiserror::Error)] | ||
/// The target is not supported by this linker | ||
#[error("unsupported target")] | ||
pub struct UnsupportedTarget; | ||
|
||
impl std::str::FromStr for Target { | ||
type Err = UnsupportedTarget; | ||
|
||
fn from_str(s: &str) -> Result<Target, UnsupportedTarget> { | ||
match s { | ||
"nvptx64-nvidia-cuda" => Ok(Target::Nvptx64NvidiaCuda), | ||
_ => Err(UnsupportedTarget), | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.