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

vla5924-practice / compiler-project / 14006464010

22 Mar 2025 07:26AM UTC coverage: 82.895% (+0.009%) from 82.886%
14006464010

Pull #197

github

web-flow
Merge 0ab7716ba into a5e3ea566
Pull Request #197: Perform convergent transformation within CascadeTransform

125 of 138 new or added lines in 8 files covered. (90.58%)

1 existing line in 1 file now uncovered.

4759 of 5741 relevant lines covered (82.89%)

268.98 hits per line

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

50.0
/compiler/lib/cli/compiler.cpp
1
#include "compiler.hpp"
2
#include "compiler/backend/optree/optimizer/transform.hpp"
3

4
#include <exception>
5
#include <iostream>
6
#include <iterator>
7
#include <string>
8
#include <string_view>
9
#include <vector>
10

11
#ifdef LLVMIR_CODEGEN_ENABLED
12
#include <cstdlib>
13
#include <filesystem>
14
#include <functional>
15
#include <ostream>
16
#endif
17

18
#include "compiler/backend/ast/optimizer/optimizer.hpp"
19
#include "compiler/backend/ast/semantizer/semantizer.hpp"
20
#include "compiler/backend/optree/optimizer/optimizer.hpp"
21
#include "compiler/backend/optree/optimizer/transform_factories.hpp"
22
#include "compiler/frontend/converter/converter.hpp"
23
#include "compiler/frontend/lexer/lexer.hpp"
24
#include "compiler/frontend/parser/parser.hpp"
25
#include "compiler/frontend/preprocessor/preprocessor.hpp"
26
#include "compiler/utils/debug.hpp"
27
#include "compiler/utils/error_buffer.hpp"
28
#include "compiler/utils/source_files.hpp"
29
#include "compiler/utils/timer.hpp"
30

31
#ifdef ENABLE_CODEGEN_AST_TO_LLVMIR
32
#include "compiler/codegen/ast_to_llvmir/ir_generator.hpp"
33
#endif
34
#ifdef ENABLE_CODEGEN_OPTREE_TO_LLVMIR
35
#include "compiler/codegen/optree_to_llvmir/llvmir_generator.hpp"
36
#endif
37

38
#include "dumping.hpp"
39
#include "helpers.hpp"
40
#include "options.hpp"
41

42
#define RETURN_IF_NONZERO(EXPR)                                                                                        \
43
    do {                                                                                                               \
44
        if (auto ret = (EXPR))                                                                                         \
45
            return ret;                                                                                                \
46
    } while (0)
47

48
#define RETURN_IF_STOPAFTER(OPTIONS, STAGE)                                                                            \
49
    do {                                                                                                               \
50
        if ((OPTIONS).stopAfter == (STAGE))                                                                            \
51
            return 0;                                                                                                  \
52
    } while (0)
53

54
using utils::SourceFile;
55
using utils::Timer;
56

57
using namespace cli;
58

