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

tudasc / TypeART / 12973752603

26 Jan 2025 10:22AM UTC coverage: 87.53%. First build
12973752603

Pull #152

github

web-flow
Merge 47346d838 into bddfb53e4
Pull Request #152: Pass configuration parser

90 of 215 new or added lines in 10 files covered. (41.86%)

3959 of 4523 relevant lines covered (87.53%)

113474.42 hits per line

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

80.75
/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 "configuration/Configuration.h"
17
#include "configuration/EnvironmentConfiguration.h"
18
#include "configuration/FileConfiguration.h"
19
#include "configuration/PassBuilderUtil.h"
20
#include "configuration/PassConfiguration.h"
21
#include "configuration/TypeARTOptions.h"
22
#include "instrumentation/MemOpArgCollector.h"
23
#include "instrumentation/MemOpInstrumentation.h"
24
#include "instrumentation/TypeARTFunctions.h"
25
#include "support/Logger.h"
26
#include "support/Table.h"
27
#include "typegen/TypeGenerator.h"
28

29
#include "llvm/ADT/DenseMap.h"
30
#include "llvm/ADT/STLExtras.h"
31
#include "llvm/ADT/SmallVector.h"
32
#include "llvm/ADT/Statistic.h"
33
#include "llvm/ADT/StringRef.h"
1,600✔
34
#include "llvm/IR/DataLayout.h"
1,600✔
35
#include "llvm/IR/Function.h"
1,600✔
36
#include "llvm/IR/LegacyPassManager.h"
37
#include "llvm/IR/Module.h"
38
#include "llvm/IR/PassManager.h"
39
#include "llvm/Pass.h"
40
#include "llvm/Passes/PassBuilder.h"
41
#include "llvm/Passes/PassPlugin.h"
42
#include "llvm/Support/CommandLine.h"
43
#include "llvm/Support/raw_ostream.h"
44

45
#include <cassert>
46
#include <cstddef>
1,600✔
47
#include <llvm/Support/Error.h>
48
#include <optional>
49
#include <sstream>
50
#include <string>
51
#include <utility>
52

53
namespace llvm {
54
class BasicBlock;
55
}  // namespace llvm
4,800✔
56

1,600✔
57
using namespace llvm;
58

59
extern llvm::cl::OptionCategory typeart_category;
60

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

67
#define DEBUG_TYPE "typeart"
68

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

