Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1b9236f

Browse files
author
whitequark
committedNov 9, 2016
now as SSA (WIP)
1 parent 124b257 commit 1b9236f

File tree

2 files changed

+70
-33
lines changed

2 files changed

+70
-33
lines changed
 

‎artiq/compiler/transforms/llvm_ir_generator.py

+67-33
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ def __init__(self, engine, module_name, target, embedding_map):
135135
self.llfunction = None
136136
self.llmap = {}
137137
self.llobject_map = {}
138+
self.llnowptr = None
138139
self.phis = []
139140
self.debug_info_emitter = DebugInfoEmitter(self.llmodule)
140141
self.empty_metadata = self.llmodule.add_metadata([])
@@ -146,10 +147,6 @@ def __init__(self, engine, module_name, target, embedding_map):
146147
self.tbaa_tree,
147148
ll.Constant(lli64, 1)
148149
])
149-
self.tbaa_now = self.llmodule.add_metadata([
150-
ll.MetaDataString(self.llmodule, "timeline position"),
151-
self.tbaa_tree
152-
])
153150

154151
def needs_sret(self, lltyp, may_be_large=True):
155152
if isinstance(lltyp, ll.VoidType):
@@ -183,14 +180,20 @@ def llty_of_type(self, typ, bare=False, for_return=False):
183180
elif types._is_pointer(typ):
184181
return llptr
185182
elif types.is_function(typ):
186-
sretarg = []
187183
llretty = self.llty_of_type(typ.ret, for_return=True)
188184
if self.needs_sret(llretty):
189185
sretarg = [llretty.as_pointer()]
190-
llretty = llvoid
186+
llretty = lli64
187+
elif llretty != llvoid:
188+
sretarg = []
189+
llretty = ll.LiteralStructType([lli64, llretty])
190+
else:
191+
sretarg = []
192+
llretty = lli64
191193

