Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 731f07e

Browse files
variables, assignments, conditionals
1 parent c9e2fba commit 731f07e

File tree

4 files changed

+127
-40
lines changed

4 files changed

+127
-40
lines changed

‎compiler/llvm_backend.py‎

Lines changed: 116 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@
88
import llvmlite.ir as ir
99
import llvmlite.binding as llvm
1010

11-
12-
int8_t = ir.IntType(8) # for booleans
11+
bool_t=ir.IntType(1) # for booleans
12+
int8_t = ir.IntType(8) # chars
1313
int32_t = ir.IntType(32) # for ints
1414
voidptr_t = ir.IntType(8).as_pointer()
1515

1616

1717
class LlvmBackend(Visitor):
1818
locals = []
1919
counter = 0
20+
globals = {}
21+
externs = {}
2022

2123
def __init__(self, ts: TypeSystem):
2224
llvm.initialize()
@@ -45,17 +47,54 @@ def newLocal(self):
4547
# TOP LEVEL & DECLARATIONS
4648

4749
def Program(self, node: Program):
50+
# globals for commonly used strings
51+
self.globals = {
52+
'true': self.global_constant('true',
53+
ir.ArrayType(int8_t, 5),
54+
self.make_bytearray('True00円'.encode('ascii'))),
55+
'false': self.global_constant('false',
56+
ir.ArrayType(int8_t, 6),
57+
self.make_bytearray('False00円'.encode('ascii'))),
58+
'fmt_i': self.global_constant('fmt_i',
59+
ir.ArrayType(int8_t, 4),
60+
self.make_bytearray('%i\n00円'.encode('ascii'))),
61+
'fmt_s': self.global_constant('fmt_s',
62+
ir.ArrayType(int8_t, 4),
63+
self.make_bytearray('%s\n00円'.encode('ascii'))),
64+
'fmt_assert': self.global_constant('fmt_assert',
65+
ir.ArrayType(int8_t, 29),
66+
self.make_bytearray('Assertion failed on line %i\n00円'.encode('ascii')))
67+
}
68+
69+
printf_t = ir.FunctionType(int32_t, [voidptr_t], True)
70+
self.externs['printf'] = ir.Function(self.module, printf_t, 'printf')
71+
setjmp_t = ir.FunctionType(int32_t, [int32_t], True)
72+
self.externs['setjmp'] = ir.Function(self.module, setjmp_t, 'setjmp')
73+
# TODO make this the right type
74+
longjmp_t = ir.FunctionType(int32_t, [int32_t], True)
75+
self.externs['longjmp'] = ir.Function(
76+
self.module, longjmp_t, 'longjmp')
77+
4878
funcType = ir.FunctionType(ir.VoidType(), [])
4979
func = ir.Function(self.module, funcType, "__main__")
80+
5081
self.enterScope()
51-
bb_entry = func.append_basic_block('entry')
52-
self.builder = ir.IRBuilder(bb_entry)
82+
entry_block = func.append_basic_block('entry')
83+
self.builder = ir.IRBuilder(entry_block)
84+
self.visitStmtList(
85+
[d for d in node.declarations if isinstance(d, VarDef)])
5386
self.visitStmtList(node.statements)
5487
self.builder.ret_void()
5588
self.exitScope()
5689

5790
def VarDef(self, node: VarDef):
58-
pass
91+
val = self.visit(node.value)
92+
saved_block = self.builder.block
93+
addr = self.create_entry_block_alloca(
94+
node.getName(), node.var.t.getLLVMType())
95+
self.builder.position_at_end(saved_block)
96+
self.builder.store(val, addr)
97+
self.locals[-1][node.getName()] = addr
5998

6099
def ClassDef(self, node: ClassDef):
61100
pass
@@ -82,14 +121,18 @@ def FuncDef(self, node: FuncDef):
82121

83122
# STATEMENTS
84123

85-
def NonLocalDecl(self, node: NonLocalDecl):
86-
pass
87-
88-
def GlobalDecl(self, node: GlobalDecl):
89-
pass
90-
91124
def AssignStmt(self, node: AssignStmt):
92-
pass
125+
val = self.visit(node.value)
126+
for var in node.targets[::-1]:
127+
if isinstance(var, MemberExpr):
128+
raise Exception("unimplemented")
129+
elif isinstance(var, IndexExpr):
130+
raise Exception("unimplemented")
131+
elif isinstance(var, Identifier):
132+
addr = self.locals[-1][var.name]
133+
self.builder.store(val, addr)
134+
else:
135+
raise Exception("Illegal assignment")
93136

94137
def IfStmt(self, node: IfStmt):
95138
pass
@@ -164,7 +207,7 @@ def UnaryExpr(self, node: UnaryExpr):
164207
val = self.visit(node.operand)
165208
return self.builder.neg(val)
166209
elif node.operator == "not":
167-
false = ir.Constant(int8_t, 0)
210+
false = ir.Constant(bool_t, 0)
168211
val = self.visit(node.operand)
169212
return self.builder.icmp_unsigned('==', false, val)
170213

@@ -195,33 +238,63 @@ def ReturnStmt(self, node: ReturnStmt):
195238

196239
def Identifier(self, node: Identifier):
197240
addr = self.locals[-1][node.name]
241+
assert addr is not None
198242
return self.builder.load(addr, node.name)
199243

200244
def MemberExpr(self, node: MemberExpr):
201245
pass
202246

203247
def IfExpr(self, node: IfExpr):
204-
pass
248+
return self.ifHelper(lambda: self.visit(node.condition),
249+
lambda: self.visit(node.thenExpr),
250+
lambda: self.visit(node.elseExpr),
251+
node.inferredType.getLLVMType())
252+
253+
def ifHelper(self, condFn, thenFn, elseFn, t):
254+
cond = condFn()
255+
256+
then_block = self.builder.append_basic_block()
257+
else_block = self.builder.append_basic_block()
258+
merge_block = self.builder.append_basic_block()
259+
self.builder.cbranch(cond, then_block, else_block)
260+
261+
self.builder.position_at_start(then_block)
262+
then_val = thenFn()
263+
self.builder.branch(merge_block)
264+
then_block = self.builder.block
265+
266+
self.builder.position_at_start(else_block)
267+
else_val = elseFn()
268+
self.builder.branch(merge_block)
269+
else_block = self.builder.block
270+
271+
self.builder.position_at_start(merge_block)
272+
273+
phi = self.builder.phi(t)
274+
phi.add_incoming(then_val, then_block)
275+
phi.add_incoming(else_val, else_block)
276+
return phi
205277

206278
def MethodCallExpr(self, node: MethodCallExpr):
207279
pass
208280

209281
# LITERALS
210282

211283
def BooleanLiteral(self, node: BooleanLiteral):
212-
return ir.Constant(int8_t, 1 if node.value else 0)
284+
return ir.Constant(bool_t, 1 if node.value else 0)
213285

214286
def IntegerLiteral(self, node: IntegerLiteral):
215287
return ir.Constant(int32_t, node.value)
216288

217289
def NoneLiteral(self, node: NoneLiteral):
218-
return ir.Constant(int32_t, 0)
290+
return ir.Constant(ir.PointerType(None), None)
219291

220292
def StringLiteral(self, node: StringLiteral):
221293
const = self.make_bytearray((node.value + '00円').encode('ascii'))
222-
alloca = self.builder.alloca(ir.ArrayType(int8_t, len(node.value) + 1), name=self.newLocal())
294+
alloca = self.builder.alloca(ir.ArrayType(
295+
int8_t, len(node.value) + 1), name=self.newLocal())
223296
self.builder.store(const, alloca)
224-
return alloca
297+
return self.builder.bitcast(alloca, voidptr_t)
225298

226299
# TYPES
227300

@@ -238,13 +311,18 @@ def ClassType(self, node: ClassType):
238311

