1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::path::{Path, PathBuf};

use crate::{env_var, Command};

/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
/// at `$LLVM_BIN_DIR/llvm-readobj`.
pub fn llvm_readobj() -> LlvmReadobj {
    LlvmReadobj::new()
}

/// Construct a new `llvm-profdata` invocation. This assumes that `llvm-profdata` is available
/// at `$LLVM_BIN_DIR/llvm-profdata`.
pub fn llvm_profdata() -> LlvmProfdata {
    LlvmProfdata::new()
}

/// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available
/// at `$LLVM_FILECHECK`.
pub fn llvm_filecheck() -> LlvmFilecheck {
    LlvmFilecheck::new()
}

/// A `llvm-readobj` invocation builder.
#[derive(Debug)]
#[must_use]
pub struct LlvmReadobj {
    cmd: Command,
}

/// A `llvm-profdata` invocation builder.
#[derive(Debug)]
#[must_use]
pub struct LlvmProfdata {
    cmd: Command,
}

/// A `llvm-filecheck` invocation builder.
#[derive(Debug)]
#[must_use]
pub struct LlvmFilecheck {
    cmd: Command,
}

crate::impl_common_helpers!(LlvmReadobj);
crate::impl_common_helpers!(LlvmProfdata);
crate::impl_common_helpers!(LlvmFilecheck);

/// Generate the path to the bin directory of LLVM.
#[must_use]
pub fn llvm_bin_dir() -> PathBuf {
    let llvm_bin_dir = env_var("LLVM_BIN_DIR");
    PathBuf::from(llvm_bin_dir)
}

impl LlvmReadobj {
    /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
    /// at `$LLVM_BIN_DIR/llvm-readobj`.
    pub fn new() -> Self {
        let llvm_readobj = llvm_bin_dir().join("llvm-readobj");
        let cmd = Command::new(llvm_readobj);
        Self { cmd }
    }

    /// Provide an input file.
    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
        self.cmd.arg(path.as_ref());
        self
    }

    /// Pass `--file-header` to display file headers.
    pub fn file_header(&mut self) -> &mut Self {
        self.cmd.arg("--file-header");
        self
    }
}

impl LlvmProfdata {
    /// Construct a new `llvm-profdata` invocation. This assumes that `llvm-profdata` is available
    /// at `$LLVM_BIN_DIR/llvm-profdata`.
    pub fn new() -> Self {
        let llvm_profdata = llvm_bin_dir().join("llvm-profdata");
        let cmd = Command::new(llvm_profdata);
        Self { cmd }
    }

    /// Provide an input file.
    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
        self.cmd.arg(path.as_ref());
        self
    }

    /// Specify the output file path.
    pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
        self.cmd.arg("-o");
        self.cmd.arg(path.as_ref());
        self
    }

    /// Take several profile data files generated by PGO instrumentation and merge them
    /// together into a single indexed profile data file.
    pub fn merge(&mut self) -> &mut Self {
        self.cmd.arg("merge");
        self
    }
}

impl LlvmFilecheck {
    /// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available
    /// at `$LLVM_FILECHECK`.
    pub fn new() -> Self {
        let llvm_filecheck = env_var("LLVM_FILECHECK");
        let cmd = Command::new(llvm_filecheck);
        Self { cmd }
    }

    /// Pipe a read file into standard input containing patterns that will be matched against the .patterns(path) call.
    pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self {
        self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice());
        self
    }

    /// Provide the patterns that need to be matched.
    pub fn patterns<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
        self.cmd.arg(path.as_ref());
        self
    }
}