74
namespace typeart::pass {
75

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

90
class TypeArtPass : public llvm::PassInfoMixin<TypeArtPass> {
91
  std::optional<config::TypeARTConfigOptions> pass_opts{std::nullopt};
1,642✔
92
  std::unique_ptr<config::Configuration> pass_config;
93

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

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

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

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

116
 public:
117
  TypeArtPass() = default;
4,926✔
NEW
118
  explicit TypeArtPass(config::TypeARTConfigOptions opts) : pass_opts(opts) {
×
119
    // LOG_INFO("Created with \n" << opts)
NEW
120
  }
×
121

122
  bool doInitialization(Module& m) {
1,636✔
123
    auto config_file_path = get_configuration_file_path();
1,636✔
124

125
    const auto init = config_file_path.has_value()
1,636✔
126
                          ? config::TypeARTConfigInit{config_file_path.value()}
36✔
127
                          : config::TypeARTConfigInit{{}, config::TypeARTConfigInit::FileConfigurationMode::Empty};
1,600✔
128

129
    auto typeart_config = [&](const auto& init) {
3,272✔
130
      if (init.mode == config::TypeARTConfigInit::FileConfigurationMode::Empty) {
1,636✔
131
        return config::make_typeart_configuration_from_opts(pass_opts.value_or(config::TypeARTConfigOptions{}));
6,400✔
132
      }
133
      return config::make_typeart_configuration(init);
36✔
134
    }(init);
1,636✔
135

136
    if (typeart_config) {
1,636✔
137
      LOG_INFO("Emitting TypeART configuration content\n" << typeart_config.get()->getOptions())
1,630✔
138
      pass_config = std::move(*typeart_config);
1,630✔
139
    } else {
1,630✔
140
      LOG_FATAL("Could not load TypeART configuration.")
6✔
141
      std::exit(EXIT_FAILURE);
6✔
142
    }
143

144
    meminst_finder = analysis::create_finder(*pass_config);
1,630✔
145

146
    const std::string types_file =
147
        pass_config->getValueOr(config::ConfigStdArgs::types, {config::ConfigStdArgValues::types});
1,630✔
148

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

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

161
    instrumentation_helper.setModule(m);
1,630✔
162
    ModuleData mdata{&m};
1,630✔
163
    typeManager->registerModule(mdata);
1,630✔
164

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

172
    return true;
173
  }
1,630✔
174

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

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

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

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

204
    TAFunctionDeclarator decl(m, instrumentation_helper, functions);
1,630✔
205

206
    auto alloc_arg_types      = instrumentation_helper.make_parameters(IType::ptr, IType::type_id, IType::extent);
1,630✔
207
    auto free_arg_types       = instrumentation_helper.make_parameters(IType::ptr);
1,630✔
208
    auto leavescope_arg_types = instrumentation_helper.make_parameters(IType::stack_count);
1,630✔
209

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

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

224
  void printStats(llvm::raw_ostream& out) {
1,630✔
225
    meminst_finder->printStats(out);
1,630✔
226

227
    const auto get_ta_mode = [&]() {
3,260✔
228
      const bool heap   = (*pass_config)[config::ConfigStdArgs::heap];
1,630✔
229
      const bool stack  = (*pass_config)[config::ConfigStdArgs::stack];
1,630✔
230
      const bool global = (*pass_config)[config::ConfigStdArgs::global];
1,630✔
231

232
      if (heap) {
1,630✔
233
        if (stack) {
1,125✔
234
          return " [Heap & Stack]";
330✔
235
        }
236
        return " [Heap]";
795✔
237
      }
238

239
      if (stack) {
505✔
240
        return " [Stack]";
505✔
241
      }
242

NEW
243
      if (global) {
×
NEW
244
        return " [Global]";
×
245
      }
246

NEW
247
      LOG_ERROR("Did not find heap or stack, or combination thereof!");
×
NEW
248
      assert((heap || stack || global) && "Needs stack, heap, global or combination thereof");
×
NEW
249
      return " [Unknown]";
×
250
    };
1,630✔
251

252
    Table stats("TypeArtPass");
1,630✔
253
    stats.wrap_header = true;
1,630✔
254
    stats.title += get_ta_mode();
1,630✔
255
    stats.put(Row::make("Malloc", NumInstrumentedMallocs.getValue()));
1,630✔
256
    stats.put(Row::make("Free", NumInstrumentedFrees.getValue()));
1,630✔
257
    stats.put(Row::make("Alloca", NumInstrumentedAlloca.getValue()));
1,630✔
258
    stats.put(Row::make("Global", NumInstrumentedGlobal.getValue()));
1,630✔
259

260
    std::ostringstream stream;
1,630✔
261
    stats.print(stream);
1,630✔
262
    out << stream.str();
1,630✔
263
  }
1,630✔
264

265
  llvm::PreservedAnalyses run(llvm::Module& m, llvm::ModuleAnalysisManager&) {
×
266
    bool changed{false};
×
267
    changed |= doInitialization(m);
×
268
    changed |= runOnModule(m);
×
269
    changed |= doFinalization();
×
270
    return changed ? llvm::PreservedAnalyses::none() : llvm::PreservedAnalyses::all();
×
271
  }
272

273
  bool runOnModule(llvm::Module& m) {
1,630✔
274
    meminst_finder->runOnModule(m);
1,630✔
275
    const bool instrument_global = (*pass_config)[config::ConfigStdArgs::global];
1,630✔
276
    bool globals_were_instrumented{false};
1,630✔
277
    if (instrument_global) {
1,630✔
278
      declareInstrumentationFunctions(m);
835✔
279

280
      const auto& globalsList = meminst_finder->getModuleGlobals();
835✔
281
      if (!globalsList.empty()) {
835✔
282
        const auto global_count = instrumentation_context->handleGlobal(globalsList);
369✔
283
        NumInstrumentedGlobal += global_count;
369✔
284
        globals_were_instrumented = global_count > 0;
369✔
285
      }
369✔
286
    }
835✔
287

288
    const auto instrumented_function = llvm::count_if(m.functions(), [&](auto& f) { return runOnFunc(f); }) > 0;
45,195✔
289
    return instrumented_function || globals_were_instrumented;
1,630✔
290
  }
291

292
  bool runOnFunc(llvm::Function& f) {
43,565✔
293
    using namespace typeart;
294

295
    if (f.isDeclaration() || f.getName().startswith("__typeart")) {
43,565✔
296
      return false;
28,533✔
297
    }
298

299
    if (!meminst_finder->hasFunctionData(f)) {
15,032✔
300
      LOG_WARNING("No allocation data could be retrieved for function: " << f.getName());
×
301
      return false;
×
302
    }
303

304
    LOG_DEBUG("Running on function: " << f.getName())
305

306
    // FIXME this is required when "PassManagerBuilder::EP_OptimizerLast" is used as the function (constant) pointer are
307
    // nullpointer/invalidated
308
    declareInstrumentationFunctions(*f.getParent());
15,032✔
309

310
    bool mod{false};
15,032✔
311
    //  auto& c = f.getContext();
312
    DataLayout dl(f.getParent());
15,032✔
313

314
    llvm::SmallDenseMap<BasicBlock*, size_t> allocCounts;
15,032✔
315

316
    const auto& fData   = meminst_finder->getFunctionData(f);
15,032✔
317
    const auto& mallocs = fData.mallocs;
15,032✔
318
    const auto& allocas = fData.allocas;
15,032✔
319
    const auto& frees   = fData.frees;
15,032✔
320

321
    const bool instrument_heap  = (*pass_config)[config::ConfigStdArgs::heap];
15,032✔
322
    const bool instrument_stack = (*pass_config)[config::ConfigStdArgs::stack];
15,032✔
323

324
    if (instrument_heap) {
15,032✔
325
      // instrument collected calls of bb:
326
      const auto heap_count = instrumentation_context->handleHeap(mallocs);
8,681✔
327
      const auto free_count = instrumentation_context->handleFree(frees);
8,681✔
328

329
      NumInstrumentedMallocs += heap_count;
8,681✔
330
      NumInstrumentedFrees += free_count;
8,681✔
331

332
      mod |= heap_count > 0 || free_count > 0;
8,681✔
333
    }
8,681✔
334

335
    if (instrument_stack) {
15,032✔
336
      const auto stack_count = instrumentation_context->handleStack(allocas);
7,435✔
337
      NumInstrumentedAlloca += stack_count;
7,435✔
338
      mod |= stack_count > 0;
7,435✔
339
    }
7,435✔
340

341
    return mod;
15,032✔
342
  }
43,565✔
343
};
344

345
class LegacyTypeArtPass : public llvm::ModulePass {
346
 private:
347
  TypeArtPass pass_impl_;
348

349
 public:
350
  static char ID;  // NOLINT
351

352
  LegacyTypeArtPass() : ModulePass(ID){};
1,642✔
353

354
  bool doInitialization(llvm::Module&) override;
355

356
  bool runOnModule(llvm::Module& module) override;
357

358
  bool doFinalization(llvm::Module&) override;
359

360
  ~LegacyTypeArtPass() override = default;
3,260✔
361
};
362

363
bool LegacyTypeArtPass::doInitialization(llvm::Module& m) {
1,642✔
364
  return pass_impl_.doInitialization(m);
1,642✔
365
}
366

367
bool LegacyTypeArtPass::runOnModule(llvm::Module& module) {
1,630✔
368
  bool changed{false};
1,630✔
369
  changed |= pass_impl_.runOnModule(module);
1,630✔
370
  return changed;
1,630✔
371
}
372

373
bool LegacyTypeArtPass::doFinalization(llvm::Module&) {
1,630✔
374
  return pass_impl_.doFinalization();
1,630✔
375
  ;
376
}
377

378
}  // namespace typeart::pass
379

380
//.....................
381
// New PM
382
//.....................
383
llvm::PassPluginLibraryInfo getTypeartPassPluginInfo() {
×
384
  using namespace llvm;
385
  return {LLVM_PLUGIN_API_VERSION, "TypeART", LLVM_VERSION_STRING, [](PassBuilder& pass_builder) {
×
386
            pass_builder.registerPipelineParsingCallback(
×
387
                [](StringRef name, ModulePassManager& module_pm, ArrayRef<PassBuilder::PipelineElement>) {
×
NEW
388
                  if (typeart::util::pass::checkParametrizedPassName(name, "typeart")) {
×
NEW
389
                    auto parameters = typeart::util::pass::parsePassParameters(
×
NEW
390
                        typeart::config::pass::parse_typeart_config, name, "typeart");
×
NEW
391
                    if (!parameters) {
×
NEW
392
                      LOG_FATAL("Error parsing params: " << parameters.takeError())
×
NEW
393
                      return false;
×
394
                    }
NEW
395
                    module_pm.addPass(typeart::pass::TypeArtPass(parameters.get()));
×
396
                    return true;
×
397
                  }
×
NEW
398
                  LOG_FATAL("Not a valid parametrized pass name: " << name)
×
399
                  return false;
×
400
                });
×
401
          }};
×
402
}
403

404
extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() {
×
405
  return getTypeartPassPluginInfo();
×
406
}
407

408
//.....................
409
// Old PM
410
//.....................
411
char typeart::pass::LegacyTypeArtPass::ID = 0;  // NOLINT
412

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

415
ModulePass* createTypeArtPass() {
×
416
  return new typeart::pass::LegacyTypeArtPass();
×
417
}
418

419
extern "C" void AddTypeArtPass(LLVMPassManagerRef pass_manager) {
×
420
  unwrap(pass_manager)->add(createTypeArtPass());
×
421
}
×
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