239312
def emit_print(self, arg: Expr):
240313
if isinstance(arg.inferredType, ListValueType) or arg.inferredType.className not in {"bool", "int", "str"}:
241-
raise Exception("unsupported")
314+
raise Exception("Only bool, int, or str may be printed")
242315
if arg.inferredType.className == "bool":
243-
raise Exception("TODO")
316+
text = self.ifHelper(
317+
lambda: arg,
318+
lambda: self.builder.bitcast(self.globals['true'], voidptr_t),
319+
lambda: self.builder.bitcast(self.globals['false'], voidptr_t),
320+
voidptr_t)
321+
return self.printf(self.globals['fmt_s'], True, text)
244322
elif arg.inferredType.className == 'int':
245-
return self.printf("%i\n", False, self.visit(arg))
323+
return self.printf(self.globals['fmt_i'], False, self.visit(arg))
246324
else:
247-
return self.printf("%s\n", True, self.visit(arg))
325+
return self.printf(self.globals['fmt_s'], True, self.visit(arg))
248326

249327
# UTILS
250328

@@ -259,16 +337,19 @@ def is_null(self, value):
259337
def is_nonnull(self, value):
260338
return self.builder.icmp_unsigned('!=', value.type(None), value)
261339

262-
def printf(self, format: str, cast: bool, arg):
263-
func_t = ir.FunctionType(int32_t, [voidptr_t], True)
264-
fmt_bytes = self.make_bytearray((format + '00円').encode('ascii'))
265-
alloca = self.builder.alloca(ir.ArrayType(int8_t, 4), name=self.newLocal())
266-
self.builder.store(fmt_bytes, alloca)
267-
try:
268-
fn = self.module.get_global('printf')
269-
except KeyError:
270-
fn = ir.Function(self.module, func_t, 'printf')
271-
fmt_ptr = self.builder.bitcast(alloca, voidptr_t)
272-
if cast:
273-
arg = self.builder.bitcast(arg, voidptr_t)
274-
return self.builder.call(fn, [fmt_ptr, arg])
340+
def printf(self, format, cast: bool, arg):
341+
fmt_ptr = self.builder.bitcast(format, voidptr_t)
342+
return self.builder.call(self.externs['printf'], [fmt_ptr, arg])
343+
344+
def create_entry_block_alloca(self, name, t):
345+
builder = ir.IRBuilder()
346+
builder.position_at_start(self.builder.function.entry_basic_block)
347+
return builder.alloca(t, size=None, name=name)
348+
349+
def global_constant(self, name, t, value):
350+
module = self.module
351+
data = ir.GlobalVariable(module, t, name, 0)
352+
data.linkage = 'internal'
353+
data.global_constant = True
354+
data.initializer = value
355+
return data

‎compiler/types/classvaluetype.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,13 @@ def toJSON(self, dump_location=True) -> dict:
130130

131131
def getLLVMType(self) -> ir.Type:
132132
if self.className == SpecialClass.BOOL:
133-
return ir.IntType(8)
133+
return ir.IntType(1)
134134
elif self.className == SpecialClass.STR:
135-
raise ir.IntType(8).as_pointer()
135+
return ir.IntType(8).as_pointer()
136136
elif self.className == SpecialClass.OBJECT:
137137
raise Exception("unsupported")
138138
elif self.className == SpecialClass.NONE:
139-
raise ir.VoidType()
139+
return ir.VoidType()
140140
elif self.className == SpecialClass.EMPTY:
141141
raise Exception("unsupported")
142142
elif self.className == SpecialClass.INT:

‎foobar.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1-
print(-5 % -2)
1+
x: str = "1"
2+
y: str = "0"
3+
print(x)
4+
print(y)
5+
x = y = "2"
6+
print(x)
7+
print(y)

‎main.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
'jvm - output JVM bytecode formatted for the Krakatau assembler\n' +
1414
'cil - output CIL bytecode formatted for the Mono ilasm assembler\n' +
1515
'wasm - output WASM in WAT format\n' +
16-
'llvm - output LLVM\n'
16+
'llvm - output LLVM IR\n'
1717
)
1818

1919

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /