Skip to content

Commit 501ba91

Browse files
author
whitequark
committedAug 31, 2015
Implement {delay,now,at}{,_mu} and {mu,seconds}_to_{seconds,mu}.
1 parent 5151adb commit 501ba91

22 files changed

+177
-155
lines changed
 

Diff for: ‎artiq/compiler/builtins.py

+24
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,30 @@ def fn_print():
138138
def fn_kernel():
139139
return types.TBuiltinFunction("kernel")
140140

141+
def fn_now():
142+
return types.TBuiltinFunction("now")
143+
144+
def fn_delay():
145+
return types.TBuiltinFunction("delay")
146+
147+
def fn_at():
148+
return types.TBuiltinFunction("at")
149+
150+
def fn_now_mu():
151+
return types.TBuiltinFunction("now_mu")
152+
153+
def fn_delay_mu():
154+
return types.TBuiltinFunction("delay_mu")
155+
156+
def fn_at_mu():
157+
return types.TBuiltinFunction("at_mu")
158+
159+
def fn_mu_to_seconds():
160+
return types.TBuiltinFunction("mu_to_seconds")
161+
162+
def fn_seconds_to_mu():
163+
return types.TBuiltinFunction("seconds_to_mu")
164+
141165
# Accessors
142166

143167
def is_none(typ):

Diff for: ‎artiq/compiler/module.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def from_filename(cls, filename, engine=None):
4242
return cls(source.Buffer(f.read(), filename, 1), engine=engine)
4343

4444
class Module:
45-
def __init__(self, src):
45+
def __init__(self, src, ref_period=1e-6):
4646
self.engine = src.engine
4747
self.object_map = src.object_map
4848

@@ -51,7 +51,8 @@ def __init__(self, src):
5151
monomorphism_validator = validators.MonomorphismValidator(engine=self.engine)
5252
escape_validator = validators.EscapeValidator(engine=self.engine)
5353
artiq_ir_generator = transforms.ARTIQIRGenerator(engine=self.engine,
54-
module_name=src.name)
54+
module_name=src.name,
55+
ref_period=ref_period)
5556
dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine)
5657
local_access_validator = validators.LocalAccessValidator(engine=self.engine)
5758

Diff for: ‎artiq/compiler/prelude.py

+17
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,34 @@
77

88
def globals():
99
return {
10+
# Value constructors
1011
"bool": builtins.fn_bool(),
1112
"int": builtins.fn_int(),
1213
"float": builtins.fn_float(),
1314
"list": builtins.fn_list(),
1415
"range": builtins.fn_range(),
16+
17+
# Exception constructors
1518
"Exception": builtins.fn_Exception(),
1619
"IndexError": builtins.fn_IndexError(),
1720
"ValueError": builtins.fn_ValueError(),
1821
"ZeroDivisionError": builtins.fn_ZeroDivisionError(),
22+
23+
# Built-in Python functions
1924
"len": builtins.fn_len(),
2025
"round": builtins.fn_round(),
2126
"print": builtins.fn_print(),
27+
28+
# ARTIQ decorators
2229
"kernel": builtins.fn_kernel(),
30+
31+
# ARTIQ time management functions
32+
"now": builtins.fn_now(),
33+
"delay": builtins.fn_delay(),
34+
"at": builtins.fn_at(),
35+
"now_mu": builtins.fn_now_mu(),
36+
"delay_mu": builtins.fn_delay_mu(),
37+
"at_mu": builtins.fn_at_mu(),
38+
"mu_to_seconds": builtins.fn_mu_to_seconds(),
39+
"seconds_to_mu": builtins.fn_seconds_to_mu(),
2340
}

Diff for: ‎artiq/compiler/testbench/jit.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
from ..targets import NativeTarget
66

77
def main():
8-
libartiq_personality = os.getenv('LIBARTIQ_PERSONALITY')
9-
if libartiq_personality is not None:
10-
llvm.load_library_permanently(libartiq_personality)
8+
libartiq_support = os.getenv('LIBARTIQ_SUPPORT')
9+
if libartiq_support is not None:
10+
llvm.load_library_permanently(libartiq_support)
1111

1212
def process_diagnostic(diag):
1313
print("\n".join(diag.render()))

Diff for: ‎artiq/compiler/transforms/artiq_ir_generator.py

+35-1
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,11 @@ class ARTIQIRGenerator(algorithm.Visitor):
6767

6868
_size_type = builtins.TInt(types.TValue(32))
6969

70-
def __init__(self, module_name, engine):
70+
def __init__(self, module_name, engine, ref_period):
7171
self.engine = engine
7272
self.functions = []
7373
self.name = [module_name] if module_name != "" else []
74+
self.ref_period = ir.Constant(ref_period, builtins.TFloat())
7475
self.current_loc = None
7576
self.current_function = None
7677
self.current_class = None
@@ -1409,6 +1410,39 @@ def body_gen(index):
14091410
self.polymorphic_print([self.visit(arg) for arg in node.args],
14101411
separator=" ", suffix="\n")
14111412
return ir.Constant(None, builtins.TNone())
1413+
elif types.is_builtin(typ, "now"):
1414+
if len(node.args) == 0 and len(node.keywords) == 0:
1415+
now_mu = self.append(ir.Builtin("now_mu", [], builtins.TInt(types.TValue(64))))
1416+
now_mu_float = self.append(ir.Coerce(now_mu, builtins.TFloat()))
1417+
return self.append(ir.Arith(ast.Mult(loc=None), now_mu_float, self.ref_period))
1418+
else:
1419+
assert False
1420+
elif types.is_builtin(typ, "delay") or types.is_builtin(typ, "at"):
1421+
if len(node.args) == 1 and len(node.keywords) == 0:
1422+
arg = self.visit(node.args[0])
1423+
arg_mu_float = self.append(ir.Arith(ast.Div(loc=None), arg, self.ref_period))
1424+
arg_mu = self.append(ir.Coerce(arg_mu_float, builtins.TInt(types.TValue(64))))
1425+
self.append(ir.Builtin(typ.name + "_mu", [arg_mu], builtins.TNone()))
1426+
else:
1427+
assert False
1428+
elif types.is_builtin(typ, "now_mu") or types.is_builtin(typ, "delay_mu") \
1429+
or types.is_builtin(typ, "at_mu"):
1430+
return self.append(ir.Builtin(typ.name,
1431+
[self.visit(arg) for arg in node.args], node.type))
1432+
elif types.is_builtin(typ, "mu_to_seconds"):
1433+
if len(node.args) == 1 and len(node.keywords) == 0:
1434+
arg = self.visit(node.args[0])
1435+
arg_float = self.append(ir.Coerce(arg, builtins.TFloat()))
1436+
return self.append(ir.Arith(ast.Mult(loc=None), arg_float, self.ref_period))
1437+
else:
1438+
assert False
1439+
elif types.is_builtin(typ, "seconds_to_mu"):
1440+
if len(node.args) == 1 and len(node.keywords) == 0:
1441+
arg = self.visit(node.args[0])
1442+
arg_mu = self.append(ir.Arith(ast.Div(loc=None), arg, self.ref_period))
1443+
return self.append(ir.Coerce(arg_mu, builtins.TInt(types.TValue(64))))
1444+
else:
1445+
assert False
14121446
elif types.is_exn_constructor(typ):
14131447
return self.alloc_exn(node.type, *[self.visit(arg_node) for arg_node in node.args])
14141448
elif types.is_constructor(typ):

Diff for: ‎artiq/compiler/transforms/inferencer.py

+35
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,17 @@ def diagnose(valid_forms):
505505
node.func.loc, notes=valid_forms)
506506
self.engine.process(diag)
507507

