29
29
#include < cxx/gcc_linux_toolchain.h>
30
30
#include < cxx/lexer.h>
31
31
#include < cxx/macos_toolchain.h>
32
+ #include < cxx/memory_layout.h>
32
33
#include < cxx/preprocessor.h>
33
34
#include < cxx/private/path.h>
34
35
#include < cxx/scope.h>
43
44
#include < cxx/mlir/cxx_dialect.h>
44
45
#include < cxx/mlir/cxx_dialect_conversions.h>
45
46
#include < llvm/IR/LLVMContext.h>
47
+ #include < llvm/IR/LegacyPassManager.h>
46
48
#include < llvm/IR/Module.h>
49
+ #include < llvm/MC/TargetRegistry.h>
50
+ #include < llvm/Pass.h>
51
+ #include < llvm/Support/TargetSelect.h>
52
+ #include < llvm/Target/TargetMachine.h>
47
53
#endif
48
54
49
55
#include < format>
@@ -81,6 +87,10 @@ struct Frontend::Private {
81
87
return cli.opt_emit_ir || cli.opt_emit_llvm || cli.opt_S || cli.opt_c ;
82
88
}
83
89
90
+ [[nodiscard]] auto needsLLVMIR () const -> bool {
91
+ return cli.opt_emit_llvm || cli.opt_S || cli.opt_c ;
92
+ }
93
+
84
94
void prepare ();
85
95
void preparePreprocessor ();
86
96
void preprocess ();
@@ -94,6 +104,8 @@ struct Frontend::Private {
94
104
void generateIR ();
95
105
void emitIR ();
96
106
void emitLLVMIR ();
107
+ void emitCode ();
108
+ void emitObjectFile ();
97
109
void printPreprocessedText ();
98
110
void dumpMacros (std::ostream& out);
99
111
@@ -109,7 +121,7 @@ struct Frontend::Private {
109
121
#ifdef CXX_WITH_MLIR
110
122
void withRawOutputStream (
111
123
const std::optional<std::string>& extension,
112
- const std::function<void (llvm::raw_ostream &)>& action);
124
+ const std::function<void (llvm::raw_pwrite_stream &)>& action);
113
125
#endif
114
126
};
115
127
@@ -169,6 +181,7 @@ Frontend::Private::Private(Frontend& frontend, const CLI& cli,
169
181
actions_.emplace_back ([this ]() { generateIR (); });
170
182
actions_.emplace_back ([this ]() { emitIR (); });
171
183
actions_.emplace_back ([this ]() { emitLLVMIR (); });
184
+ actions_.emplace_back ([this ]() { emitCode (); });
172
185
}
173
186
174
187
Frontend::Private::~Private () {}
@@ -196,7 +209,7 @@ void Frontend::Private::withOutputStream(
196
209
#ifdef CXX_WITH_MLIR
197
210
void Frontend::Private::withRawOutputStream (
198
211
const std::optional<std::string>& extension,
199
- const std::function<void (llvm::raw_ostream &)>& action) {
212
+ const std::function<void (llvm::raw_pwrite_stream &)>& action) {
200
213
auto explicitOutput = cli.getSingle (" -o" );
201
214
202
215
if (explicitOutput == " -" || (!explicitOutput.has_value () &&
@@ -507,7 +520,7 @@ void Frontend::Private::emitIR() {
507
520
}
508
521
509
522
void Frontend::Private::emitLLVMIR () {
510
- if (!cli. opt_emit_llvm ) return ;
523
+ if (!needsLLVMIR () ) return ;
511
524
512
525
#ifdef CXX_WITH_MLIR
513
526
if (!module_) return ;
@@ -522,9 +535,76 @@ void Frontend::Private::emitLLVMIR() {
522
535
return ;
523
536
}
524
537
538
+ if (!cli.opt_emit_llvm ) return ;
539
+
525
540
shouldExit_ = true ;
541
+
526
542
withRawOutputStream (
527
543
" .ll" , [&](llvm::raw_ostream& out) { llvmModule_->print (out, nullptr ); });
544
+
545
+ #endif
546
+ }
547
+
548
+ void Frontend::Private::emitCode () {
549
+ if (!cli.opt_S && !cli.opt_c ) return ;
550
+ #ifdef CXX_WITH_MLIR
551
+ llvm::InitializeAllAsmPrinters ();
552
+
553
+ auto triple = toolchain_->memoryLayout ()->triple ();
554
+
555
+ std::string error;
556
+ auto target = llvm::TargetRegistry::lookupTarget (triple, error);
557
+
558
+ if (!target) {
559
+ std::cerr << std::format (" cxx: cannot find target for triple '{}': {}\n " ,
560
+ triple, error);
561
+ shouldExit_ = true ;
562
+ exitStatus_ = EXIT_FAILURE;
563
+ return ;
564
+ }
565
+
566
+ llvm::TargetOptions opt;
567
+
568
+ auto RM = std::optional<llvm::Reloc::Model>();
569
+
570
+ auto targetMachine =
571
+ target->createTargetMachine (triple, " generic" , " " , opt, RM);
572
+
573
+ if (!targetMachine) {
574
+ std::cerr << std::format (" cxx: cannot create target machine for '{}': {}\n " ,
575
+ triple, error);
576
+ shouldExit_ = true ;
577
+ exitStatus_ = EXIT_FAILURE;
578
+ return ;
579
+ }
580
+
581
+ std::string extension;
582
+ if (cli.opt_S ) {
583
+ extension = " .s" ;
584
+ } else if (cli.opt_c ) {
585
+ extension = " .o" ;
586
+ }
587
+
588
+ withRawOutputStream (extension, [&](llvm::raw_pwrite_stream& out) {
589
+ llvm::legacy::PassManager pm;
590
+
591
+ llvm::CodeGenFileType fileType;
592
+ if (cli.opt_S ) {
593
+ fileType = llvm::CodeGenFileType::AssemblyFile;
594
+ } else {
595
+ fileType = llvm::CodeGenFileType::ObjectFile;
596
+ }
597
+
598
+ if (targetMachine->addPassesToEmitFile (pm, out, nullptr , fileType)) {
599
+ std::cerr << " cxx: target machine cannot emit assembly\n " ;
600
+ shouldExit_ = true ;
601
+ exitStatus_ = EXIT_FAILURE;
602
+ return ;
603
+ }
604
+
605
+ pm.run (*llvmModule_);
606
+ out.flush ();
607
+ });
528
608
#endif
529
609
}
530
610
0 commit comments