forked from M-Labs/artiq
Make negative and too-far shifts have defined behavior.
This commit is contained in:
parent
bf60978c7b
commit
4cfe4ea148
|
@ -900,8 +900,14 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
def visit_BinOpT(self, node):
|
def visit_BinOpT(self, node):
|
||||||
if builtins.is_numeric(node.type):
|
if builtins.is_numeric(node.type):
|
||||||
# TODO: check for division by zero
|
# TODO: check for division by zero
|
||||||
# TODO: check for shift by too many bits
|
rhs = self.visit(node.right)
|
||||||
return self.append(ir.Arith(node.op, self.visit(node.left), self.visit(node.right)))
|
if isinstance(node.op, (ast.LShift, ast.RShift)):
|
||||||
|
# Check for negative shift amount.
|
||||||
|
self._make_check(self.append(ir.Compare(ast.GtE(loc=None), rhs,
|
||||||
|
ir.Constant(0, rhs.type))),
|
||||||
|
lambda: self.append(ir.Alloc([], builtins.TValueError())))
|
||||||
|
|
||||||
|
return self.append(ir.Arith(node.op, self.visit(node.left), rhs))
|
||||||
elif isinstance(node.op, ast.Add): # list + list, tuple + tuple
|
elif isinstance(node.op, ast.Add): # list + list, tuple + tuple
|
||||||
lhs, rhs = self.visit(node.left), self.visit(node.right)
|
lhs, rhs = self.visit(node.left), self.visit(node.right)
|
||||||
if types.is_tuple(node.left.type) and types.is_tuple(node.right.type):
|
if types.is_tuple(node.left.type) and types.is_tuple(node.right.type):
|
||||||
|
|
|
@ -368,11 +368,21 @@ class LLVMIRGenerator:
|
||||||
return self.llbuilder.fptosi(llvalue, self.llty_of_type(insn.type),
|
return self.llbuilder.fptosi(llvalue, self.llty_of_type(insn.type),
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
elif isinstance(insn.op, ast.LShift):
|
elif isinstance(insn.op, ast.LShift):
|
||||||
return self.llbuilder.shl(self.map(insn.lhs()), self.map(insn.rhs()),
|
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
|
||||||
name=insn.name)
|
llrhs_max = ll.Constant(llrhs.type, builtins.get_int_width(insn.lhs().type))
|
||||||
|
llrhs_overflow = self.llbuilder.icmp_signed('>=', llrhs, llrhs_max)
|
||||||
|
llvalue_zero = ll.Constant(lllhs.type, 0)
|
||||||
|
llvalue = self.llbuilder.shl(lllhs, llrhs)
|
||||||
|
return self.llbuilder.select(llrhs_overflow, llvalue_zero, llvalue,
|
||||||
|
name=insn.name)
|
||||||
elif isinstance(insn.op, ast.RShift):
|
elif isinstance(insn.op, ast.RShift):
|
||||||
return self.llbuilder.ashr(self.map(insn.lhs()), self.map(insn.rhs()),
|
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
|
||||||
name=insn.name)
|
llrhs_max = ll.Constant(llrhs.type, builtins.get_int_width(insn.lhs().type) - 1)
|
||||||
|
llrhs_overflow = self.llbuilder.icmp_signed('>', llrhs, llrhs_max)
|
||||||
|
llvalue = self.llbuilder.ashr(lllhs, llrhs)
|
||||||
|
llvalue_max = self.llbuilder.ashr(lllhs, llrhs_max) # preserve sign bit
|
||||||
|
return self.llbuilder.select(llrhs_overflow, llvalue_max, llvalue,
|
||||||
|
name=insn.name)
|
||||||
elif isinstance(insn.op, ast.BitAnd):
|
elif isinstance(insn.op, ast.BitAnd):
|
||||||
return self.llbuilder.and_(self.map(insn.lhs()), self.map(insn.rhs()),
|
return self.llbuilder.and_(self.map(insn.lhs()), self.map(insn.rhs()),
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
|
|
|
@ -28,6 +28,8 @@ assert 9.0 ** 0.5 == 3.0
|
||||||
assert 1 << 1 == 2
|
assert 1 << 1 == 2
|
||||||
assert 2 >> 1 == 1
|
assert 2 >> 1 == 1
|
||||||
assert -2 >> 1 == -1
|
assert -2 >> 1 == -1
|
||||||
|
assert 1 << 32 == 0
|
||||||
|
assert -1 >> 32 == -1
|
||||||
assert 0x18 & 0x0f == 0x08
|
assert 0x18 & 0x0f == 0x08
|
||||||
assert 0x18 | 0x0f == 0x1f
|
assert 0x18 | 0x0f == 0x1f
|
||||||
assert 0x18 ^ 0x0f == 0x17
|
assert 0x18 ^ 0x0f == 0x17
|
||||||
|
|
Loading…
Reference in New Issue