Summary
-llzk-to-pcl emits pcl.iff followed by pcl.not for bool.xor, but a downstream use of the XOR result can still consume the pcl.iff value.
Reproduction
Reproducer run:
https://github.com/Kuhai9801/llzk-lib/actions/runs/28180228869
!F = !felt.type<"goldilocks">
function.def @constrain(%self: !struct.type<@A>, %a: !F, %b: !F, %c: !F) attributes {function.allow_constraint, function.allow_non_native_field_ops} {
%eq1 = bool.cmp eq(%a, %b) : !F, !F
%eq2 = bool.cmp eq(%b, %c) : !F, !F
%xor = bool.xor %eq1, %eq2
%use = bool.and %xor, %eq1
function.return
}
Run: llzk-opt -llzk-to-pcl -verify-diagnostics repro.llzk
Expected shape:
%2 = pcl.iff %0, %1
%3 = pcl.not %2
%4 = pcl.and %3, %0
Actual shape:
%2 = pcl.iff %0, %1
%3 = pcl.not %2
%4 = pcl.and %2, %0
Expected
Uses of the LLZK bool.xor result consume the lowered pcl.not result.
Actual
The later pcl.and consumes the pcl.iff result.
Notes
The relevant lowering is in backends/pcl-conv/lib/Transforms/PCLLoweringPass.cpp. The CmpOp NE case has a similar two-step lowering shape.
Summary
-llzk-to-pclemitspcl.ifffollowed bypcl.notforbool.xor, but a downstream use of the XOR result can still consume thepcl.iffvalue.Reproduction
Reproducer run:
https://github.com/Kuhai9801/llzk-lib/actions/runs/28180228869
Run:
llzk-opt -llzk-to-pcl -verify-diagnostics repro.llzkExpected shape:
Actual shape:
Expected
Uses of the LLZK
bool.xorresult consume the loweredpcl.notresult.Actual
The later
pcl.andconsumes thepcl.iffresult.Notes
The relevant lowering is in
backends/pcl-conv/lib/Transforms/PCLLoweringPass.cpp. TheCmpOpNEcase has a similar two-step lowering shape.