Skip to content

Commit 158406e

Browse files
committed
fix llvm
1 parent 0e3a528 commit 158406e

File tree

9 files changed

+188
-289
lines changed

9 files changed

+188
-289
lines changed

Diff for: Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ clean:
99
rm -f *.out.py
1010
rm -f *.wasm
1111
rm -f *.wat
12-
rm -f *.ll
12+
rm -f *.ll
13+
rm -f *.s

Diff for: README.md

+39
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Progress is documented on my [blog](https://yangdanny97.github.io/blog/):
99
- [Part 2: JVM backend](https://yangdanny97.github.io/blog/2021/08/26/chocopy-jvm-backend)
1010
- [Part 3: CIL backend](https://yangdanny97.github.io/blog/2022/05/22/chocopy-cil-backend)
1111
- [Part 4: WASM backend](https://yangdanny97.github.io/blog/2022/10/11/chocopy-wasm-backend)
12+
- [Part 5: LLVM backend - coming soon!](https://yangdanny97.github.io/blog)
1213

1314
## Features
1415

@@ -21,6 +22,7 @@ This compiler contains multiple backends not found in the reference implementati
2122
- JVM bytecode, formatted for the Krakatau assembler
2223
- CIL bytecode, formatted for the Mono ilasm assembler
2324
- WASM, in WAT format
25+
- LLVM IR, in text format
2426

2527
The test suite includes both static validation of generated/annotated ASTs, as well as runtime tests that actually execute the output programs to check correctness. Many of the AST validation test cases are taken from test suites included in the release code for Berkeley's CS164, with some additional tests written for more coverage.
2628

@@ -35,6 +37,10 @@ The test suite includes both static validation of generated/annotated ASTs, as w
3537
- WASM Backend Requirements:
3638
- [WebAssembly Binary Toolkit (wabt)](https://github.com/WebAssembly/wabt), specifically the `wat2wasm` tool
3739
- NodeJS for the runtime
40+
- LLVM Backend Requirements
41+
- LLVM toolchain
42+
- `llvmlite`
43+
- Tested with LLVM 16.0.6
3844

3945
## Usage
4046

@@ -61,6 +67,7 @@ The input file should have extension `.py`. If the output file is not provided,
6167
- `jvm` - output JVM bytecode formatted for the Krakatau assembler
6268
- `cil` - output CIL bytecode formatted for the Mono ilasm assembler
6369
- `wasm` - output WASM as plaintext in WAT format
70+
- `llvm` - output LLVM IR in text format
6471

6572
## Differences from the reference implementation:
6673

@@ -145,6 +152,38 @@ Strings, lists, objects, and refs holding nonlocals are stored in the heap, alig
145152

146153
To provide memory safety, string/list indexing have bounds checking and list operations have a null-check, which crashes the program with a generic "unreachable" instruction.
147154

155+
## LLVM Backend Notes:
156+
157+
The LLVM backend for this compiler outputs LLVM IR in plaintext `.ll` format which can be compiled using `llc` or interpreted using `lli`:
158+
1. Use this compiler to generate plaintext LLVM IR
159+
- Format: `python3 main.py --mode llvm <input file> <output dir>`
160+
- Example: `python3 main.py --mode llvm tests/runtime/binary_tree.py .`
161+
2. Run the `.ll` files using `lli`
162+
- Example: `lli <.ll file>`
163+
- Example: `lli binary_tree.ll`
164+
165+
The `demo_llvm.sh` script is a useful utility to compile and run files with the LLVM backend with a single command (provide the path to the input source file as an argument).
166+
- To run the same example as above, run `./demo_llvm.sh tests/runtime/binary_tree.py`
167+
168+
Generated programs should only depend on the C standard library, so there's no custom runtime to link to.
169+
170+
### LLVM Backend - Unsupported Features:
171+
- `input` stdlib function - TODO
172+
173+
### LLVM Backend - Memory Format, Safety, and Management:
174+
175+
- strings - null-terminated `char*`, same as C strings
176+
- lists - first 4 bytes for length, followed by the contents as a packed array
177+
- ints - 32 bits
178+
- pointers (objects, strings, lists) - same as C pointers, where `None` is the null pointer
179+
- objects - struct containing vtable address followed by attributes
180+
181+
Memory does not get freed/garbage collected once it is allocated, so large programs may run out of memory.
182+
183+
To provide some memory safety, string/list indexing have bounds checking and list operations have a null-check, which exits the program with a generic error message and line number.
184+
185+
Error handling is done using the `setjmp`/`longjmp` strategy, with the line of the error/assertion used as the argument for `longjmp`.
186+
148187
## FAQ
149188

150189
- What is this for?

Diff for: compiler/compiler.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def __init__(self):
2424
self.parser = Parser()
2525
self.typechecker = TypeChecker(self.ts)
2626

27-
def parse(self, infile) -> Node:
27+
def parse(self, infile) -> Program:
2828
astparser = self.parser
2929
# given an input file, parse it into an AST object
3030
lines = None
@@ -46,46 +46,46 @@ def parse(self, infile) -> Node:
4646
astparser.errors.append(ParseError(message))
4747
return None
4848

49-
def closurepass(self, ast: Node):
49+
def closurepass(self, ast: Program):
5050
ClosureVisitor().visit(ast)
5151
NestedFuncHoister().visit(ast)
5252
self.transformer = ClosureTransformer()
5353
self.transformer.visit(ast)
5454
return ast
5555

56-
def typecheck(self, ast: Node):
56+
def typecheck(self, ast: Program):
5757
# given an AST object, typecheck it
5858
# typechecking mutates the AST, adding types and errors
5959
self.typechecker.visit(ast)
6060
return ast
6161

62-
def emitPython(self, ast: Node):
62+
def emitPython(self, ast: Program):
6363
backend = PythonBackend()
6464
backend.visit(ast)
6565
return backend.builder
6666

67-
def emitJVM(self, main: str, ast: Node):
67+
def emitJVM(self, main: str, ast: Program):
6868
self.closurepass(ast)
6969
EmptyListTyper().visit(ast)
7070
jvm_backend = JvmBackend(main, self.transformer.ts)
7171
jvm_backend.visit(ast)
7272
return jvm_backend.classes
7373

74-
def emitCIL(self, main: str, ast: Node):
74+
def emitCIL(self, main: str, ast: Program):
7575
self.closurepass(ast)
7676
EmptyListTyper().visit(ast)
7777
cil_backend = CilBackend(main, self.transformer.ts)
7878
cil_backend.visit(ast)
7979
return cil_backend.builder
8080

81-
def emitWASM(self, main: str, ast: Node):
81+
def emitWASM(self, main: str, ast: Program):
8282
self.closurepass(ast)
8383
EmptyListTyper().visit(ast)
8484
wasm_backend = WasmBackend(main, self.transformer.ts)
8585
wasm_backend.visit(ast)
8686
return wasm_backend.builder
8787

88-
def emitLLVM(self, ast: Node):
88+
def emitLLVM(self, ast: Program):
8989
self.closurepass(ast)
9090
EmptyListTyper().visit(ast)
9191
llvm_backend = LlvmBackend(self.transformer.ts)

0 commit comments

Comments
 (0)