aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/cpp/LTOBackendArtifacts.java
blob: d04c187d6cec17c121b6c015fec39d05c46fd5b4 (plain)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.rules.cpp;

import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.actions.LTOBackendAction;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * LTOBackendArtifacts represents a set of artifacts for a single ThinLTO backend compile.
 *
 * <p>ThinLTO expands the traditional 2 step compile (N x compile .cc, 1x link (N .o files) into a 4
 * step process:
 *
 * <ul>
 * <li>1. Bitcode generation (N times). This is produces intermediate LLVM bitcode from a source
 *     file. For this product, it reuses the .o extension.
 * <li>2. Indexing (once on N files). This takes all bitcode .o files, and for each .o file, it
 *     decides from which other .o files symbols can be inlined. In addition, it generates an index
 *     for looking up these symbols, and an imports file for identifying new input files for each
 *     step 3 {@link LTOBackendAction}.
 * <li>3. Backend compile (N times). This is the traditional compilation, and uses the same command
 *     line as the Bitcode generation in 1). Since the compiler has many bit code files available,
 *     it can inline functions and propagate constants across .o files. This step is costly, as it
 *     will do traditional optimization. The result is a .lto.o file, a traditional ELF object file.
 * <li>4. Backend link (once). This is the traditional link, and produces the final executable.
 * </ul>
 */
public final class LTOBackendArtifacts {
  // A file containing mapping of symbol => bitcode file containing the symbol.
  private final Artifact index;

  // The bitcode file which is the input of the compile.
  private final Artifact bitcodeFile;

  // A file containing a list of bitcode files necessary to run the backend step. Currently
  // unused.
  private final Artifact imports;

  // The result of executing the above command line, an ELF object file.
  private final Artifact objectFile;

  // A map of all of the bitcode files. This is the universe from which the .imports file
  // distills its lists.  The map is the same across all LTOBackendArtifacts of a given
  // binary.
  private final Map<PathFragment, Artifact> bitcodeFiles;

  // Command line arguments to apply to back-end compile action, typically from
  // the feature configuration and user-provided linkopts.
  private List<String> commandLine;

  LTOBackendArtifacts(
      PathFragment ltoOutputRootPrefix,
      Artifact bitcodeFile,
      Map<PathFragment, Artifact> allBitCodeFiles,
      RuleContext ruleContext,
      BuildConfiguration configuration,
      CppLinkAction.LinkArtifactFactory linkArtifactFactory) {
    this.bitcodeFile = bitcodeFile;
    PathFragment obj = ltoOutputRootPrefix.getRelative(bitcodeFile.getRootRelativePath());

    objectFile = linkArtifactFactory.create(ruleContext, configuration, obj);
    imports = linkArtifactFactory.create(
        ruleContext, configuration, FileSystemUtils.appendExtension(obj, ".imports"));
    index = linkArtifactFactory.create(
        ruleContext, configuration, FileSystemUtils.appendExtension(obj, ".thinlto.bc"));

    bitcodeFiles = allBitCodeFiles;
  }

  public Artifact getObjectFile() {
    return objectFile;
  }

  public Artifact getBitcodeFile() {
    return bitcodeFile;
  }

  public void addIndexingOutputs(ImmutableList.Builder<Artifact> builder) {
    builder.add(imports);
    builder.add(index);
  }

  public void setCommandLine(List<String> cmdLine) {
    commandLine = cmdLine;
  }

  public void scheduleLTOBackendAction(
      RuleContext ruleContext, FeatureConfiguration featureConfiguration, boolean usePic) {
    LTOBackendAction.Builder builder = new LTOBackendAction.Builder();
    builder.addImportsInfo(bitcodeFiles, imports);

    builder.addInput(bitcodeFile);
    builder.addInput(index);
    builder.addTransitiveInputs(CppHelper.getToolchain(ruleContext).getCompile());

    builder.addOutput(objectFile);

    builder.setProgressMessage("LTO Backend Compile " + objectFile.getFilename());
    builder.setMnemonic("CcLtoBackendCompile");

    // The command-line doesn't specify the full path to clang++, so we set it in the
    // environment.
    CppConfiguration cppConfiguration = ruleContext.getFragment(CppConfiguration.class);

    PathFragment compiler = cppConfiguration.getCppExecutable();

    builder.setExecutable(compiler);
    Variables.Builder buildVariablesBuilder = new Variables.Builder();
    buildVariablesBuilder.addVariable("thinlto_index", index.getExecPath().toString());
    // The output from the LTO backend step is a native object file.
    buildVariablesBuilder.addVariable(
        "thinlto_output_object_file", objectFile.getExecPath().toString());
    // The input to the LTO backend step is the bitcode file.
    buildVariablesBuilder.addVariable(
        "thinlto_input_bitcode_file", bitcodeFile.getExecPath().toString());
    Variables buildVariables = buildVariablesBuilder.build();
    List<String> execArgs = new ArrayList<>();
    execArgs.addAll(featureConfiguration.getCommandLine("lto-backend", buildVariables));
    if (usePic) {
      execArgs.add("-fPIC");
    }
    execArgs.addAll(commandLine);
    builder.addExecutableArguments(execArgs);

    ruleContext.registerAction(builder.build(ruleContext));
  }
}