• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tudasc / TypeART / 12907888223

22 Jan 2025 12:09PM UTC coverage: 90.585%. First build
12907888223

Pull #150

github

web-flow
Merge fac19b081 into d1dd55b3a
Pull Request #150: Enable new PM for LLVM 18

149 of 175 new or added lines in 1 file covered. (85.14%)

3839 of 4238 relevant lines covered (90.59%)

109071.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.0
/lib/passes/TypeARTPass.cpp
1
// TypeART library
2
//
3
// Copyright (c) 2017-2025 TypeART Authors
4
// Distributed under the BSD 3-Clause license.
5
// (See accompanying file LICENSE.txt or copy at
6
// https://opensource.org/licenses/BSD-3-Clause)
7
//
8
// Project home: https://github.com/tudasc/TypeART
9
//
10
// SPDX-License-Identifier: BSD-3-Clause
11
//
12

13
#include "Commandline.h"
14
#include "TypeARTConfiguration.h"
15
#include "analysis/MemInstFinder.h"
16
#include "instrumentation/MemOpArgCollector.h"
17
#include "instrumentation/MemOpInstrumentation.h"
18
#include "instrumentation/TypeARTFunctions.h"
19
#include "support/Configuration.h"
20
#include "support/FileConfiguration.h"
21
#include "support/Logger.h"
22
#include "support/Table.h"
23
#include "typegen/TypeGenerator.h"
24

25
#include "llvm/ADT/DenseMap.h"
26
#include "llvm/ADT/STLExtras.h"
27
#include "llvm/ADT/SmallVector.h"
28
#include "llvm/ADT/Statistic.h"
29
#include "llvm/ADT/StringRef.h"
30
#include "llvm/IR/DataLayout.h"
31
#include "llvm/IR/Function.h"
32
#include "llvm/IR/LegacyPassManager.h"
33
#include "llvm/IR/Module.h"
34
#include "llvm/IR/PassManager.h"
35
#include "llvm/Pass.h"
36
#include "llvm/Passes/PassBuilder.h"
37
#include "llvm/Passes/PassPlugin.h"
38
#include "llvm/Support/CommandLine.h"
39
#include "llvm/Support/raw_ostream.h"
40

41
#include <cassert>
42
#include <cstddef>
43
#include <optional>
44
#include <sstream>
45
#include <string>
46
#include <utility>
47

48
namespace llvm {
49
class BasicBlock;
50
}  // namespace llvm
51

52
using namespace llvm;
53

54
extern llvm::cl::OptionCategory typeart_category;
55

56
static cl::opt<std::string> cl_typeart_configuration_file(
1,642✔
57
    "typeart-config", cl::init(""),
1,642✔
58
    cl::desc(
1,642✔
59
        "Location of the configuration file to configure the TypeART pass. Commandline arguments are prioritized."),
1,642✔
60
    cl::cat(typeart_category));
3,284✔
61

62
static cl::opt<bool> cl_typeart_configuration_file_dump("typeart-config-dump", cl::init(false), cl::Hidden,
3,284✔
63
                                                        cl::desc("Dump default config file content to std::out."),
1,642✔
64
                                                        cl::cat(typeart_category));
3,284✔
65

66
#define DEBUG_TYPE "typeart"
67

68
ALWAYS_ENABLED_STATISTIC(NumInstrumentedMallocs, "Number of instrumented mallocs");
69
ALWAYS_ENABLED_STATISTIC(NumInstrumentedFrees, "Number of instrumented frees");
70
ALWAYS_ENABLED_STATISTIC(NumInstrumentedAlloca, "Number of instrumented (stack) allocas");
71
ALWAYS_ENABLED_STATISTIC(NumInstrumentedGlobal, "Number of instrumented globals");
72

73
namespace typeart::pass {
74

75
std::optional<std::string> get_configuration_file_path() {
1,636✔
76
  if (!cl_typeart_configuration_file.empty()) {
1,636✔
77
    LOG_DEBUG("Using cl::opt for config file " << cl_typeart_configuration_file.getValue());
78
    return cl_typeart_configuration_file.getValue();
36✔
79
  }
80
  const char* config_file = std::getenv("TYPEART_CONFIG_FILE");
1,600✔
81
  if (config_file != nullptr) {
1,600✔
82
    LOG_DEBUG("Using env var for types file " << config_file)
83
    return std::string{config_file};
×
84
  }
85
  LOG_INFO("No configuration file set.")
1,600✔
86
  return {};
1,600✔
87
}
1,636✔
88

89
class TypeArtPass : public llvm::PassInfoMixin<TypeArtPass> {
1,642✔
90
  std::unique_ptr<config::Configuration> pass_config;
91

92
  struct TypeArtFunc {
93
    const std::string name;
94
    llvm::Value* f{nullptr};
95
  };
96

97
  TypeArtFunc typeart_alloc{"__typeart_alloc"};
1,642✔
98
  TypeArtFunc typeart_alloc_global{"__typeart_alloc_global"};
1,642✔
99
  TypeArtFunc typeart_alloc_stack{"__typeart_alloc_stack"};
1,642✔
100
  TypeArtFunc typeart_free{"__typeart_free"};
1,642✔
101
  TypeArtFunc typeart_leave_scope{"__typeart_leave_scope"};
1,642✔
102

103
  TypeArtFunc typeart_alloc_omp        = typeart_alloc;
1,642✔
104
  TypeArtFunc typeart_alloc_stacks_omp = typeart_alloc_stack;
1,642✔
105
  TypeArtFunc typeart_free_omp         = typeart_free;
1,642✔
106
  TypeArtFunc typeart_leave_scope_omp  = typeart_leave_scope;
1,642✔
107

108
  std::unique_ptr<analysis::MemInstFinder> meminst_finder;
109
  std::unique_ptr<TypeGenerator> typeManager;
110
  InstrumentationHelper instrumentation_helper;
111
  TAFunctions functions;
112
  std::unique_ptr<InstrumentationContext> instrumentation_context;
113

114
 public:
115
  bool doInitialization(Module& m) {
1,636✔
116
    if (cl_typeart_configuration_file_dump.getValue()) {
1,636✔
117
      auto config = config::make_typeart_configuration({"", config::TypeARTConfigInit::FileConfigurationMode::Empty});
6✔
118
      config->get()->emitTypeartFileConfiguration(llvm::outs());
6✔
119
      LOG_DEBUG("Emitted standard config. Exiting now.")
120
      std::exit(EXIT_SUCCESS);
6✔
121
    }
122

123
    auto config_file_path = get_configuration_file_path();
1,630✔
124

125
    if (!config_file_path) {
1,630✔
126
      pass_config = std::make_unique<config::cl::CommandLineOptions>();
1,594✔
127
    } else {
1,594✔
128
      auto typeart_config = config::make_typeart_configuration({config_file_path.value()});
36✔
129
      if (typeart_config) {
36✔
130
        {
131
          std::string typeart_conf_str;
30✔
132
          llvm::raw_string_ostream conf_out_stream{typeart_conf_str};
30✔
133
          typeart_config->get()->emitTypeartFileConfiguration(conf_out_stream);
30✔
134
          LOG_INFO("Emitting TypeART file content\n" << conf_out_stream.str())
30✔
135
        }
30✔
136
        pass_config = std::move(*typeart_config);
30✔
137
      } else {
30✔
138
        LOG_FATAL("Could not load TypeARTConfiguration.")
6✔
139
        std::exit(EXIT_FAILURE);
6✔
140
      }
141
    }
30✔
142
    meminst_finder = analysis::create_finder(*pass_config);
1,624✔
143

144
    const std::string types_file =
145
        pass_config->getValueOr(config::ConfigStdArgs::types, {config::ConfigStdArgValues::types});
1,624✔
146

147
    const TypegenImplementation typesgen_parser =
1,624✔
148
        pass_config->getValueOr(config::ConfigStdArgs::typegen, {config::ConfigStdArgValues::typegen});
1,624✔
149
    typeManager = make_typegen(types_file, typesgen_parser);
1,624✔
150

151
    LOG_DEBUG("Propagating type infos.");
152
    const auto [loaded, error] = typeManager->load();
1,624✔
153
    if (loaded) {
1,624✔
154
      LOG_DEBUG("Existing type configuration successfully loaded from " << types_file);
155
    } else {
778✔
156
      LOG_DEBUG("No valid existing type configuration found: " << types_file << ". Reason: " << error.message());
157
    }
158

159
    instrumentation_helper.setModule(m);
1,624✔
160
    ModuleData mdata{&m};
1,624✔
161
    typeManager->registerModule(mdata);
1,624✔
162

163
    auto arg_collector = std::make_unique<MemOpArgCollector>(typeManager.get(), instrumentation_helper);
1,624✔
164
    const bool instrument_stack_lifetime = (*pass_config)[config::ConfigStdArgs::stack_lifetime];
1,624✔
165
    auto mem_instrument =
166
        std::make_unique<MemOpInstrumentation>(functions, instrumentation_helper, instrument_stack_lifetime);
1,624✔
167
    instrumentation_context =
1,624✔
168
        std::make_unique<InstrumentationContext>(std::move(arg_collector), std::move(mem_instrument));
1,624✔
169

170
    return true;
171
  }
1,624✔
172

173
  bool doFinalization() {
1,624✔
174
    /*
175
     * Persist the accumulated type definition information for this module.
176
     */
177
    const std::string types_file = (*pass_config)[config::ConfigStdArgs::types];
1,624✔
178
    LOG_DEBUG("Writing type file to " << types_file);
179

180
    const auto [stored, error] = typeManager->store();
1,624✔
181
    if (stored) {
1,624✔
182
      LOG_DEBUG("Success!");
183
    } else {
1,624✔
NEW
184
      LOG_FATAL("Failed writing type config to " << types_file << ". Reason: " << error.message());
×
185
    }
186

187
    const bool print_stats = (*pass_config)[config::ConfigStdArgs::stats];
1,624✔
188
    if (print_stats) {
1,624✔
189
      auto& out = llvm::errs();
1,624✔
190
      printStats(out);
1,624✔
191
    }
1,624✔
192
    return false;
193
  }
1,624✔
194

195
  void declareInstrumentationFunctions(Module& m) {
15,861✔
196
    // Remove this return if problems come up during compilation
197
    if (typeart_alloc_global.f != nullptr && typeart_alloc_stack.f != nullptr && typeart_alloc.f != nullptr &&
30,098✔
198
        typeart_free.f != nullptr && typeart_leave_scope.f != nullptr) {
14,237✔
199
      return;
14,237✔
200
    }
201

202
    TAFunctionDeclarator decl(m, instrumentation_helper, functions);
1,624✔
203

204
    auto alloc_arg_types      = instrumentation_helper.make_parameters(IType::ptr, IType::type_id, IType::extent);
1,624✔
205
    auto free_arg_types       = instrumentation_helper.make_parameters(IType::ptr);
1,624✔
206
    auto leavescope_arg_types = instrumentation_helper.make_parameters(IType::stack_count);
1,624✔
207

208
    typeart_alloc.f        = decl.make_function(IFunc::heap, typeart_alloc.name, alloc_arg_types);
1,624✔
209
    typeart_alloc_stack.f  = decl.make_function(IFunc::stack, typeart_alloc_stack.name, alloc_arg_types);
1,624✔
210
    typeart_alloc_global.f = decl.make_function(IFunc::global, typeart_alloc_global.name, alloc_arg_types);
1,624✔
211
    typeart_free.f         = decl.make_function(IFunc::free, typeart_free.name, free_arg_types);
1,624✔
212
    typeart_leave_scope.f  = decl.make_function(IFunc::scope, typeart_leave_scope.name, leavescope_arg_types);
1,624✔
213

214
    typeart_alloc_omp.f = decl.make_function(IFunc::heap_omp, typeart_alloc_omp.name, alloc_arg_types, true);
1,624✔
215
    typeart_alloc_stacks_omp.f =
1,624✔
216
        decl.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp.name, alloc_arg_types, true);
1,624✔
217
    typeart_free_omp.f = decl.make_function(IFunc::free_omp, typeart_free_omp.name, free_arg_types, true);
1,624✔
218
    typeart_leave_scope_omp.f =
1,624✔
219
        decl.make_function(IFunc::scope_omp, typeart_leave_scope_omp.name, leavescope_arg_types, true);
1,624✔
220
  }
15,861✔
221

222
  void printStats(llvm::raw_ostream& out) {
1,624✔
223
    meminst_finder->printStats(out);
1,624✔
224

225
    const auto get_ta_mode = [&]() {
3,248✔
226
      const bool heap  = (*pass_config)[config::ConfigStdArgs::heap];
1,624✔
227
      const bool stack = (*pass_config)[config::ConfigStdArgs::stack];
1,624✔
228

229
      if (heap) {
1,624✔
230
        if (stack) {
1,119✔
231
          return " [Heap & Stack]";
330✔
232
        }
233
        return " [Heap]";
789✔
234
      }
235

236
      if (stack) {
505✔
237
        return " [Stack]";
505✔
238
      }
239

NEW
240
      llvm_unreachable("Did not find heap or stack, or combination thereof!");
×
241
    };
1,624✔
242

243
    Table stats("TypeArtPass");
1,624✔
244
    stats.wrap_header = true;
1,624✔
245
    stats.title += get_ta_mode();
1,624✔
246
    stats.put(Row::make("Malloc", NumInstrumentedMallocs.getValue()));
1,624✔
247
    stats.put(Row::make("Free", NumInstrumentedFrees.getValue()));
1,624✔
248
    stats.put(Row::make("Alloca", NumInstrumentedAlloca.getValue()));
1,624✔
249
    stats.put(Row::make("Global", NumInstrumentedGlobal.getValue()));
1,624✔
250

251
    std::ostringstream stream;
1,624✔
252
    stats.print(stream);
1,624✔
253
    out << stream.str();
1,624✔
254
  }
1,624✔
255

NEW
256
  llvm::PreservedAnalyses run(llvm::Module& m, llvm::ModuleAnalysisManager&) {
×
NEW
257
    bool changed{false};
×
NEW
258
    changed |= doInitialization(m);
×
NEW
259
    changed |= runOnModule(m);
×
NEW
260
    changed |= doFinalization();
×
NEW
261
    return changed ? llvm::PreservedAnalyses::none() : llvm::PreservedAnalyses::all();
×
262
  }
263

264
  bool runOnModule(llvm::Module& m) {
1,624✔
265
    meminst_finder->runOnModule(m);
1,624✔
266
    const bool instrument_global = (*pass_config)[config::ConfigStdArgs::global];
1,624✔
267
    bool instrumented_global{false};
1,624✔
268
    if (instrument_global) {
1,624✔
269
      declareInstrumentationFunctions(m);
835✔
270

271
      const auto& globalsList = meminst_finder->getModuleGlobals();
835✔
272
      if (!globalsList.empty()) {
835✔
273
        const auto global_count = instrumentation_context->handleGlobal(globalsList);
369✔
274
        NumInstrumentedGlobal += global_count;
369✔
275
        instrumented_global = global_count > 0;
369✔
276
      }
369✔
277
    }
835✔
278

279
    const auto instrumented_function = llvm::count_if(m.functions(), [&](auto& f) { return runOnFunc(f); }) > 0;
45,129✔
280
    return instrumented_function || instrumented_global;
1,624✔
281
  }
282

283
  bool runOnFunc(llvm::Function& f) {
43,505✔
284
    using namespace typeart;
285

286
    if (f.isDeclaration() || f.getName().startswith("__typeart")) {
43,505✔
287
      return false;
28,479✔
288
    }
289

290
    if (!meminst_finder->hasFunctionData(f)) {
15,026✔
NEW
291
      LOG_WARNING("No allocation data could be retrieved for function: " << f.getName());
×
NEW
292
      return false;
×
293
    }
294

295
    LOG_DEBUG("Running on function: " << f.getName())
296

297
    // FIXME this is required when "PassManagerBuilder::EP_OptimizerLast" is used as the function (constant) pointer are
298
    // nullpointer/invalidated
299
    declareInstrumentationFunctions(*f.getParent());
15,026✔
300

301
    bool mod{false};
15,026✔
302
    //  auto& c = f.getContext();
303
    DataLayout dl(f.getParent());
15,026✔
304

305
    llvm::SmallDenseMap<BasicBlock*, size_t> allocCounts;
15,026✔
306

307
    const auto& fData   = meminst_finder->getFunctionData(f);
15,026✔
308
    const auto& mallocs = fData.mallocs;
15,026✔
309
    const auto& allocas = fData.allocas;
15,026✔
310
    const auto& frees   = fData.frees;
15,026✔
311

312
    const bool instrument_heap  = (*pass_config)[config::ConfigStdArgs::heap];
15,026✔
313
    const bool instrument_stack = (*pass_config)[config::ConfigStdArgs::stack];
15,026✔
314

315
    if (instrument_heap) {
15,026✔
316
      // instrument collected calls of bb:
317
      const auto heap_count = instrumentation_context->handleHeap(mallocs);
8,675✔
318
      const auto free_count = instrumentation_context->handleFree(frees);
8,675✔
319

320
      NumInstrumentedMallocs += heap_count;
8,675✔
321
      NumInstrumentedFrees += free_count;
8,675✔
322

323
      mod |= heap_count > 0 || free_count > 0;
8,675✔
324
    }
8,675✔
325

326
    if (instrument_stack) {
15,026✔
327
      const auto stack_count = instrumentation_context->handleStack(allocas);
7,435✔
328
      NumInstrumentedAlloca += stack_count;
7,435✔
329
      mod |= stack_count > 0;
7,435✔
330
    }
7,435✔
331

332
    return mod;
15,026✔
333
  }
43,505✔
334
};
335

