Skip to content

Commit 4cfe4ea

Browse files
author
whitequark
committedJul 22, 2015
Make negative and too-far shifts have defined behavior.
1 parent bf60978 commit 4cfe4ea

File tree

3 files changed

+24
-6
lines changed

3 files changed

+24
-6
lines changed
 

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -900,8 +900,14 @@ def visit_CoerceT(self, node):
900900
def visit_BinOpT(self, node):
901901
if builtins.is_numeric(node.type):
902902
# TODO: check for division by zero
903-
# TODO: check for shift by too many bits
904-
return self.append(ir.Arith(node.op, self.visit(node.left), self.visit(node.right)))
903+
rhs = self.visit(node.right)
904+
if isinstance(node.op, (ast.LShift, ast.RShift)):
905+
# Check for negative shift amount.
906+
self._make_check(self.append(ir.Compare(ast.GtE(loc=None), rhs,
907+
ir.Constant(0, rhs.type))),
908+
lambda: self.append(ir.Alloc([], builtins.TValueError())))
909+
910+
return self.append(ir.Arith(node.op, self.visit(node.left), rhs))
905911
elif isinstance(node.op, ast.Add): # list + list, tuple + tuple
906912
lhs, rhs = self.visit(node.left), self.visit(node.right)
907913
if types.is_tuple(node.left.type) and types.is_tuple(node.right.type):

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

+14-4
Original file line numberDiff line numberDiff line change
@@ -368,11 +368,21 @@ def process_Arith(self, insn):
368368
return self.llbuilder.fptosi(llvalue, self.llty_of_type(insn.type),
369369
name=insn.name)
370370
elif isinstance(insn.op, ast.LShift):
371-
return self.llbuilder.shl(self.map(insn.lhs()), self.map(insn.rhs()),
372-
name=insn.name)
371+
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
372+
llrhs_max = ll.Constant(llrhs.type, builtins.get_int_width(insn.lhs().type))
373+
llrhs_overflow = self.llbuilder.icmp_signed('>=', llrhs, llrhs_max)
374+
llvalue_zero = ll.Constant(lllhs.type, 0)
375+
llvalue = self.llbuilder.shl(lllhs, llrhs)
376+
return self.llbuilder.select(llrhs_overflow, llvalue_zero, llvalue,
377+
name=insn.name)
373378
elif isinstance(insn.op, ast.RShift):
374-
return self.llbuilder.ashr(self.map(insn.lhs()), self.map(insn.rhs()),
375-
name=insn.name)
379+
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
380+
llrhs_max = ll.Constant(llrhs.type, builtins.get_int_width(insn.lhs().type) - 1)
381+
llrhs_overflow = self.llbuilder.icmp_signed('>', llrhs, llrhs_max)
382+
llvalue = self.llbuilder.ashr(lllhs, llrhs)
383+
llvalue_max = self.llbuilder.ashr(lllhs, llrhs_max) # preserve sign bit
384+
return self.llbuilder.select(llrhs_overflow, llvalue_max, llvalue,
385+
name=insn.name)
376386
elif isinstance(insn.op, ast.BitAnd):
377387
return self.llbuilder.and_(self.map(insn.lhs()), self.map(insn.rhs()),
378388
name=insn.name)

Diff for: ‎lit-test/compiler/integration/arithmetics.py

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
assert 1 << 1 == 2
2929
assert 2 >> 1 == 1
3030
assert -2 >> 1 == -1
31+
assert 1 << 32 == 0
32+
assert -1 >> 32 == -1
3133
assert 0x18 & 0x0f == 0x08
3234
assert 0x18 | 0x0f == 0x1f
3335
assert 0x18 ^ 0x0f == 0x17

0 commit comments

Comments
 (0)
Please sign in to comment.