59
namespace {
60

61
#ifdef LLVMIR_CODEGEN_ENABLED
62
std::string llToObj(const std::string &llcBin, const std::filesystem::path &llFile,
7✔
63
                    const std::filesystem::path &objFile) {
64
    std::vector<std::string> cmd = {
65
        llcBin,
66
#ifdef COMPILER_PLATFORM_LINUX
67
        "-relocation-model=pic",
68
#endif
69
        "-filetype=obj",
70
        llFile.string(),
71
        "-o",
72
        objFile.string(),
73
    };
63✔
74
    return makeCommand(cmd);
14✔
75
}
7✔
76

77
std::string objToExe(const std::string &clangBin, const std::filesystem::path &objFile,
7✔
78
                     const std::filesystem::path &exeFile) {
79
    std::vector<std::string> cmd = {
80
        clangBin,
81
#ifdef COMPILER_PLATFORM_LINUX
82
        "-fPIE",
83
#endif
84
        objFile.string(), "-o", exeFile.string(),
85
    };
56✔
86
    return makeCommand(cmd);
14✔
87
}
7✔
88

89
int runCommand(const std::string &cmd) {
14✔
90
    int ret = std::system(cmd.c_str());
14✔
91
    if (ret != 0) {
14✔
92
        std::cerr << "Process returned " << ret << ": " << cmd << '\n';
×
93
    }
94
    return ret;
14✔
95
}
96

97
int runLLVMIRGenerator(const Options &opt, const std::function<void(std::ostream &)> &dumpToStream,
7✔
98
                       const std::function<void(const std::string &)> &dumpToFile) {
99
    if (opt.debug) {
7✔
100
        std::cerr << "LLVMIR GENERATOR:\n";
1✔
101
        dumpToStream(std::cerr);
1✔
102
    }
103
    bool printOutput = opt.output == "-";
7✔
104
    if (!opt.compile) {
7✔
105
        if (printOutput)
×
106
            dumpToStream(std::cout);
×
107
        else
108
            dumpToFile(opt.output);
×
109
        return 0;
×
110
    }
111
    if (printOutput) {
7✔
112
        std::cerr << "Unable to print binary file to stdout. Please, provide --output argument.\n";
×
113
        return 3;
×
114
    }
115
    TemporaryDirectory tempDir;
7✔
116
    try {
117
        auto llFile = tempDir.path() / "out.ll";
7✔
118
        dumpToFile(llFile.string());
7✔
119
        auto objFile = tempDir.path() / "out.obj";
7✔
120
        auto exeFile = tempDir.path() / "out.exe";
7✔
121
        auto llcCmd = llToObj(opt.llc, llFile, objFile);
7✔
122
        auto clangCmd = objToExe(opt.clang, objFile, exeFile);
7✔
123
        if (opt.debug) {
7✔
124
            std::cerr << "Executing commands:\n"
125
                      << "  " << llcCmd << "\n"
126
                      << "  " << clangCmd << "\n";
1✔
127
        }
128
        bool cmdFailed = (runCommand(llcCmd) || runCommand(clangCmd));
7✔
129
        if (cmdFailed)
7✔
130
            return 3;
×
131
        std::filesystem::copy_file(exeFile, opt.output, std::filesystem::copy_options::overwrite_existing);
7✔
132
    } catch (std::exception &e) {
7✔
133
        std::cerr << e.what();
×
134
        return 3;
×
135
    }
×
136
    return 0;
7✔
137
}
7✔
138
#endif
139

140
} // namespace
141

142
Compiler::Compiler(const Options &options) : opt(options) {
7✔
143
    if (opt.time)
7✔
144
        measuredTimes.reserve(8);
×
145
}
7✔
146

147
int Compiler::readFiles() {
7✔
148
    if (opt.files.empty()) {
7✔
149
        std::cerr << "No files provided\n";
×
150
        return 2;
×
151
    }
152
    try {
153
        for (const std::string &path : opt.files) {
14✔
154
            if (!std::filesystem::exists(path)) {
7✔
155
                std::cerr << "File is non-existent: " << path << '\n';
×
156
                return 2;
×
157
            }
158
            SourceFile other = utils::readFile(std::filesystem::canonical(path).string());
14✔
159
            source.insert(source.end(), std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
7✔
160
            if (opt.debug)
7✔
161
                std::cerr << "Read file " << path << "\n";
1✔
162
        }
7✔
163
    } catch (std::exception &e) {
×
164
        std::cerr << e.what();
×
165
        return 3;
×
166
    }
×
167
    return 0;
7✔
168
}
169

170
int Compiler::runPreprocessor() {
7✔
171
    Timer timer;
7✔
172
    try {
173
        timer.start();
7✔
174
        source = preprocessor::Preprocessor::process(source);
7✔
175
        timer.stop();
7✔
176
    } catch (const ErrorBuffer &errors) {
×
177
        std::cerr << errors.message();
×
178
        return 3;
×
179
    }
×
180
    if (opt.debug)
7✔
181
        std::cerr << "PREPROCESSOR:\n" << dumping::dump(source);
1✔
182
    if (opt.time)
7✔
183
        measuredTimes.emplace_back(stage::preprocessor, timer.elapsed());
×
184
    return 0;
7✔
185
}
186

187
int Compiler::runLexer() {
7✔
188
    Timer timer;
7✔
189
    try {
190
        timer.start();
7✔
191
        tokens = lexer::Lexer::process(source);
7✔
192
        timer.stop();
7✔
193
    } catch (const ErrorBuffer &errors) {
×
194
        std::cerr << errors.message();
×
195
        return 3;
×
196
    }
×
197
    if (opt.debug)
7✔
198
        std::cerr << "LEXER:\n" << dumping::dump(tokens);
1✔
199
    if (opt.time)
7✔
200
        measuredTimes.emplace_back(stage::lexer, timer.elapsed());
×
201
    return 0;
7✔
202
}
203

204
int Compiler::runParser() {
7✔
205
    Timer timer;
7✔
206
    try {
207
        timer.start();
7✔
208
        tree = parser::Parser::process(tokens);
7✔
209
        timer.stop();
7✔
210
    } catch (const ErrorBuffer &errors) {
×
211
        std::cerr << errors.message();
×
212
        return 3;
×
213
    }
×
214
    if (opt.debug) {
7✔
215
        std::cerr << "PARSER:\n";
1✔
216
        tree.dump(std::cerr);
1✔
217
    }
218
    tokens.clear();
7✔
219
    if (opt.time)
7✔
220
        measuredTimes.emplace_back(stage::parser, timer.elapsed());
×
221
    return 0;
7✔
222
}
223

224
int Compiler::runConverter() {
7✔
225
    Timer timer;
7✔
226
    try {
227
        timer.start();
7✔
228
        program.root = converter::Converter::process(tree).root;
7✔
229
        timer.stop();
7✔
230
    } catch (const ErrorBuffer &errors) {
×
231
        std::cerr << errors.message();
×
232
        return 3;
×
233
    }
×
234
    if (opt.debug) {
7✔
235
        std::cerr << "CONVERTER:\n";
1✔
236
        program.root->dump(std::cerr);
1✔
237
    }
238
    if (opt.time)
7✔
239
        measuredTimes.emplace_back(stage::converter, timer.elapsed());
×
240
    return 0;
7✔
241
}
242

243
int Compiler::runAstSemantizer() {
×
244
    Timer timer;
×
245
    try {
246
        timer.start();
×
247
        semantizer::Semantizer::process(tree);
×
248
        timer.stop();
×
249
    } catch (const ErrorBuffer &errors) {
×
250
        std::cerr << errors.message();
×
251
        return 3;
×
252
    }
×
253
    if (opt.debug) {
×
254
        std::cerr << "SEMANTIZER:\n";
×
255
        tree.dump(std::cerr);
×
256
    }
257
    if (opt.time)
×
258
        measuredTimes.emplace_back(stage::semantizer, timer.elapsed());
×
259
    return 0;
×
260
}
261

262
int Compiler::runAstOptimizer() {
×
263
    Timer timer;
×
264
    try {
265
        timer.start();
×
266
        optimizer::Optimizer::process(tree);
×
267
        timer.stop();
×
268
    } catch (const ErrorBuffer &errors) {
×
269
        std::cerr << errors.message();
×
270
        return 3;
×
271
    }
×
272
    if (opt.debug) {
×
273
        std::cerr << "OPTIMIZER:\n";
×
274
        tree.dump(std::cerr);
×
275
    }
276
    if (opt.time)
×
277
        measuredTimes.emplace_back(stage::optimizer, timer.elapsed());
×
278
    return 0;
×
279
}
280

281
#ifdef ENABLE_CODEGEN_AST_TO_LLVMIR
282
int Compiler::runAstLLVMIRGenerator() {
×
283
    Timer timer;
×
284
    ir_generator::IRGenerator generator(opt.files.front());
×
285
    timer.start();
×
286
    generator.process(tree);
×
287
    timer.stop();
×
288
    if (auto ret = runLLVMIRGenerator(
×
289
            opt, [&g = generator](std::ostream &str) { str << g.dump(); },
×
290
            [&g = generator](const std::string &str) { g.writeToFile(str); })) {
×
291
        return ret;
×
292
    }
293
    if (opt.time)
×
294
        measuredTimes.emplace_back(stage::codegen, timer.elapsed());
×
295
    return 0;
×
296
}
×
297
#endif
298

299
int Compiler::runOptreeOptimizer() {
×
300
    using namespace optree::optimizer;
301
    Timer timer;
×
302
    try {
303
        Optimizer optimizer;
×
NEW
304
        auto canonicalizer = CascadeTransform::make("Canonicalizer");
×
NEW
305
        canonicalizer->add(createEraseUnusedOps());
×
NEW
306
        canonicalizer->add(createFoldConstants());
×
NEW
307
        optimizer.add(canonicalizer);
×
308
        optimizer.add(createEraseUnusedFunctions());
×
309
        timer.start();
×
310
        optimizer.process(program);
×
311
        timer.stop();
×
312
    } catch (const ErrorBuffer &errors) {
×
313
        std::cerr << errors.message();
×
314
        return 3;
×
315
    }
×
316
    if (opt.debug) {
×
317
        std::cerr << "OPTIMIZER:\n";
×
318
        program.root->dump(std::cerr);
×
319
    }
320
    if (opt.time)
×
321
        measuredTimes.emplace_back(stage::optimizer, timer.elapsed());
×
322
    return 0;
×
323
}
324

325
#ifdef ENABLE_CODEGEN_OPTREE_TO_LLVMIR
326
int Compiler::runOptreeLLVMIRGenerator() {
7✔
327
    Timer timer;
7✔
328
    optree::llvmir_generator::LLVMIRGenerator generator(opt.files.front());
7✔
329
    timer.start();
7✔
330
    generator.process(program);
7✔
331
    timer.stop();
7✔
332
    if (auto ret = runLLVMIRGenerator(
7✔
333
            opt, [&g = generator](std::ostream &str) { str << g.dump(); },
1✔
334
            [&g = generator](const std::string &str) { g.dumpToFile(str); })) {
7✔
335
        return ret;
×
336
    }
337
    if (opt.time)
7✔
338
        measuredTimes.emplace_back(stage::codegen, timer.elapsed());
×
339
    return 0;
7✔
340
}
7✔
341
#endif
342

343
int Compiler::run() {
7✔
344
    if (opt.debug) {
7✔
345
        std::cerr << "Provided options: ";
1✔
346
        opt.dump();
1✔
347
        std::cerr << '\n';
1✔
348
    }
349
    RETURN_IF_NONZERO(readFiles());
7✔
350
    RETURN_IF_NONZERO(runPreprocessor());
7✔
351
    RETURN_IF_STOPAFTER(opt, stage::preprocessor);
7✔
352
    RETURN_IF_NONZERO(runLexer());
7✔
353
    RETURN_IF_STOPAFTER(opt, stage::lexer);
7✔
354
    RETURN_IF_NONZERO(runParser());
7✔
355
    RETURN_IF_STOPAFTER(opt, stage::parser);
7✔
356
    if (opt.backend == backend::ast) {
7✔
357
        RETURN_IF_NONZERO(runAstSemantizer());
×
358
        RETURN_IF_STOPAFTER(opt, stage::semantizer);
×
359
        RETURN_IF_NONZERO(runAstOptimizer());
×
360
        RETURN_IF_STOPAFTER(opt, stage::optimizer);
×
361
#ifdef ENABLE_CODEGEN_AST_TO_LLVMIR
362
        if (opt.codegen == codegen::llvm) {
×
363
            RETURN_IF_NONZERO(runAstLLVMIRGenerator());
×
364
            RETURN_IF_STOPAFTER(opt, stage::codegen);
×
365
        } else {
366
            COMPILER_UNREACHABLE("unexpected codegen");
×
367
        }
368
#endif
369
    } else if (opt.backend == backend::optree) {
7✔
370
        RETURN_IF_NONZERO(runConverter());
7✔
371
        RETURN_IF_STOPAFTER(opt, stage::converter);
7✔
372
        if (opt.optimize) {
7✔
373
            RETURN_IF_NONZERO(runOptreeOptimizer());
×
374
            RETURN_IF_STOPAFTER(opt, stage::optimizer);
×
375
        }
376
#ifdef ENABLE_CODEGEN_OPTREE_TO_LLVMIR
377
        if (opt.codegen == codegen::llvm) {
7✔
378
            RETURN_IF_NONZERO(runOptreeLLVMIRGenerator());
7✔
379
            RETURN_IF_STOPAFTER(opt, stage::codegen);
7✔
380
        } else {
381
            COMPILER_UNREACHABLE("unexpected codegen");
×
382
        }
383
#endif
384
    } else {
385
        COMPILER_UNREACHABLE("unexpected backend");
×
386
    }
387
    return 0;
7✔
388
}
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