Problem with LLVM DAGCombiner


I was testing the vector divide on a RISCV target simulator and found out there is a problem if the element type of vector is unsigned char. Strangely, it works fine if the type is signed char.

Below is the reduced code of the problem:

typedef unsigned char uint8x2_t __attribute__((vector_size(2)));
uint8x2_t div(uint8x2_t a, uint8x2_t b) {
  return a / b;
int main() {
  uint8x2_t a = {2, 2};
  uint8x2_t b = {0, 1};
  uint8x2_t c = div(a, b);
  if (c[1] != 2)
    return 1;
  return 0;

I checked the assembly code and found the difference between the two types is the absence of an AND instruction in unsigned char.

The AND instruction is for rebuilding the vector after two elements been divided separately. The process is shifting one element 8 bits to the left, then uses AND instruction to mask out unnecessary data beyond 8th digit of the other element. At last, there is an OR instruction to combine two elements into one vector.

It seems that DAGCombiner in LLVM considers the result produced by unsigned divide will always be zero beyond the 8th digit and deems the AND instruction is unnecessary. As the result, it was removed.

It is a valid move under most circumstances but there is a division by zero case in my code. The simulator returns 0xfffffff when it occurs. If the element type is char, there will be an AND instruction to truncate data into 8 bits (0xff), so it can get the correct result while using OR to build the vector. However if the element type is unsigned char, the AND will be removed. The other element in the vector will be affect by 0xffffffff while using OR. Hence causes the problem.

Is there any way to prevent DAGCombiner from removing AND?.