[RFC] Clarify the behavior of select with FP poison-generating flags

Motivation

Consider the following transformation from [InstCombine] ninf should not be propagated · Issue #136430 · llvm/llvm-project · GitHub :
Alive2: Compiler Explorer

define half @test_fcmp_select_maxnum(half %x) {
#0:
  %cmp2 = fcmp ogt half %x, 0x5bf8
  %sel2 = select nnan ninf nsz i1 %cmp2, half %x, half 0x5bf8
  ret half %sel2
}
=>
define half @test_fcmp_select_maxnum(half %x) {
#0:
  %sel2 = fmax ninf nsz half %x, 0x5bf8
  ret half %sel2
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
half %x = #xfc00 (-oo)

Source:
i1 %cmp2 = #x0 (0)
half %sel2 = #x5bf8 (255)

Target:
half %sel2 = poison
Source value: #x5bf8 (255)
Target value: poison

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors

Alive2 and llubi only apply the ninf flag to the result of select instruction. But the current LangRef wording does not specify this behavior. And some optimizations in LLVM assumes that the ninf flag is applied to both the arm of select: [InstCombine] Fix ninf propagation for fcmp+sel -> minmax by dtcxzyw · Pull Request #136433 · llvm/llvm-project · GitHub

For clarity, let’s see the following example:

entry:
  br i1 true, label %if.end, label %if.else
if.else:
  br label %if.end
if.end:
  %x = phi nnan float [ poison, %if.else ], [ %nnan_val, %entry ]
->
%x = select nnan i1 true, float %nnan_val, float poison ->
%x = select nnan i1 true, float %nnan_val, float nan ->
%x = poison (If we apply the nnan flag to both arms)

In some cases, one of the arms of a select may never be selected. If we apply the nnan flag to both the inputs, we cannot preserve the nnan flag in the phi -> select conversion. BTW, it also violates the guarantee that a select doesn’t propagate poison from the value not being selected.

Proposed Change to the LangRef Wording

The LangRef should explicitly state that the poison-generating flags on select instructions are only applied to the final result.

Related comments: [InstCombine] Fix ninf propagation for fcmp+sel -> minmax by dtcxzyw · Pull Request #136433 · llvm/llvm-project · GitHub

cc @nikic @arsenm @jcranmer @nlopes @regehr

I think this makes sense. It follows the usual semantics for select poison propagation and makes select consistent with phi. (For phi it’s not possible to define different semantics.)

Candidate patch: [LangRef] Clarify the behavior of select with FP poison-generating flags by dtcxzyw · Pull Request #137131 · llvm/llvm-project · GitHub