diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 09cea92ad..0d17417d9 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -284,8 +284,33 @@ class ARTIQIRGenerator(algorithm.Visitor): finally: self.current_assign = None + def coerce_to_bool(self, insn, block=None): + if builtins.is_bool(insn.type): + return insn + elif builtins.is_int(insn.type): + return self.append(ir.Compare(ast.NotEq(loc=None), insn, ir.Constant(0, insn.type)), + block=block) + elif builtins.is_float(insn.type): + return self.append(ir.Compare(ast.NotEq(loc=None), insn, ir.Constant(0, insn.type)), + block=block) + elif builtins.is_iterable(insn.type): + length = self.iterable_len(insn) + return self.append(ir.Compare(ast.NotEq(loc=None), length, ir.Constant(0, length.type)), + block=block) + else: + note = diagnostic.Diagnostic("note", + "this expression has type {type}", + {"type": types.TypePrinter().name(insn.type)}, + insn.loc) + diag = diagnostic.Diagnostic("warning", + "this expression, which is always truthful, is coerced to bool", {}, + insn.loc, notes=[note]) + self.engine.process(diag) + return ir.Constant(True, builtins.TBool()) + def visit_If(self, node): cond = self.visit(node.test) + cond = self.coerce_to_bool(cond) head = self.current_block if_true = self.add_block() @@ -838,17 +863,19 @@ class ARTIQIRGenerator(algorithm.Visitor): zip(blocks, [(h,t) for (v,h,t) in blocks[1:]] + [(tail, tail)]): phi.add_incoming(value, value_tail) if next_value_head != tail: + cond = self.coerce_to_bool(value, block=value_tail) if isinstance(node.op, ast.And): - value_tail.append(ir.BranchIf(value, next_value_head, tail)) + value_tail.append(ir.BranchIf(cond, next_value_head, tail)) else: - value_tail.append(ir.BranchIf(value, tail, next_value_head)) + value_tail.append(ir.BranchIf(cond, tail, next_value_head)) else: value_tail.append(ir.Branch(tail)) return phi def visit_UnaryOpT(self, node): if isinstance(node.op, ast.Not): - return self.append(ir.Select(self.visit(node.operand), + cond = self.coerce_to_bool(self.visit(node.operand)) + return self.append(ir.Select(cond, ir.Constant(False, builtins.TBool()), ir.Constant(True, builtins.TBool()))) elif isinstance(node.op, ast.USub): @@ -1116,9 +1143,7 @@ class ARTIQIRGenerator(algorithm.Visitor): return ir.Constant(False, builtins.TBool()) elif len(node.args) == 1 and len(node.keywords) == 0: arg = self.visit(node.args[0]) - return self.append(ir.Select(arg, - ir.Constant(True, builtins.TBool()), - ir.Constant(False, builtins.TBool()))) + return self.coerce_to_bool(arg) else: assert False elif types.is_builtin(typ, "int"): diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 61b29abee..5c9c78fe4 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -295,7 +295,7 @@ class LLVMIRGenerator: if builtins.get_int_width(typ) > builtins.get_int_width(value_typ): return self.llbuilder.sext(self.map(insn.value()), self.llty_of_type(typ), name=insn.name) - else: # builtins.get_int_width(typ) < builtins.get_int_width(value_typ): + else: # builtins.get_int_width(typ) <= builtins.get_int_width(value_typ): return self.llbuilder.trunc(self.map(insn.value()), self.llty_of_type(typ), name=insn.name) else: diff --git a/lit-test/compiler/codegen/warning_useless_bool.py b/lit-test/compiler/codegen/warning_useless_bool.py new file mode 100644 index 000000000..f76e011c8 --- /dev/null +++ b/lit-test/compiler/codegen/warning_useless_bool.py @@ -0,0 +1,5 @@ +# RUN: %python -m artiq.compiler.testbench.module +diag %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +# CHECK-L: ${LINE:+1}: warning: this expression, which is always truthful, is coerced to bool +bool(IndexError()) diff --git a/lit-test/compiler/integration/operator.py b/lit-test/compiler/integration/arithmetics.py similarity index 93% rename from lit-test/compiler/integration/operator.py rename to lit-test/compiler/integration/arithmetics.py index 4bf0ab7c1..a93dd5945 100644 --- a/lit-test/compiler/integration/operator.py +++ b/lit-test/compiler/integration/arithmetics.py @@ -1,7 +1,5 @@ # RUN: %python -m artiq.compiler.testbench.jit %s -assert (not True) == False -assert (not False) == True assert -(-1) == 1 assert -(-1.0) == 1.0 assert +1 == 1 diff --git a/lit-test/compiler/integration/bool.py b/lit-test/compiler/integration/bool.py new file mode 100644 index 000000000..9df8b97c2 --- /dev/null +++ b/lit-test/compiler/integration/bool.py @@ -0,0 +1,20 @@ +# RUN: %python -m artiq.compiler.testbench.jit %s + +assert (not 0) == True +assert (not 1) == False + +assert (0 and 0) is 0 +assert (1 and 0) is 0 +assert (0 and 1) is 0 +assert (1 and 2) is 2 + +assert (0 or 0) is 0 +assert (1 or 0) is 1 +assert (0 or 1) is 1 +assert (1 or 2) is 1 + +assert bool(False) is False and bool(False) is False +assert bool(0) is False and bool(1) is True +assert bool(0.0) is False and bool(1.0) is True +x = []; assert bool(x) is False; x = [1]; assert bool(x) is True +assert bool(range(0)) is False and bool(range(1)) is True