508+
def simple_form(info, arg_types=[], return_type=builtins.TNone()):
509+
self._unify(node.type, return_type,
510+
node.loc, None)
511+
512+
if len(node.args) == len(arg_types) and len(node.keywords) == 0:
513+
for index, arg_type in enumerate(arg_types):
514+
self._unify(node.args[index].type, arg_type,
515+
node.args[index].loc, None)
516+
else:
517+
diagnose([ valid_form(info) ])
518+
508519
if types.is_exn_constructor(typ):
509520
valid_forms = lambda: [
510521
valid_form("{exn}() -> {exn}".format(exn=typ.name)),
@@ -730,6 +741,30 @@ def makenotes(printer, typea, typeb, loca, locb):
730741
pass
731742
else:
732743
diagnose(valid_forms())
744+
elif types.is_builtin(typ, "now"):
745+
simple_form("now() -> float",
746+
[], builtins.TFloat())
747+
elif types.is_builtin(typ, "delay"):
748+
simple_form("delay(time:float) -> None",
749+
[builtins.TFloat()])
750+
elif types.is_builtin(typ, "at"):
751+
simple_form("at(time:float) -> None",
752+
[builtins.TFloat()])
753+
elif types.is_builtin(typ, "now_mu"):
754+
simple_form("now_mu() -> int(width=64)",
755+
[], builtins.TInt(types.TValue(64)))
756+
elif types.is_builtin(typ, "delay_mu"):
757+
simple_form("delay_mu(time_mu:int(width=64)) -> None",
758+
[builtins.TInt(types.TValue(64))])
759+
elif types.is_builtin(typ, "at_mu"):
760+
simple_form("at_mu(time_mu:int(width=64)) -> None",
761+
[builtins.TInt(types.TValue(64))])
762+
elif types.is_builtin(typ, "mu_to_seconds"):
763+
simple_form("mu_to_seconds(time_mu:int(width=64)) -> float",
764+
[builtins.TInt(types.TValue(64))], builtins.TFloat())
765+
elif types.is_builtin(typ, "seconds_to_mu"):
766+
simple_form("seconds_to_mu(time:float) -> int(width=64)",
767+
[builtins.TFloat()], builtins.TInt(types.TValue(64)))
733768
elif types.is_constructor(typ):
734769
# An user-defined class.
735770
self._unify(node.type, typ.find().instance,

Diff for: ‎artiq/compiler/transforms/llvm_ir_generator.py

+25-7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
lli1 = ll.IntType(1)
1515
lli8 = ll.IntType(8)
1616
lli32 = ll.IntType(32)
17+
lli64 = ll.IntType(64)
1718
lldouble = ll.DoubleType()
1819
llptr = ll.IntType(8).as_pointer()
1920
llmetadata = ll.MetaData()
@@ -331,9 +332,9 @@ def llconst_of_const(self, const):
331332
assert False
332333

333334
def llbuiltin(self, name):
334-
llfun = self.llmodule.get_global(name)
335-
if llfun is not None:
336-
return llfun
335+
llglobal = self.llmodule.get_global(name)
336+
if llglobal is not None:
337+
return llglobal
337338

338339
if name in "llvm.donothing":
339340
llty = ll.FunctionType(llvoid, [])
@@ -366,13 +367,19 @@ def llbuiltin(self, name):
366367
var_arg=True)
367368
elif name == "recv_rpc":
368369
llty = ll.FunctionType(lli32, [llptr])
370+
elif name == "now":
371+
llty = lli64
369372
else:
370373
assert False
371374

372-
llfun = ll.Function(self.llmodule, llty, name)
373-
if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"):
374-
llfun.attributes.add("noreturn")
375-
return llfun
375+
if isinstance(llty, ll.FunctionType):
376+
llglobal = ll.Function(self.llmodule, llty, name)
377+
if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"):
378+
llglobal.attributes.add("noreturn")
379+
else:
380+
llglobal = ll.GlobalVariable(self.llmodule, llty, name)
381+
382+
return llglobal
376383

377384
def map(self, value):
378385
if isinstance(value, (ir.Argument, ir.Instruction, ir.BasicBlock)):
@@ -774,6 +781,17 @@ def get_outer(llenv, env_ty):
774781
elif insn.op == "exncast":
775782
# This is an identity cast at LLVM IR level.
776783
return self.map(insn.operands[0])
784+
elif insn.op == "now_mu":
785+
return self.llbuilder.load(self.llbuiltin("now"), name=insn.name)
786+
elif insn.op == "delay_mu":
787+
interval, = insn.operands
788+
llnowptr = self.llbuiltin("now")
789+
llnow = self.llbuilder.load(llnowptr)
790+
lladjusted = self.llbuilder.add(llnow, self.map(interval))
791+
return self.llbuilder.store(lladjusted, llnowptr)
792+
elif insn.op == "at_mu":
793+
time, = insn.operands
794+
return self.llbuilder.store(self.map(time), self.llbuiltin("now"))
777795
else:
778796
assert False
779797

Diff for: ‎artiq/coredevice/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def compile(self, function, args, kwargs, with_attr_writeback=True):
3939
stitcher.stitch_call(function, args, kwargs)
4040
stitcher.finalize()
4141

42-
module = Module(stitcher)
42+
module = Module(stitcher, ref_period=self.ref_period)
4343
target = OR1KTarget()
4444

4545
library = target.compile_and_link([module])

Diff for: ‎artiq/py2llvm_old/transforms/lower_time.py

-64
This file was deleted.

Diff for: ‎artiq/py2llvm_old/transforms/quantize_time.py

-70
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,3 @@
1-
"""
2-
This transform turns calls to delay() that use non-integer time
3-
expressed in seconds into calls to delay_mu() that use int64 time
4-
expressed in multiples of ref_period.
5-
6-
It does so by inserting multiplication/division/rounding operations around
7-
those calls.
8-
9-
The seconds_to_mu and mu_to_seconds core language functions are also
10-
implemented here, as well as watchdog to syscall conversion.
11-
"""
12-
13-
import ast
14-
15-
from artiq.transforms.tools import value_to_ast
16-
17-
18-
def _seconds_to_mu(ref_period, node):
19-
divided = ast.copy_location(
20-
ast.BinOp(left=node,
21-
op=ast.Div(),
22-
right=value_to_ast(ref_period)),
23-
node)
24-
return ast.copy_location(
25-
ast.Call(func=ast.Name("round64", ast.Load()),
26-
args=[divided],
27-
keywords=[], starargs=[], kwargs=[]),
28-
divided)
29-
30-
31-
def _mu_to_seconds(ref_period, node):
32-
return ast.copy_location(
33-
ast.BinOp(left=node,
34-
op=ast.Mult(),
35-
right=value_to_ast(ref_period)),
36-
node)
37-
38-
39-
class _TimeQuantizer(ast.NodeTransformer):
40-
def __init__(self, ref_period):
41-
self.ref_period = ref_period
42-
self.watchdog_id_counter = 0
43-
44-
def visit_Call(self, node):
45-
funcname = node.func.id
46-
if funcname == "delay":
47-
node.func.id = "delay_mu"
48-
if (isinstance(node.args[0], ast.Call)
49-
and node.args[0].func.id == "mu_to_seconds"):
50-
# optimize:
51-
# delay(mu_to_seconds(x)) -> delay_mu(x)
52-
node.args[0] = self.visit(node.args[0].args[0])
53-
else:
54-
node.args[0] = _seconds_to_mu(self.ref_period,
55-
self.visit(node.args[0]))
56-
return node
57-
elif funcname == "seconds_to_mu":
58-
return _seconds_to_mu(self.ref_period,
59-
self.visit(node.args[0]))
60-
elif funcname == "mu_to_seconds":
61-
return _mu_to_seconds(self.ref_period,
62-
self.visit(node.args[0]))
63-
else:
64-
self.generic_visit(node)
65-
return node
66-
671
def visit_With(self, node):
682
self.generic_visit(node)
693
if (isinstance(node.items[0].context_expr, ast.Call)
@@ -107,7 +41,3 @@ def visit_With(self, node):
10741
finalbody=[stmt_clear])
10842
]
10943
return node
110-
111-
112-
def quantize_time(func_def, ref_period):
113-
_TimeQuantizer(ref_period).visit(func_def)
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
CC ?= clang
22

3-
libartiq_personality.so: ../../soc/runtime/artiq_personality.c artiq_terminate.c
3+
libartiq_support.so: ../../soc/runtime/artiq_personality.c artiq_terminate.c artiq_time.c
44
$(CC) -std=c99 -Wall -Werror -I. -I../../soc/runtime -g -fPIC -shared -o $@ $^

Diff for: ‎lit-test/libartiq_support/artiq_time.c

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include <stdint.h>
2+
3+
int64_t now = 0;

Diff for: ‎lit-test/libartiq_support/libartiq_personality.so

23.1 KB
Binary file not shown.

Diff for: ‎lit-test/libartiq_support/libartiq_support.so

23.5 KB
Binary file not shown.
File renamed without changes.

Diff for: ‎lit-test/test/lit.cfg

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ not_ = '{} {}'.format(python_executable, os.path.join(root, 'not.py'))
1717
config.substitutions.append( ('%not', not_) )
1818

1919
if os.name == 'posix':
20-
personality_build = os.path.join(root, 'libartiq_personality')
21-
if subprocess.call(['make', '-sC', personality_build]) != 0:
20+
support_build = os.path.join(root, 'libartiq_support')
21+
if subprocess.call(['make', '-sC', support_build]) != 0:
2222
lit_config.fatal("Unable to build JIT support library")
2323

24-
personality_lib = os.path.join(personality_build, 'libartiq_personality.so')
25-
config.environment['LIBARTIQ_PERSONALITY'] = personality_lib
24+
support_lib = os.path.join(support_build, 'libartiq_support.so')
25+
config.environment['LIBARTIQ_SUPPORT'] = support_lib
2626

2727
config.available_features.add('exceptions')

Diff for: ‎lit-test/test/time/advance.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# RUN: %python -m artiq.compiler.testbench.jit %s
2+
3+
assert now() == 0.0
4+
delay(100.0)
5+
assert now() == 100.0
6+
at(12345.0)
7+
assert now() == 12345.0
8+
9+
assert now_mu() == 12345000000

Diff for: ‎lit-test/test/time/advance_mu.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# RUN: %python -m artiq.compiler.testbench.jit %s
2+
3+
assert now_mu() == 0
4+
delay_mu(100)
5+
assert now_mu() == 100
6+
at_mu(12345)
7+
assert now_mu() == 12345

Diff for: ‎lit-test/test/time/conversion.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# RUN: %python -m artiq.compiler.testbench.jit %s
2+
3+
assert seconds_to_mu(2.0) == 2000000
4+
assert mu_to_seconds(1500000) == 1.5

Diff for: ‎soc/runtime/ksupport.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
void ksupport_abort(void);
2121

22+
int64_t now;
23+
2224
/* compiler-rt symbols */
2325
extern void __divsi3, __modsi3, __ledf2, __gedf2, __unorddf2, __eqdf2, __ltdf2,
2426
__nedf2, __gtdf2, __negsf2, __negdf2, __addsf3, __subsf3, __mulsf3,
@@ -87,8 +89,7 @@ static const struct symbol runtime_exports[] = {
8789
{"abort", &ksupport_abort},
8890

8991
/* proxified syscalls */
90-
{"now_init", &now_init},
91-
{"now_save", &now_save},
92+
{"now", &now},
9293

9394
{"watchdog_set", &watchdog_set},
9495
{"watchdog_clear", &watchdog_clear},
@@ -212,7 +213,10 @@ int main(void)
212213
void (*kernel_init)() = request->library_info->init;
213214

214215
mailbox_send_and_wait(&load_reply);
216+
217+
now = now_init();
215218
kernel_init();
219+
now_save(now);
216220

217221
struct msg_base finished_reply;
218222
finished_reply.type = MESSAGE_TYPE_FINISHED;

0 commit comments

Comments
 (0)
Please sign in to comment.