42
42
#include < cxx/mlir/codegen.h>
43
43
#include < cxx/mlir/cxx_dialect.h>
44
44
#include < cxx/mlir/cxx_dialect_conversions.h>
45
+ #include < llvm/IR/LLVMContext.h>
46
+ #include < llvm/IR/Module.h>
45
47
#endif
46
48
47
49
#include < format>
55
57
56
58
namespace cxx {
57
59
58
- Frontend::Frontend (const CLI& cli, std::string fileName)
59
- : cli(cli), fileName_(std::move(fileName)) {
60
- diagnosticsClient_ = std::make_unique<VerifyDiagnosticsClient>();
61
- unit_ = std::make_unique<TranslationUnit>(diagnosticsClient_.get ());
60
+ struct Frontend ::Private {
61
+ Frontend& frontend;
62
+ const CLI& cli;
63
+ std::string fileName_;
64
+ std::unique_ptr<TranslationUnit> unit_;
65
+ std::unique_ptr<VerifyDiagnosticsClient> diagnosticsClient_;
66
+ std::unique_ptr<Toolchain> toolchain_;
67
+ std::vector<std::function<void ()>> actions_;
68
+ #ifdef CXX_WITH_MLIR
69
+ std::unique_ptr<mlir::MLIRContext> context_;
70
+ mlir::ModuleOp module_;
71
+ std::unique_ptr<llvm::LLVMContext> llvmContext_;
72
+ std::unique_ptr<llvm::Module> llvmModule_;
73
+ #endif
74
+ bool shouldExit_ = false ;
75
+ int exitStatus_ = 0 ;
62
76
63
- actions_.emplace_back ([this ]() { showSearchPaths (std::cerr); });
64
- actions_.emplace_back ([this ]() { preprocess (); });
65
- actions_.emplace_back ([this ]() { printPreprocessedText (); });
66
- actions_.emplace_back ([this ]() { dumpMacros (std::cout); });
67
- actions_.emplace_back ([this ]() { dumpTokens (std::cout); });
68
- actions_.emplace_back ([this ]() { unit_->preprocessor ()->squeeze (); });
69
- actions_.emplace_back ([this ]() { parse (); });
70
- actions_.emplace_back ([this ]() { dumpSymbols (std::cout); });
71
- actions_.emplace_back ([this ]() { dumpAst (); });
72
- actions_.emplace_back ([this ]() { printAstIfNeeded (); });
73
- actions_.emplace_back ([this ]() { serializeAst (); });
74
- actions_.emplace_back ([this ]() { emitIR (); });
77
+ Private (Frontend& frontend, const CLI& cli, std::string fileName);
78
+ ~Private ();
79
+
80
+ [[nodiscard]] auto needsIR () const -> bool {
81
+ return cli.opt_emit_ir || cli.opt_emit_llvm || cli.opt_S || cli.opt_c ;
82
+ }
83
+
84
+ void prepare ();
85
+ void preparePreprocessor ();
86
+ void preprocess ();
87
+ void parse ();
88
+ void showSearchPaths (std::ostream& out);
89
+ void dumpTokens (std::ostream& out);
90
+ void dumpSymbols (std::ostream& out);
91
+ void serializeAst ();
92
+ void dumpAst ();
93
+ void printAstIfNeeded ();
94
+ void generateIR ();
95
+ void emitIR ();
96
+ void emitLLVMIR ();
97
+ void printPreprocessedText ();
98
+ void dumpMacros (std::ostream& out);
99
+
100
+ [[nodiscard]] auto readAll (const std::string& fileName, std::istream& in)
101
+ -> std::optional<std::string>;
102
+
103
+ [[nodiscard]] auto readAll (const std::string& fileName)
104
+ -> std::optional<std::string>;
105
+
106
+ void withOutputStream (const std::optional<std::string>& extension,
107
+ const std::function<void (std::ostream&)>& action);
108
+
109
+ #ifdef CXX_WITH_MLIR
110
+ void withRawOutputStream (
111
+ const std::optional<std::string>& extension,
112
+ const std::function<void (llvm::raw_ostream&)>& action);
113
+ #endif
114
+ };
115
+
116
+ Frontend::Frontend (const CLI& cli, std::string fileName) {
117
+ priv = std::make_unique<Private>(*this , cli, std::move (fileName));
75
118
}
76
119
77
120
Frontend::~Frontend () {}
78
121
79
122
auto Frontend::translationUnit () const -> TranslationUnit* {
80
- return unit_.get ();
123
+ return priv-> unit_ .get ();
81
124
}
82
125
83
- auto Frontend::toolchain () const -> Toolchain* { return toolchain_.get (); }
126
+ auto Frontend::toolchain () const -> Toolchain* {
127
+ return priv->toolchain_ .get ();
128
+ }
84
129
85
- auto Frontend::fileName () const -> const std::string& { return fileName_; }
130
+ auto Frontend::fileName () const -> const std::string& {
131
+ return priv->fileName_ ;
132
+ }
86
133
87
134
void Frontend::addAction (std::function<void ()> action) {
88
- actions_.emplace_back (std::move (action));
135
+ priv-> actions_ .emplace_back (std::move (action));
89
136
}
90
137
91
138
auto Frontend::operator ()() -> bool {
92
- prepare ();
93
- preparePreprocessor ();
139
+ priv-> prepare ();
140
+ priv-> preparePreprocessor ();
94
141
95
- for (const auto & action : actions_) {
96
- if (shouldExit_) break ;
142
+ for (const auto & action : priv-> actions_ ) {
143
+ if (priv-> shouldExit_ ) break ;
97
144
action ();
98
145
}
99
146
100
- diagnosticsClient_->verifyExpectedDiagnostics ();
147
+ priv-> diagnosticsClient_ ->verifyExpectedDiagnostics ();
101
148
102
- return !diagnosticsClient_->hasErrors ();
149
+ return !priv-> diagnosticsClient_ ->hasErrors ();
103
150
}
104
151
105
- void Frontend::withOutputStream (
152
+ Frontend::Private::Private (Frontend& frontend, const CLI& cli,
153
+ std::string fileName)
154
+ : frontend(frontend), cli(cli), fileName_(std::move(fileName)) {
155
+ diagnosticsClient_ = std::make_unique<VerifyDiagnosticsClient>();
156
+ unit_ = std::make_unique<TranslationUnit>(diagnosticsClient_.get ());
157
+
158
+ actions_.emplace_back ([this ]() { showSearchPaths (std::cerr); });
159
+ actions_.emplace_back ([this ]() { preprocess (); });
160
+ actions_.emplace_back ([this ]() { printPreprocessedText (); });
161
+ actions_.emplace_back ([this ]() { dumpMacros (std::cout); });
162
+ actions_.emplace_back ([this ]() { dumpTokens (std::cout); });
163
+ actions_.emplace_back ([this ]() { unit_->preprocessor ()->squeeze (); });
164
+ actions_.emplace_back ([this ]() { parse (); });
165
+ actions_.emplace_back ([this ]() { dumpSymbols (std::cout); });
166
+ actions_.emplace_back ([this ]() { dumpAst (); });
167
+ actions_.emplace_back ([this ]() { printAstIfNeeded (); });
168
+ actions_.emplace_back ([this ]() { serializeAst (); });
169
+ actions_.emplace_back ([this ]() { generateIR (); });
170
+ actions_.emplace_back ([this ]() { emitIR (); });
171
+ actions_.emplace_back ([this ]() { emitLLVMIR (); });
172
+ }
173
+
174
+ Frontend::Private::~Private () {}
175
+
176
+ void Frontend::Private::withOutputStream (
106
177
const std::optional<std::string>& extension,
107
178
const std::function<void (std::ostream&)>& action) {
108
179
auto explicitOutput = cli.getSingle (" -o" );
@@ -123,7 +194,7 @@ void Frontend::withOutputStream(
123
194
}
124
195
125
196
#ifdef CXX_WITH_MLIR
126
- void Frontend::withRawOutputStream (
197
+ void Frontend::Private:: withRawOutputStream (
127
198
const std::optional<std::string>& extension,
128
199
const std::function<void (llvm::raw_ostream&)>& action) {
129
200
auto explicitOutput = cli.getSingle (" -o" );
@@ -145,7 +216,7 @@ void Frontend::withRawOutputStream(
145
216
}
146
217
#endif
147
218
148
- void Frontend::printPreprocessedText () {
219
+ void Frontend::Private:: printPreprocessedText () {
149
220
if (!cli.opt_E && !cli.opt_Eonly ) {
150
221
return ;
151
222
}
@@ -168,7 +239,7 @@ void Frontend::printPreprocessedText() {
168
239
});
169
240
}
170
241
171
- void Frontend::preprocess () {
242
+ void Frontend::Private:: preprocess () {
172
243
auto source = readAll (fileName_);
173
244
174
245
if (!source.has_value ()) {
@@ -182,15 +253,15 @@ void Frontend::preprocess() {
182
253
unit_->setSource (std::move (*source), fileName_);
183
254
}
184
255
185
- void Frontend::dumpMacros (std::ostream& out) {
256
+ void Frontend::Private:: dumpMacros (std::ostream& out) {
186
257
if (!cli.opt_E && !cli.opt_dM ) return ;
187
258
188
259
unit_->preprocessor ()->printMacros (out);
189
260
190
261
shouldExit_ = true ;
191
262
}
192
263
193
- void Frontend::prepare () {
264
+ void Frontend::Private:: prepare () {
194
265
auto preprocessor = unit_->preprocessor ();
195
266
196
267
const auto lang = cli.getSingle (" -x" );
@@ -287,7 +358,7 @@ void Frontend::prepare() {
287
358
unit_->control ()->setMemoryLayout (toolchain_->memoryLayout ());
288
359
}
289
360
290
- void Frontend::preparePreprocessor () {
361
+ void Frontend::Private:: preparePreprocessor () {
291
362
auto preprocessor = unit_->preprocessor ();
292
363
293
364
if (cli.opt_P ) {
@@ -331,7 +402,7 @@ void Frontend::preparePreprocessor() {
331
402
}
332
403
}
333
404
334
- void Frontend::parse () {
405
+ void Frontend::Private:: parse () {
335
406
unit_->parse (ParserConfiguration{
336
407
.checkTypes = cli.opt_fcheck || unit_->language () == LanguageKind::kC ,
337
408
.fuzzyTemplateResolution = true ,
@@ -343,7 +414,7 @@ void Frontend::parse() {
343
414
}
344
415
}
345
416
346
- void Frontend::dumpTokens (std::ostream& out) {
417
+ void Frontend::Private:: dumpTokens (std::ostream& out) {
347
418
if (!cli.opt_dump_tokens ) return ;
348
419
349
420
auto dumpTokens = DumpTokens{cli};
@@ -352,33 +423,33 @@ void Frontend::dumpTokens(std::ostream& out) {
352
423
shouldExit_ = true ;
353
424
}
354
425
355
- void Frontend::dumpSymbols (std::ostream& out) {
426
+ void Frontend::Private:: dumpSymbols (std::ostream& out) {
356
427
if (!cli.opt_dump_symbols ) return ;
357
428
auto globalScope = unit_->globalScope ();
358
429
auto globalNamespace = globalScope->owner ();
359
430
cxx::dump (out, globalNamespace);
360
431
}
361
432
362
- void Frontend::dumpAst () {
433
+ void Frontend::Private:: dumpAst () {
363
434
if (!cli.opt_ast_dump ) return ;
364
435
auto printAST = ASTPrinter{unit_.get (), std::cout};
365
436
printAST (unit_->ast ());
366
437
}
367
438
368
- void Frontend::printAstIfNeeded () {
439
+ void Frontend::Private:: printAstIfNeeded () {
369
440
if (!cli.opt_ast_print ) return ;
370
441
auto prettyPrinter = ASTPrettyPrinter{unit_.get (), std::cout};
371
442
prettyPrinter (unit_->ast ());
372
443
}
373
444
374
- void Frontend::serializeAst () {
445
+ void Frontend::Private:: serializeAst () {
375
446
if (!cli.opt_emit_ast ) return ;
376
447
auto outputFile = fs::path{fileName_}.filename ().replace_extension (" .ast" );
377
448
std::ofstream out (outputFile.string (), std::ios::binary);
378
449
(void )unit_->serialize (out);
379
450
}
380
451
381
- void Frontend::showSearchPaths (std::ostream& out) {
452
+ void Frontend::Private:: showSearchPaths (std::ostream& out) {
382
453
if (!cli.opt_v ) return ;
383
454
384
455
out << std::format (" #include <...> search starts here:\n " );
@@ -392,37 +463,72 @@ void Frontend::showSearchPaths(std::ostream& out) {
392
463
out << std::format (" End of search list.\n " );
393
464
}
394
465
395
- void Frontend::emitIR () {
396
- if (!cli.opt_emit_ir ) return ;
466
+ void Frontend::Private::generateIR () {
467
+ if (cli.opt_fsyntax_only ) return ;
468
+ if (!needsIR ()) return ;
397
469
398
470
#ifdef CXX_WITH_MLIR
399
- mlir::MLIRContext context ;
400
- context. loadDialect <mlir::cxx::CxxDialect>();
471
+ context_ = std::make_unique< mlir::MLIRContext>() ;
472
+ context_-> loadDialect <mlir::cxx::CxxDialect>();
401
473
402
- auto codegen = cxx::Codegen{context , unit_.get ()};
474
+ auto codegen = cxx::Codegen{*context_ , unit_.get ()};
403
475
404
476
auto ir = codegen (unit_->ast ());
405
477
406
- if (failed (lowerToMLIR (ir.module ))) {
407
- std::cerr << " cxx: failed to lower C++ AST to MLIR" << std::endl;
408
- shouldExit_ = true ;
409
- exitStatus_ = EXIT_FAILURE;
478
+ if (succeeded (lowerToMLIR (ir.module ))) {
479
+ module_ = ir.module ;
410
480
return ;
411
481
}
412
482
483
+ std::cerr << " cxx: failed to lower C++ AST to MLIR" << std::endl;
484
+ shouldExit_ = true ;
485
+ exitStatus_ = EXIT_FAILURE;
486
+ #endif
487
+ }
488
+
489
+ void Frontend::Private::emitIR () {
490
+ if (!cli.opt_emit_ir ) return ;
491
+
492
+ #ifdef CXX_WITH_MLIR
493
+ if (!module_) return ;
494
+
495
+ shouldExit_ = true ;
496
+
413
497
mlir::OpPrintingFlags flags;
414
498
if (cli.opt_g ) {
415
499
flags.enableDebugInfo (true , false );
416
500
}
417
501
418
502
withRawOutputStream (std::nullopt , [&](llvm::raw_ostream& out) {
419
- ir. module ->print (out, flags);
503
+ module_ ->print (out, flags);
420
504
});
421
505
422
506
#endif
423
507
}
424
508
425
- auto Frontend::readAll (const std::string& fileName, std::istream& in)
509
+ void Frontend::Private::emitLLVMIR () {
510
+ if (!cli.opt_emit_llvm ) return ;
511
+
512
+ #ifdef CXX_WITH_MLIR
513
+ if (!module_) return ;
514
+
515
+ llvmContext_ = std::make_unique<llvm::LLVMContext>();
516
+ llvmModule_ = exportToLLVMIR (module_, *llvmContext_);
517
+
518
+ if (!llvmModule_) {
519
+ std::cerr << " cxx: failed to lower MLIR module to LLVM IR" << std::endl;
520
+ shouldExit_ = true ;
521
+ exitStatus_ = EXIT_FAILURE;
522
+ return ;
523
+ }
524
+
525
+ shouldExit_ = true ;
526
+ withRawOutputStream (
527
+ " .ll" , [&](llvm::raw_ostream& out) { llvmModule_->print (out, nullptr ); });
528
+ #endif
529
+ }
530
+
531
+ auto Frontend::Private::readAll (const std::string& fileName, std::istream& in)
426
532
-> std::optional<std::string> {
427
533
std::string code;
428
534
char buffer[4 * 1024 ];
@@ -433,7 +539,7 @@ auto Frontend::readAll(const std::string& fileName, std::istream& in)
433
539
return code;
434
540
}
435
541
436
- auto Frontend::readAll (const std::string& fileName)
542
+ auto Frontend::Private:: readAll (const std::string& fileName)
437
543
-> std::optional<std::string> {
438
544
if (fileName == " -" || fileName.empty ()) return readAll (" <stdin>" , std::cin);
439
545
if (std::ifstream stream (fileName); stream) return readAll (fileName, stream);
0 commit comments