192194
envarg = llptr
193-
llty = ll.FunctionType(args=sretarg + [envarg] +
195+
nowarg = lli64
196+
llty = ll.FunctionType(args=sretarg + [nowarg, envarg] +
194197
[self.llty_of_type(typ.args[arg])
195198
for arg in typ.args] +
196199
[self.llty_of_type(ir.TOption(typ.optargs[arg]))
@@ -354,8 +357,6 @@ def llbuiltin(self, name):
354357
llty = ll.FunctionType(llvoid, [lli32, llptr, llptrptr])
355358
elif name == "recv_rpc":
356359
llty = ll.FunctionType(lli32, [llptr])
357-
elif name == "now":
358-
llty = lli64
359360
elif name == "watchdog_set":
360361
llty = ll.FunctionType(lli32, [lli64])
361362
elif name == "watchdog_clear":
@@ -381,9 +382,7 @@ def get_function(self, typ, name):
381382
if llfun is None:
382383
llfunty = self.llty_of_type(typ, bare=True)
383384
llfun = ll.Function(self.llmodule, llfunty, name)
384-
385-
llretty = self.llty_of_type(typ.find().ret, for_return=True)
386-
if self.needs_sret(llretty):
385+
if self.has_sret(typ):
387386
llfun.args[0].add_attribute('sret')
388387
return llfun
389388

@@ -532,6 +531,10 @@ def process_function(self, func):
532531
if func.is_cold:
533532
self.llfunction.attributes.add('cold')
534533
self.llfunction.attributes.add('noinline')
534+
if 'inline' in func.flags:
535+
self.llfunction.attributes.add('inlinehint')
536+
if 'always_inline' in func.flags:
537+
self.llfunction.attributes.add('alwaysinline')
535538

536539
self.llfunction.attributes.add('uwtable')
537540
self.llfunction.attributes.personality = self.llbuiltin("__artiq_personality")
@@ -545,20 +548,28 @@ def process_function(self, func):
545548

546549
# First, map arguments.
547550
if self.has_sret(func.type):
548-
llactualargs = self.llfunction.args[1:]
551+
llactualargs = self.llfunction.args[2:]
552+
llnow = self.llfunction.args[1]
549553
else:
550-
llactualargs = self.llfunction.args
554+
llactualargs = self.llfunction.args[1:]
555+
llnow = self.llfunction.args[0]
551556

552557
for arg, llarg in zip(func.arguments, llactualargs):
553558
llarg.name = arg.name
554559
self.llmap[arg] = llarg
555560

556-
# Second, create all basic blocks.
561+
# Second, set up a pre-entry block.
562+
llpreentry = self.llfunction.append_basic_block("preentry")
563+
self.llbuilder.position_at_end(llpreentry)
564+
self.llnowptr = self.llbuilder.alloca(lli64, name="now")
565+
self.llbuilder.store(llnow, self.llnowptr)
566+
567+
# Third, create all basic blocks.
557568
for block in func.basic_blocks:
558569
llblock = self.llfunction.append_basic_block(block.name)
559570
self.llmap[block] = llblock
560571

561-
# Third, translate all instructions.
572+
# Fourth, translate all instructions.
562573
for block in func.basic_blocks:
563574
self.llbuilder.position_at_end(self.llmap[block])
564575
for insn in block.instructions:
@@ -577,7 +588,11 @@ def process_function(self, func):
577588
# using a different map (the following one).
578589
llblock_map[block] = self.llbuilder.basic_block
579590

580-
# Fourth, add incoming values to phis.
591+
# Fifth, branch from pre-entry block to the real entry block.
592+
self.llbuilder.position_at_end(llpreentry)
593+
self.llbuilder.branch(self.llmap[func.entry()])
594+
595+
# Sixth, add incoming values to phis.
581596
for phi, llphi in self.phis:
582597
for value, block in phi.incoming():
583598
llphi.add_incoming(self.map(value), llblock_map[block])
@@ -1074,20 +1089,16 @@ def get_outer(llenv, env_ty):
10741089
# This is an identity cast at LLVM IR level.
10751090
return self.map(insn.operands[0])
10761091
elif insn.op == "now_mu":
1077-
llnow = self.llbuilder.load(self.llbuiltin("now"), name=insn.name)
1078-
llnow.set_metadata("tbaa", self.tbaa_now)
1092+
llnow = self.llbuilder.load(self.llnowptr, name=insn.name)
10791093
return llnow
10801094
elif insn.op == "at_mu":
10811095
time, = insn.operands
1082-
return self.llbuilder.store(self.map(time), self.llbuiltin("now"))
1096+
return self.llbuilder.store(self.map(time), self.llnowptr)
10831097
elif insn.op == "delay_mu":
10841098
interval, = insn.operands
1085-
llnowptr = self.llbuiltin("now")
1086-
llnow = self.llbuilder.load(llnowptr, name="now.old")
1087-
llnow.set_metadata("tbaa", self.tbaa_now)
1099+
llnow = self.llbuilder.load(self.llnowptr, name="now.old")
10881100
lladjusted = self.llbuilder.add(llnow, self.map(interval), name="now.new")
1089-
llnowstore = self.llbuilder.store(lladjusted, llnowptr)
1090-
llnowstore.set_metadata("tbaa", self.tbaa_now)
1101+
llnowstore = self.llbuilder.store(lladjusted, self.llnowptr)
10911102
return llnowstore
10921103
elif insn.op == "watchdog_set":
10931104
interval, = insn.operands
@@ -1118,8 +1129,9 @@ def _prepare_closure_call(self, insn):
11181129
llfun = self.llbuilder.extract_value(llclosure, 1, name=name)
11191130
else:
11201131
llfun = self.map(insn.static_target_function)
1132+
llnow = self.llbuilder.load(self.llnowptr)
11211133
llenv = self.llbuilder.extract_value(llclosure, 0, name="env.fun")
1122-
return llfun, [llenv] + list(llargs)
1134+
return llfun, [llnow, llenv] + list(llargs)
11231135

11241136
def _prepare_ffi_call(self, insn):
11251137
llargs = []
@@ -1156,6 +1168,16 @@ def _prepare_ffi_call(self, insn):
11561168

11571169
return llfun, list(llargs)
11581170

1171+
def _process_closure_result(self, functionty, llresult):
1172+
if builtins.is_none(functionty.ret):
1173+
assert llresult.type == lli64
1174+
return self.llbuilder.store(llresult, self.llnowptr)
1175+
else:
1176+
llnow = self.llbuilder.extract_value(llresult, 0)
1177+
llvalue = self.llbuilder.extract_value(llresult, 1)
1178+
self.llbuilder.store(llnow, self.llnowptr)
1179+
return llvalue
1180+
11591181
# See session.c:{send,receive}_rpc_value and comm_generic.py:_{send,receive}_rpc_value.
11601182
def _rpc_tag(self, typ, error_handler):
11611183
typ = typ.find()
@@ -1340,11 +1362,14 @@ def process_Call(self, insn):
13401362
if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags:
13411363
llcall.set_metadata('tbaa', self.tbaa_nowrite_call)
13421364

1365+
if types.is_python_function(functiontyp):
1366+
llresult = self._process_closure_result(functiontyp, llresult)
1367+
13431368
return llresult
13441369

13451370
def process_Invoke(self, insn):
13461371
functiontyp = insn.target_function().type
1347-
llnormalblock = self.map(insn.normal_target())
1372+
llnormalblock = self.llfunction.append_basic_block("invoke.post")
13481373
llunwindblock = self.map(insn.exception_target())
13491374
if types.is_rpc(functiontyp):
13501375
return self._build_rpc(insn.target_function().loc,
@@ -1366,14 +1391,19 @@ def process_Invoke(self, insn):
13661391

13671392
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
13681393
else:
1369-
llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
1370-
name=insn.name)
1394+
llcall = llresult = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
1395+
name=insn.name)
13711396

13721397
# See the comment in process_Call.
13731398
if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags:
13741399
llcall.set_metadata('tbaa', self.tbaa_nowrite_call)
13751400

1376-
return llcall
1401+
self.llbuilder.position_at_end(llnormalblock)
1402+
if types.is_python_function(functiontyp):
1403+
llresult = self._process_closure_result(functiontyp, llresult)
1404+
self.llbuilder.branch(self.map(insn.normal_target()))
1405+
1406+
return llresult
13771407

13781408
def _quote(self, value, typ, path):
13791409
value_id = id(value)
@@ -1497,15 +1527,19 @@ def process_IndirectBranch(self, insn):
14971527
return llinsn
14981528

14991529
def process_Return(self, insn):
1530+
llnow = self.llbuilder.load(self.llnowptr)
15001531
if builtins.is_none(insn.value().type):
1501-
return self.llbuilder.ret_void()
1532+
return self.llbuilder.ret(llnow)
15021533
else:
15031534
llvalue = self.map(insn.value())
15041535
if self.needs_sret(llvalue.type):
15051536
self.llbuilder.store(llvalue, self.llfunction.args[0])
1506-
return self.llbuilder.ret_void()
1537+
return self.llbuilder.ret(llnow)
15071538
else:
1508-
return self.llbuilder.ret(llvalue)
1539+
llret = ll.Constant(self.llfunction.ftype.return_type, ll.Undefined)
1540+
llret = self.llbuilder.insert_value(llret, llnow, 0)
1541+
llret = self.llbuilder.insert_value(llret, llvalue, 1)
1542+
return self.llbuilder.ret(llret)
15091543

15101544
def process_Unreachable(self, insn):
15111545
return self.llbuilder.unreachable()

‎artiq/compiler/types.py

+3
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,9 @@ def is_c_function(typ, name=None):
594594
return isinstance(typ, TCFunction) and \
595595
typ.name == name
596596

597+
def is_python_function(typ):
598+
return typ.find().__class__ == TFunction
599+
597600
def is_builtin(typ, name=None):
598601
typ = typ.find()
599602
if name is None:

0 commit comments

Comments
 (0)
Please sign in to comment.