Skip to content

Commit ca1bbd6

Browse files
committed
Add APIs to the JS bindings to generate MLIR
1 parent 91093e6 commit ca1bbd6

File tree

10 files changed

+81
-13
lines changed

10 files changed

+81
-13
lines changed

packages/cxx-frontend/src/Parser.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ interface ParserParams {
5151
export class Parser {
5252
#unit: Unit | undefined;
5353
#ast: AST | undefined;
54+
#pendingAST: Promise<AST> | undefined;
5455

5556
static async init({
5657
wasm,
@@ -97,24 +98,54 @@ export class Parser {
9798
this.#unit = cxx.createUnit(source, path, { resolve, readFile });
9899
}
99100

100-
async parse() {
101+
async parse(): Promise<AST> {
102+
return await this.getASTAsync();
103+
}
104+
105+
async emitIR(): Promise<string> {
106+
const _ = await this.getASTAsync();
107+
return this.#unit?.emitIR() ?? "";
108+
}
109+
110+
async #parseHelper(): Promise<AST> {
111+
if (this.#pendingAST) {
112+
return await this.#pendingAST;
113+
}
114+
101115
if (!this.#unit) {
102-
return;
116+
throw new Error("Parser has been disposed");
103117
}
118+
104119
await this.#unit.parse();
105-
this.#ast = AST.from(this.#unit.getHandle(), this);
120+
121+
const ast = AST.from(this.#unit.getHandle(), this);
122+
123+
if (!ast) {
124+
throw new Error("Failed to create AST");
125+
}
126+
127+
this.#ast = ast;
128+
129+
return ast;
106130
}
107131

108132
dispose() {
109133
this.#unit?.delete();
110134
this.#unit = undefined;
111135
this.#ast = undefined;
136+
this.#pendingAST = undefined;
112137
}
113138

114139
getUnitHandle(): number {
115140
return this.#unit?.getUnitHandle() ?? 0;
116141
}
117142

143+
async getASTAsync(): Promise<AST> {
144+
this.#pendingAST ??= this.#parseHelper();
145+
return await this.#pendingAST;
146+
}
147+
148+
// internal
118149
getAST(): AST | undefined {
119150
return this.#ast;
120151
}

packages/cxx-frontend/src/Unit.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ export interface Unit {
2626
getHandle(): number;
2727
getUnitHandle(): number;
2828
getDiagnostics(): Diagnostic[];
29+
emitIR(): string;
2930
}

packages/cxx-frontend/src/cxx-js.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export type CXX = {
101101
TranslationUnit: TranslationUnit;
102102

103103
createUnit(source: string, path: string, api: Api): Unit;
104+
emitIR(handle: number): string;
104105
getASTKind(handle: number): number;
105106
getASTSlot(handle: number, slot: number): number;
106107
getASTSlotKind(handle: number, slot: number): ASTSlotKind;

src/frontend/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ add_executable(cxx
2626
target_link_libraries(cxx PRIVATE cxx-lsp)
2727

2828
if (CXX_ENABLE_MLIR)
29-
target_compile_definitions(cxx PRIVATE CXX_WITH_MLIR)
3029
target_link_libraries(cxx PRIVATE cxx-mlir)
3130
endif()
3231

src/js/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ add_executable(cxx-js ${SOURCES})
2727

2828
target_link_libraries(cxx-js cxx-parser embind)
2929

30+
if (CXX_ENABLE_MLIR)
31+
target_link_libraries(cxx-js cxx-mlir)
32+
endif()
33+
3034
target_link_options(cxx-js PUBLIC
3135
"SHELL:-s ENVIRONMENT=web"
3236
"SHELL:-s MINIMAL_RUNTIME"

src/js/cxx/api.cc

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@
3737
#include <optional>
3838
#include <sstream>
3939

40+
#ifdef CXX_WITH_MLIR
41+
#include <cxx/mlir/codegen.h>
42+
#include <cxx/mlir/cxx_dialect.h>
43+
#include <llvm/Support/raw_os_ostream.h>
44+
#include <mlir/IR/MLIRContext.h>
45+
#endif
46+
4047
using namespace emscripten;
4148

4249
namespace {
@@ -179,6 +186,31 @@ struct WrappedUnit {
179186

180187
co_return val{true};
181188
}
189+
190+
auto emitIR() -> std::string {
191+
#ifdef CXX_WITH_MLIR
192+
mlir::MLIRContext context;
193+
context.loadDialect<mlir::cxx::CxxDialect>();
194+
195+
cxx::Codegen codegen(context, unit.get());
196+
197+
auto ir = codegen(unit->ast());
198+
199+
mlir::OpPrintingFlags flags;
200+
flags.enableDebugInfo(true, true);
201+
202+
std::ostringstream out;
203+
llvm::raw_os_ostream os(out);
204+
ir.module->print(os, flags);
205+
os.flush();
206+
207+
auto code = out.str();
208+
209+
return code;
210+
#else
211+
return {};
212+
#endif
213+
}
182214
};
183215

184216
auto getTokenText(std::intptr_t handle, std::intptr_t unitHandle)
@@ -381,7 +413,8 @@ EMSCRIPTEN_BINDINGS(cxx) {
381413
.function("parse", &WrappedUnit::parse)
382414
.function("getHandle", &WrappedUnit::getHandle)
383415
.function("getUnitHandle", &WrappedUnit::getUnitHandle)
384-
.function("getDiagnostics", &WrappedUnit::getDiagnostics);
416+
.function("getDiagnostics", &WrappedUnit::getDiagnostics)
417+
.function("emitIR", &WrappedUnit::emitIR);
385418

386419
function("createUnit", &createUnit, allow_raw_pointers());
387420
function("getASTKind", &getASTKind);

src/mlir/cxx/mlir/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ target_link_libraries(cxx-mlir PUBLIC
2020
MLIRControlFlowDialect
2121
MLIRSCFDialect
2222
)
23+
24+
target_compile_definitions(cxx-mlir PUBLIC CXX_WITH_MLIR)
25+
2326
add_dependencies(cxx-mlir MLIRCxxOpsIncGen)
2427

2528
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")

templates/cxx-browser-esm-vite/src/main.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,10 @@ async function main() {
4444
source,
4545
});
4646

47-
parser.parse();
47+
const ast = await parser.parse();
4848

4949
const rows: string[] = [];
5050

51-
const ast = parser.getAST();
52-
5351
for (const { node, depth } of ast?.walk().preVisit() ?? []) {
5452
if (!(node instanceof AST)) {
5553
continue;

templates/cxx-parse-esm/index.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,16 @@ async function main() {
5151

5252
const parser = new Parser({ source, path: "source.cc" });
5353

54-
await parser.parse();
54+
const ast = await parser.parse();
5555

5656
const diagnostics = parser.getDiagnostics();
5757

5858
if (diagnostics.length > 0) {
5959
console.log("diagnostics", diagnostics);
6060
}
6161

62-
const ast = parser.getAST();
63-
6462
for (const { node, slot, depth } of ast?.walk().preVisit() ?? []) {
65-
if (!node instanceof AST) continue;
63+
if (!(node instanceof AST)) continue;
6664
const ind = " ".repeat(depth * 2);
6765
const kind = ASTKind[node.getKind()];
6866
const member = slot !== undefined ? `${ASTSlot[slot]}: ` : "";

templates/cxx-parse/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ async function main() {
5959
const ast = parser.getAST();
6060

6161
for (const { node, slot, depth } of ast?.walk().preVisit() ?? []) {
62-
if (!node instanceof AST) continue;
62+
if (!(node instanceof AST)) continue;
6363
const ind = " ".repeat(depth * 2);
6464
const kind = ASTKind[node.getKind()];
6565
const member = slot !== undefined ? `${ASTSlot[slot]}: ` : "";

0 commit comments

Comments
 (0)