<div dir="ltr">Hello,<div><br></div><div>I'd like to offer an alternative solution to the "poison problem": remove it.</div><div><br></div><div>What follows is rather informal.  I'd happily write up a nicer document if this RFC stands up to scrutiny.</div><div><br></div><div>The idea was born from two observations:</div><div>- undef was introduced to model a load of uninitialized memory, a form of undefined behavior.</div><div>- poison was introduced to model integer overflow, another form of undefined behavior.</div><div><br></div><div>I find it awkward that one form of uninitialized behavior is more or less powerful than another.</div><div><br></div><div>We rely on the following properties for undef:</div><div>- undef is permitted to be an arbitrary bit-pattern.</div><div>- Instructions may or may not be value dependent on their undef operands.<br></div><div><br></div><div>We rely on the following properties for poison:</div><div>- Instructions which have poison operands are capable of providing results which are not consistent with a two's complement operand.</div><div><br></div><div>Here is a case where we believed distinguishing between poison and undef is essential:</div><div>%add = add nsw i32 %a, %b</div><div>%cmp = icmp sgt i32 %add, %a</div><div><br></div><div>If %a is INT_MAX and %b is 1, then %add results in overflow.<br></div><div>If overflow results in undef, then %cmp would be equivalent to:</div><div>%cmp = icmp sgt i32 undef, INT_MIN</div><div><br></div><div>There is no bit-pattern we could substitute for undef which would make %cmp true, this means that we cannot optimize %cmp to 'icmp sgt i32 %b, 0'.</div><div><br></div><div>Poison was created to allow us to produce whatever value we'd like for %cmp if %add resulted in overflow.</div><div><br></div><div>What I would like to do is to remove poison and replace it with undef while still optimizing comparison instructions.  The quick-and-dirty way of stating this is: an icmp with an undef operand produces undef regardless of its other operand.</div><div><br></div><div>I believe this would allow us to exploit and optimize overflow in arithmetic flowing into comparison operations.</div><div><br></div><div>Could this be problematic?</div><div><br></div><div>Whether we intended to or not, LLVM's implementation of undef's semantics already allows us to say that a memory location is not equivalent to any possible bit-pattern.<br></div><div><br></div><div>Consider the following program:</div><div><div>define i1 @f() {</div><div>  %mem = alloca i1</div><div>  %load = load i1* %mem</div><div>  %cmp = icmp eq i1 %load, false</div><div>  ret i1 %cmp</div><div>}</div></div><div><br></div><div>Because it is possible for %load's undef to be either true or false, %cmp must be equivalent to undef as well.  This is completely consistent with the above rules.</div><div><br></div><div>The following program is a little more interesting:</div><div><div>define i1 @g() {</div><div>  %mem = alloca i1</div><div>  %load = load i1* %mem</div><div>  %cmp0 = icmp eq i1 %load, 0</div><div>  %cmp1 = icmp eq i1 %load, 1</div><div>  %and = xor i1 %cmp0, %cmp1</div><div>  ret i1 %and</div><div>}</div></div><div><br></div><div>The intent of this program is to compare a memory location against all possible values the location might have.</div><div><br class="">If we ran LLVM's InstCombine pass then %and would have been replaced with the "expected" result of true.<br></div><div><br></div><div>If we instead ran SROA over @g, we would be left with:<br></div><div><div>  %cmp0 = icmp eq i1 undef, false</div><div>  %cmp1 = icmp eq i1 undef, true</div><div>  %and = xor i1 %cmp0, %cmp1</div></div><div><br></div><div>Now that %cmp0 and %cmp1 have different undef values, %and is now undef.</div><div>This result is sufficient to say that the contents of %mem are neither true nor false!</div></div>