Skip to content

[SDAG] Miscompile of logical or of comparisons of loads with !range metadata #64589

@nikic

Description

@nikic
define i8 @test(ptr %p) {
  %v1 = load i8, ptr %p, align 4, !range !0, !noundef !{}
  %cmp1 = icmp eq i8 %v1, 0
  %p2 = getelementptr inbounds i8, ptr %p, i64 1
  %v2 = load i8, ptr %p2, align 1, !range !0
  %cmp2 = icmp eq i8 %v2, 0
  %or = select i1 %cmp1, i1 %cmp2, i1 false
  %res = select i1 %or, i8 0, i8 2
  ret i8 %res
}

!0 = !{i8 0, i8 2}

Lowers to:

	movzbl	(%rdi), %eax
	orb	1(%rdi), %al
	addb	%al, %al
	retq

This is incorrect because the %v2 only has !range, but not !noundef. As such, the load may return a poison value.

I believe nominally the folds at https://github.com/llvm/llvm-project/blob/68744ffbdd7daac41da274eef9ac0d191e11c16d/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp#L11252 are at fault here: These select to and/or folds are well-known to be unsound in the presence of poison values.

However, removing these folds would be quite involved (as we have seen on the IR side), so the immediate fix here is probably to not transfer !range metadata to SDAG if it does not have !noundef, which sidesteps the issue.

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions