Skip to content

Commit

Permalink
compiler: implement min()/max() as builtins.
Browse files Browse the repository at this point in the history
Fixes #239.
whitequark committed Jun 22, 2016
1 parent 77d47c2 commit 33e8e59
Showing 6 changed files with 63 additions and 0 deletions.
6 changes: 6 additions & 0 deletions artiq/compiler/builtins.py
Original file line number Diff line number Diff line change
@@ -138,6 +138,12 @@ def fn_len():
def fn_round():
return types.TBuiltinFunction("round")

def fn_min():
return types.TBuiltinFunction("min")

def fn_max():
return types.TBuiltinFunction("max")

def fn_print():
return types.TBuiltinFunction("print")

2 changes: 2 additions & 0 deletions artiq/compiler/prelude.py
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ def globals():
# Built-in Python functions
"len": builtins.fn_len(),
"round": builtins.fn_round(),
"min": builtins.fn_min(),
"max": builtins.fn_max(),
"print": builtins.fn_print(),

# ARTIQ decorators
14 changes: 14 additions & 0 deletions artiq/compiler/transforms/artiq_ir_generator.py
Original file line number Diff line number Diff line change
@@ -1667,6 +1667,20 @@ def body_gen(index):
return self.append(ir.Builtin("round", [arg], node.type))
else:
assert False
elif types.is_builtin(typ, "min"):
if len(node.args) == 2 and len(node.keywords) == 0:
arg0, arg1 = map(self.visit, node.args)
cond = self.append(ir.Compare(ast.Lt(loc=None), arg0, arg1))
return self.append(ir.Select(cond, arg0, arg1))
else:
assert False
elif types.is_builtin(typ, "max"):
if len(node.args) == 2 and len(node.keywords) == 0:
arg0, arg1 = map(self.visit, node.args)
cond = self.append(ir.Compare(ast.Gt(loc=None), arg0, arg1))
return self.append(ir.Select(cond, arg0, arg1))
else:
assert False
elif types.is_builtin(typ, "print"):
self.polymorphic_print([self.visit(arg) for arg in node.args],
separator=" ", suffix="\n")
31 changes: 31 additions & 0 deletions artiq/compiler/transforms/inferencer.py
Original file line number Diff line number Diff line change
@@ -789,6 +789,37 @@ def makenotes(printer, typea, typeb, loca, locb):
node.loc, None)
else:
diagnose(valid_forms())
elif types.is_builtin(typ, "min") or types.is_builtin(typ, "max"):
fn = typ.name

valid_forms = lambda: [
valid_form("{}(x:int(width='a), y:int(width='a)) -> int(width='a)".format(fn)),
valid_form("{}(x:float, y:float) -> float".format(fn))
]

if len(node.args) == 2 and len(node.keywords) == 0:
arg0, arg1 = node.args

self._unify(arg0.type, arg1.type,
arg0.loc, arg1.loc)

if builtins.is_int(arg0.type) or builtins.is_float(arg0.type):
self._unify(arg0.type, node.type,
arg0.loc, node.loc)
elif types.is_var(arg0.type):
pass # undetermined yet
else:
note = diagnostic.Diagnostic("note",
"this expression has type {type}",
{"type": types.TypePrinter().name(arg0.type)},
arg0.loc)
diag = diagnostic.Diagnostic("error",
"the arguments of {fn}() must be of a numeric type",
{"fn": fn},
node.func.loc, notes=[note])
self.engine.process(diag)
else:
diagnose(valid_forms())
elif types.is_builtin(typ, "print"):
valid_forms = lambda: [
valid_form("print(args...) -> None"),
3 changes: 3 additions & 0 deletions artiq/test/lit/inferencer/error_builtin_calls.py
Original file line number Diff line number Diff line change
@@ -10,3 +10,6 @@

# CHECK-L: ${LINE:+1}: error: the argument of list() must be of an iterable type
list(1)

# CHECK-L: ${LINE:+1}: error: the arguments of min() must be of a numeric type
min([1], [1])
7 changes: 7 additions & 0 deletions artiq/test/lit/integration/minmax.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# RUN: %python -m artiq.compiler.testbench.jit %s
# RUN: %python %s

assert min(1, 2) == 1
assert max(1, 2) == 2
assert min(1.0, 2.0) == 1.0
assert max(1.0, 2.0) == 2.0

0 comments on commit 33e8e59

Please sign in to comment.