336
class LegacyTypeArtPass : public llvm::ModulePass {
337
 private:
338
  TypeArtPass pass_impl_;
339

340
 public:
341
  static char ID;  // NOLINT
342

343
  LegacyTypeArtPass() : ModulePass(ID){};
1,642✔
344

345
  bool doInitialization(llvm::Module&) override;
346

347
  bool runOnModule(llvm::Module& module) override;
348

349
  bool doFinalization(llvm::Module&) override;
350

351
  ~LegacyTypeArtPass() override = default;
3,248✔
352
};
353

354
bool LegacyTypeArtPass::doInitialization(llvm::Module& m) {
1,642✔
355
  return pass_impl_.doInitialization(m);
1,642✔
356
}
357

358
bool LegacyTypeArtPass::runOnModule(llvm::Module& module) {
1,624✔
359
  bool changed{false};
1,624✔
360
  changed |= pass_impl_.runOnModule(module);
1,624✔
361
  return changed;
1,624✔
362
}
363

364
bool LegacyTypeArtPass::doFinalization(llvm::Module&) {
1,624✔
365
  return pass_impl_.doFinalization();
1,624✔
366
  ;
367
}
368

369
}  // namespace typeart::pass
370

371
//.....................
372
// New PM
373
//.....................
NEW
374
llvm::PassPluginLibraryInfo getTypeartPassPluginInfo() {
×
NEW
375
  return {LLVM_PLUGIN_API_VERSION, "TypeART", LLVM_VERSION_STRING, [](PassBuilder& pass_builder) {
×
NEW
376
            pass_builder.registerPipelineParsingCallback(
×
NEW
377
                [](StringRef name, ModulePassManager& module_pm, ArrayRef<PassBuilder::PipelineElement>) {
×
NEW
378
                  if (name == "typeart") {
×
NEW
379
                    module_pm.addPass(typeart::pass::TypeArtPass());
×
NEW
380
                    return true;
×
381
                  }
NEW
382
                  return false;
×
NEW
383
                });
×
NEW
384
          }};
×
385
}
386

NEW
387
extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() {
×
NEW
388
  return getTypeartPassPluginInfo();
×
389
}
390

391
//.....................
392
// Old PM
393
//.....................
394
char typeart::pass::LegacyTypeArtPass::ID = 0;  // NOLINT
395

396
static RegisterPass<typeart::pass::LegacyTypeArtPass> x("typeart", "TypeArt Pass");  // NOLINT
1,642✔
397

NEW
398
ModulePass* createTypeArtPass() {
×
NEW
399
  return new typeart::pass::LegacyTypeArtPass();
×
400
}
401

NEW
402
extern "C" void AddTypeArtPass(LLVMPassManagerRef pass_manager) {
×
NEW
403
  unwrap(pass_manager)->add(createTypeArtPass());
×
404
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc