Skip to content

Commit f7b4e4e

Browse files
committed
Add DLTI data layout to the cxx IR code
Also, implement -c and -S options to the CLI.
1 parent bc4bfd5 commit f7b4e4e

12 files changed

+165
-8
lines changed

src/frontend/cxx/frontend.cc

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <cxx/gcc_linux_toolchain.h>
3030
#include <cxx/lexer.h>
3131
#include <cxx/macos_toolchain.h>
32+
#include <cxx/memory_layout.h>
3233
#include <cxx/preprocessor.h>
3334
#include <cxx/private/path.h>
3435
#include <cxx/scope.h>
@@ -43,7 +44,12 @@
4344
#include <cxx/mlir/cxx_dialect.h>
4445
#include <cxx/mlir/cxx_dialect_conversions.h>
4546
#include <llvm/IR/LLVMContext.h>
47+
#include <llvm/IR/LegacyPassManager.h>
4648
#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>
4753
#endif
4854

4955
#include <format>
@@ -81,6 +87,10 @@ struct Frontend::Private {
8187
return cli.opt_emit_ir || cli.opt_emit_llvm || cli.opt_S || cli.opt_c;
8288
}
8389

90+
[[nodiscard]] auto needsLLVMIR() const -> bool {
91+
return cli.opt_emit_llvm || cli.opt_S || cli.opt_c;
92+
}
93+
8494
void prepare();
8595
void preparePreprocessor();
8696
void preprocess();
@@ -94,6 +104,8 @@ struct Frontend::Private {
94104
void generateIR();
95105
void emitIR();
96106
void emitLLVMIR();
107+
void emitCode();
108+
void emitObjectFile();
97109
void printPreprocessedText();
98110
void dumpMacros(std::ostream& out);
99111

@@ -109,7 +121,7 @@ struct Frontend::Private {
109121
#ifdef CXX_WITH_MLIR
110122
void withRawOutputStream(
111123
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);
113125
#endif
114126
};
115127

@@ -169,6 +181,7 @@ Frontend::Private::Private(Frontend& frontend, const CLI& cli,
169181
actions_.emplace_back([this]() { generateIR(); });
170182
actions_.emplace_back([this]() { emitIR(); });
171183
actions_.emplace_back([this]() { emitLLVMIR(); });
184+
actions_.emplace_back([this]() { emitCode(); });
172185
}
173186

174187
Frontend::Private::~Private() {}
@@ -196,7 +209,7 @@ void Frontend::Private::withOutputStream(
196209
#ifdef CXX_WITH_MLIR
197210
void Frontend::Private::withRawOutputStream(
198211
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) {
200213
auto explicitOutput = cli.getSingle("-o");
201214

202215
if (explicitOutput == "-" || (!explicitOutput.has_value() &&
@@ -507,7 +520,7 @@ void Frontend::Private::emitIR() {
507520
}
508521

509522
void Frontend::Private::emitLLVMIR() {
510-
if (!cli.opt_emit_llvm) return;
523+
if (!needsLLVMIR()) return;
511524

512525
#ifdef CXX_WITH_MLIR
513526
if (!module_) return;
@@ -522,9 +535,76 @@ void Frontend::Private::emitLLVMIR() {
522535
return;
523536
}
524537

538+
if (!cli.opt_emit_llvm) return;
539+
525540
shouldExit_ = true;
541+
526542
withRawOutputStream(
527543
".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+
});
528608
#endif
529609
}
530610

src/mlir/cxx/mlir/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@ target_link_libraries(cxx-mlir PUBLIC
3737
MLIRLLVMToLLVMIRTranslation
3838
MLIRPass
3939
MLIRTargetLLVMIRExport
40+
MLIRTargetLLVMIRImport
4041
MLIRTransforms
4142
)
4243

44+
if (EMSCRIPTEN)
45+
target_link_libraries(cxx-mlir PUBLIC LLVMWebAssemblyCodeGen)
46+
endif()
47+
4348
target_compile_definitions(cxx-mlir PUBLIC CXX_WITH_MLIR)
4449

4550
add_dependencies(cxx-mlir MLIRCxxOpsIncGen)

src/mlir/cxx/mlir/CxxOps.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def Cxx_Dialect : Dialect {
3030
let name = "cxx";
3131
let cppNamespace = "mlir::cxx";
3232
let useDefaultTypePrinterParser = 1;
33-
let dependentDialects = ["mlir::cf::ControlFlowDialect" ];
33+
let dependentDialects = ["mlir::cf::ControlFlowDialect", "mlir::DLTIDialect", "mlir::LLVM::LLVMDialect"];
3434
}
3535

3636
class Cxx_Type<string name, string typeMnemonic, list<Trait> traits = []>
@@ -405,4 +405,4 @@ def Cxx_TodoStmtOp : Cxx_Op<"todo.stmt"> {
405405
let arguments = (ins StringProp:$message);
406406
let results = (outs);
407407
let assemblyFormat = "$message attr-dict";
408-
}
408+
}

src/mlir/cxx/mlir/codegen_units.cc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,21 @@
2323
// cxx
2424
#include <cxx/ast.h>
2525
#include <cxx/ast_visitor.h>
26+
#include <cxx/control.h>
27+
#include <cxx/memory_layout.h>
2628
#include <cxx/translation_unit.h>
2729

30+
// mlir
31+
#include <llvm/IR/DataLayout.h>
32+
#include <llvm/MC/TargetRegistry.h>
33+
#include <llvm/Support/Error.h>
34+
#include <llvm/Support/TargetSelect.h>
35+
#include <llvm/Target/TargetMachine.h>
36+
#include <mlir/Dialect/DLTI/DLTI.h>
37+
#include <mlir/Target/LLVMIR/Import.h>
38+
39+
#include <format>
40+
2841
namespace cxx {
2942

3043
namespace {
@@ -57,11 +70,44 @@ auto Codegen::operator()(UnitAST* ast) -> UnitResult {
5770
}
5871

5972
auto Codegen::UnitVisitor::operator()(TranslationUnitAST* ast) -> UnitResult {
73+
llvm::InitializeAllTargetInfos();
74+
llvm::InitializeAllTargets();
75+
llvm::InitializeAllTargetMCs();
76+
6077
auto loc = gen.builder_.getUnknownLoc();
6178
auto name = gen.unit_->fileName();
6279
auto module = gen.builder_.create<mlir::ModuleOp>(loc, name);
6380
gen.builder_.setInsertionPointToStart(module.getBody());
6481

82+
auto memoryLayout = gen.control()->memoryLayout();
83+
84+
auto triple = gen.control()->memoryLayout()->triple();
85+
86+
std::string error;
87+
auto target = llvm::TargetRegistry::lookupTarget(triple, error);
88+
89+
if (!target) {
90+
cxx_runtime_error(std::format("failed to find target for triple '{}': {}",
91+
triple, error));
92+
}
93+
94+
llvm::TargetOptions opt;
95+
96+
auto RM = std::optional<llvm::Reloc::Model>();
97+
98+
auto targetMachine =
99+
target->createTargetMachine(triple, "generic", "", opt, RM);
100+
101+
auto llvmDataLayout = targetMachine->createDataLayout();
102+
103+
auto dataLayout =
104+
mlir::translateDataLayout(llvmDataLayout, module->getContext());
105+
106+
module->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dataLayout);
107+
108+
module->setAttr("cxx.triple", mlir::StringAttr::get(module->getContext(),
109+
memoryLayout->triple()));
110+
65111
std::swap(gen.module_, module);
66112

67113
ForEachExternalDefinition forEachExternalDefinition;

src/mlir/cxx/mlir/cxx_dialect.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
// mlir
2424
#include <llvm/ADT/TypeSwitch.h>
2525
#include <mlir/Dialect/ControlFlow/IR/ControlFlowOps.h>
26+
#include <mlir/Dialect/DLTI/DLTI.h>
2627
#include <mlir/Dialect/Func/IR/FuncOps.h>
28+
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
2729
#include <mlir/Dialect/SCF/IR/SCF.h>
2830
#include <mlir/IR/Builders.h>
2931
#include <mlir/IR/DialectImplementation.h>

src/mlir/cxx/mlir/cxx_dialect_conversions.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@
2424
#include <cxx/mlir/cxx_dialect.h>
2525

2626
// mlir
27+
#include <llvm/IR/DataLayout.h>
2728
#include <llvm/IR/Module.h>
29+
#include <llvm/Support/Error.h>
2830
#include <mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h>
2931
#include <mlir/Conversion/LLVMCommon/TypeConverter.h>
3032
#include <mlir/Dialect/ControlFlow/IR/ControlFlowOps.h>
33+
#include <mlir/Dialect/DLTI/DLTI.h>
3134
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
3235
#include <mlir/Pass/Pass.h>
3336
#include <mlir/Pass/PassManager.h>
@@ -1085,6 +1088,7 @@ class CxxToLLVMLoweringPass
10851088
auto getArgument() const -> StringRef override { return "cxx-to-llvm"; }
10861089

10871090
void getDependentDialects(DialectRegistry &registry) const override {
1091+
registry.insert<DLTIDialect>();
10881092
registry.insert<LLVM::LLVMDialect>();
10891093
}
10901094

@@ -1097,9 +1101,6 @@ void CxxToLLVMLoweringPass::runOnOperation() {
10971101
auto context = &getContext();
10981102
auto module = getOperation();
10991103

1100-
// set up the data layout
1101-
DataLayout dataLayout(module);
1102-
11031104
// set up the type converter
11041105
LLVMTypeConverter typeConverter{context};
11051106

src/parser/cxx/gcc_linux_toolchain.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ GCCLinuxToolchain::GCCLinuxToolchain(Preprocessor* preprocessor,
3232
: Toolchain(preprocessor), arch_(std::move(arch)) {
3333
if (arch_ == "aarch64") {
3434
memoryLayout()->setSizeOfLongDouble(8);
35+
memoryLayout()->setTriple("aarch64-linux");
3536
} else if (arch_ == "x86_64") {
3637
memoryLayout()->setSizeOfLongDouble(16);
38+
memoryLayout()->setTriple("x86_64-linux");
3739
} else {
3840
cxx_runtime_error(std::format("Unsupported architecture: {}", arch_));
3941
}

src/parser/cxx/macos_toolchain.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ MacOSToolchain::MacOSToolchain(Preprocessor* preprocessor, std::string arch)
4242

4343
if (arch_ == "aarch64") {
4444
memoryLayout()->setSizeOfLongDouble(8);
45+
memoryLayout()->setTriple("aarch64-darwin");
4546
} else if (arch_ == "x86_64") {
4647
memoryLayout()->setSizeOfLongDouble(16);
48+
memoryLayout()->setTriple("x86_64-apple-darwin24.6.0");
4749
} else {
4850
cxx_runtime_error(std::format("Unsupported architecture: {}", arch_));
4951
}

src/parser/cxx/memory_layout.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,4 +326,10 @@ auto MemoryLayout::alignmentOf(const Type* type) const
326326
return visit(AlignmentOf{*this}, type);
327327
}
328328

329+
auto MemoryLayout::triple() const -> const std::string& { return triple_; }
330+
331+
void MemoryLayout::setTriple(std::string triple) {
332+
triple_ = std::move(triple);
333+
}
334+
329335
} // namespace cxx

src/parser/cxx/memory_layout.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,16 @@ class MemoryLayout {
5050
[[nodiscard]] auto alignmentOf(const Type* type) const
5151
-> std::optional<std::size_t>;
5252

53+
[[nodiscard]] auto triple() const -> const std::string&;
54+
void setTriple(std::string triple);
55+
5356
private:
5457
std::size_t bits_ = 0;
5558
std::size_t sizeOfPointer_ = 0;
5659
std::size_t sizeOfLong_ = 0;
5760
std::size_t sizeOfLongLong_ = 0;
5861
std::size_t sizeOfLongDouble_ = 0;
62+
std::string triple_;
5963
};
6064

6165
#undef DECLARE_METHOD

0 commit comments

Comments
 (0)