This is an automated email from the ASF dual-hosted git repository.

tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new 009c117d04 [FIX][TIRx] Preserve boolean bitwise not semantics in C 
codegen (#20461)
009c117d04 is described below

commit 009c117d0469163128fc7098ade201f2f47ea469
Author: Shushi Hong <[email protected]>
AuthorDate: Fri Sep 25 19:20:52 2026 -0400

    [FIX][TIRx] Preserve boolean bitwise not semantics in C codegen (#20461)
    
    The same as #20445 but for the main. This pr fixes incorrect code
    generation for boolean `BitwiseNot`.
    
    For boolean values, bitwise NOT should flip `false` to `true` and `true`
    to `false`. The current C code generator emits `~value`, but C/C++ first
    converts the boolean to an integer:
    
    - `~false` becomes `~0`, which is `-1`.
    - `~true` becomes `~1`, which is `-2`.
    
    Both results are nonzero, so converting them back to boolean produces
    `true` in both cases. CUDA boolean vectors have a related problem: their
    generated vector types do not support the `~` operator, causing
    compilation to fail.
    
    This change emits `value == false` for boolean operands. It produces the
    correct result for scalar booleans and uses the existing vector
    comparison code to apply the operation to each lane. Integer operands
    continue to use `~value`..
---
 src/target/source/codegen_c.cc                   |  6 ++++++
 tests/python/codegen/test_target_codegen_bool.py | 17 +++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/src/target/source/codegen_c.cc b/src/target/source/codegen_c.cc
index a496cee1b2..dd59944d85 100644
--- a/src/target/source/codegen_c.cc
+++ b/src/target/source/codegen_c.cc
@@ -667,6 +667,12 @@ void CodeGenC::Dispatch_(const prim::BitwiseXorNode* op, 
std::ostream& os) {  //
   PrintBinaryExpr(op, "^", os, this);
 }
 void CodeGenC::Dispatch_(const prim::BitwiseNotNode* op, std::ostream& os) {  
// NOLINT(*)
+  if (op->a.ty().MatchesCode(DLDataTypeCode::kDLBool)) {
+    // C promotes ~bool to int. Comparing against false preserves the boolean
+    // complement and uses the target's elementwise path for vector operands.
+    PrintExpr(prim::EQ(op->a, prim::MakeConst(op->a.ty(), false)), os);
+    return;
+  }
   os << "(~";
   PrintExpr(op->a, os);
   os << ')';
diff --git a/tests/python/codegen/test_target_codegen_bool.py 
b/tests/python/codegen/test_target_codegen_bool.py
index a2ef816053..b4b85f6f66 100644
--- a/tests/python/codegen/test_target_codegen_bool.py
+++ b/tests/python/codegen/test_target_codegen_bool.py
@@ -87,5 +87,22 @@ def test_cmp_load_store(target):
         run_and_check()
 
 
+def test_bitwise_not_c(tmp_path):
+    @T.prim_func
+    def complement(values: T.Buffer((5,), "int32"), output: T.Buffer((5,), 
"bool")):
+        for i in range(5):
+            output[i] = T.bitwise_not(values[i] != 0)
+
+    built = tvm.compile(complement, target="c")
+    library = str(tmp_path / "complement.so")
+    built.export_library(library)
+    built = tvm.runtime.load_module(library)
+
+    values = np.array([-3, -1, 0, 1, 2], dtype="int32")
+    output = tvm.runtime.tensor(np.zeros(5, dtype="bool"))
+    built(tvm.runtime.tensor(values), output)
+    np.testing.assert_array_equal(output.numpy(), np.logical_not(values))
+
+
 if __name__ == "__main__":
     tvm.testing.main()

Reply via email to