88import llvmlite .ir as ir
99import 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
1313int32_t = ir .IntType (32 ) # for ints
1414voidptr_t = ir .IntType (8 ).as_pointer ()
1515
1616
1717class 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\n 00円 ' .encode ('ascii' ))),
61+ 'fmt_s' : self .global_constant ('fmt_s' ,
62+ ir .ArrayType (int8_t , 4 ),
63+ self .make_bytearray ('%s\n 00円 ' .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\n 00円 ' .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
0 commit comments