Skip to content

ConstraintEliminationPass incorrectly replaces a i256 ne with a constant false. #68751

@allight

Description

@allight

manual_min.ll is a llvm ir program that displays a miscompile.

This reproduces using llvm as of commit: ff5e2ba

Unfortunately due to not causing any crash I was unable to minimize it any more than this since whatever I tried bugpoint would either reduce it to nothing or not change anything.

Bug code is generated from an xls program below:

DSLX

fn main(x4: u51) -> bool {
        let x5: u51 = bit_slice_update(x4, x4, x4);
        let x6: uN[102] = x5 ++ x5;
        let x9: uN[153] = x6 ++ x5;
        let gate_src: bool = x6 as uN[153] != x9;
        gate_src
}

XLS IR

package crasher_manual_min2

file_number 0 "xls/fuzzer/crashers/crasher_manual_min2.x"

fn __crasher_manual_min2__main(x4: bits[51]) -> bits[1] {
  // bit_slice_update(a, b, c) returns 'a' with bits starting at index 'b' replaced with the bits of 'c'
  x5: bits[51] = bit_slice_update(x4, x4, x4, id=2, pos=[(0,54,38)])
  x6: bits[102] = concat(x5, x5, id=3, pos=[(0,55,29)])
  zero_ext.5: bits[153] = zero_ext(x6, new_bit_count=153, id=5)
  x9: bits[153] = concat(x6, x5, id=4, pos=[(0,56,29)])
  ret gate_src: bits[1] = ne(zero_ext.5, x9, id=6, pos=[(0,58,43)])
}

This is compiled using the xls jit compiler to LLVM. This code is linked with a runner below which simply executes this program on the numbers [0, 256] and prints each result. This should result in a zero byte followed by all 0x1 bytes.

% cat manual_min_runner.bc | lli | hd
00000000  00 01 01 01 01 01 01 01  01 01 01 01 01 01 01 01  |................|
00000010  01 01 01 01 01 01 01 01  01 01 01 01 01 01 01 01  |................|
*
00000100
Runner code

#include <stdio.h>
#include <unistd.h>
#include <stdint.h>

extern char __crasher_manual_min2__main(void* inputs, void* outputs, void* buf, void* events, void* user_data, void* rt, long long int cont);

typedef int64_t i64;
// returns a bool
char tryone(i64 v) {
  void* inp_ptr[1];
  i64 bit64 = v;
  inp_ptr[0] = &bit64;
  void* out_ptr[1];
  char val = 0;
  out_ptr[0] = &val;
  void* temp_buf[1];
  void* user_data[1];
  __crasher_manual_min2__main(inp_ptr, out_ptr, temp_buf, 0, 0, 0, 0);
  return val;
}

int main() {
  // return (tryone(1) << 1) | tryone(0);
  for (int i = 0; i < 256; ++i) {
    char r = tryone(i);
    write(1, &r, sizeof(char));
  }
  return 0;
}

However in the 349th pass (ConstraintEliminationPass) a miscompile occurs and after that pass the program will always print all 0s.
 % cat manual_min_runner.opt.bc | lli | hd
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000100

This is based on the investigation for google/xls#1146

Repro build process:

% opt manual_min.llvm.ir --O3 -opt-bisect-limit=$current_id > bisect_manual_min.llvm.opt.bc
% clang -S -emit-llvm manual_min_runner.c -o manual_min_runner.ll
% opt manual_min_runner.ll > manual_min_runner_driver.bc
% llvm-link  bisect_manual_min.llvm.opt.bc manual_min_runner_driver.bc > bisect_manual_min_runner.opt.bc

The bitcode can be run by lli or compiled further. It doesn't seem to affect the miscompile.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions