Rewrite the section on trap values to contain a generic description

of dependence and define trap values in terms of dependence, instead
of trying to cover the concept with a flurry of ad-hoc rules.

The dependence model isn't complete yet, but it's already much more
rigorous than the description it replaces.

llvm-svn: 102479
This commit is contained in:
Dan Gohman 2010-04-28 00:49:41 +00:00
parent f8eeafd9f1
commit 9a9dc98868

View File

@ -2336,80 +2336,104 @@ has undefined behavior.</p>
effects has nevertheless detected a condition which results in undefined
behavior.</p>
<p>Any value other than a non-intrinsic call, invoke, or phi with a trap
operand has trap as its result value. Any instruction with
a trap operand which may have side effects emits those side effects as
if it had an undef operand instead. If the side effects are externally
visible, the behavior is undefined.</p>
<p>There is currently no way of representing a trap value in the IR; they
only exist when produced by instructions such as
<a href="#i_add"><tt>add</tt></a> with the <tt>nsw</tt> flag.</p>
<p>Trap values may be stored to memory; a load from memory including any
part of a trap value results in a (full) trap value.</p>
<p>For example:</p>
<p>Trap value behavior is defined in terms of value <i>dependence</i>:</p>
<!-- FIXME: In the case of multiple threads, this only applies to loads from
the same thread as the store, or loads which are sequenced after the
<p>
<ul>
<li>Values other than <a href="#i_phi"><tt>phi</tt></a> nodes depend on
their operands.</li>
<li><a href="#i_phi"><tt>Phi</tt></a> nodes depend on the operand corresponding
to their dynamic predecessor basic block.</li>
<li>Function arguments depend on the corresponding actual argument values in
the dynamic callers of their functions.</li>
<li><a href="#i_call"><tt>Call</tt></a> instructions depend on the
<a href="#i_ret"><tt>ret</tt></a> instructions that dynamically transfer
control back to them.</li>
<li>Non-volatile loads and stores depend on the most recent stores to all of the
referenced memory addresses, following the order in the IR
(including loads and stores implied by intrinsics such as
<a href="#int_memcpy"><tt>@llvm.memcpy</tt></a>.)</li>
<!-- FIXME: padding in the middle of a struct -->
<!-- TODO: In the case of multiple threads, this only applies to loads and
stores from the same thread as the store, or which are sequenced after the
store by synchronization. -->
<div class="doc_code">
<pre>
%trap = sub nuw i32 0, 1 ; Results in a trap value.
%still_trap = and i32 %trap, 0 ; Whereas (and i32 undef, 0) would return 0.
%trap_yet_again = getelementptr i32* @h, i32 %still_trap
store i32 0, i32* %trap_yet_again ; undefined behavior
<!-- TODO: floating-point exception state -->
volatile store i32 %trap, i32* @g ; External observation; undefined behavior.
%trap2 = load i32* @g ; Returns a trap value, not just undef.
%narrowaddr = bitcast i32* @g to i16*
%wideaddr = bitcast i32* @g to i64*
%trap3 = load 16* %narrowaddr ; Returns a trap value
%trap4 = load i64* %widaddr ; Returns a trap value, not partial trap.
</pre>
</div>
<li>An instruction with externally visible side effects depends on the most
recent preceding instruction with externally visible side effects, following
the order in the IR. (This includes volatile loads and stores.)</li>
<p>If a <a href="#i_br"><tt>br</tt></a> or
<a href="#i_switch"><tt>switch</tt></a> instruction has a trap value
operand, all non-phi non-void instructions which control-depend on it
have trap as their result value. A <a href="#i_phi"><tt>phi</tt></a>
node with an incoming value associated with a control edge which is
control-dependent on it has trap as its result value when control is
transferred from that block. If any instruction which control-depends
on the <tt>br</tt> or <tt>switch</tt> invokes externally visible side
effects, the behavior of the program is undefined. For example:</p>
<li>An instruction <i>control-depends</i> on a <a href="#i_br"><tt>br</tt></a>,
<a href="#i_switch"><tt>switch</tt></a>, or
<a href="#i_indirectbr"><tt>indirectbr</tt></a> if the <tt>br</tt>,
<tt>switch</tt>, or <tt>indirectbr</tt> has multiple successors and the
instruction is always executed when control transfers to one of the
successors, and may not be executed when control is transfered to
another.</li>
<!-- FIXME: What about exceptions thrown from control-dependent instrs? -->
<!-- FIXME: invoke, unwind, exceptions -->
<li>Dependence is transitive.</li>
</ul>
</p>
<p>Whenever a trap value is generated, all values which depend on it evaluate
to trap. If they have side effects, the evoke their side effects as if each
operand with a trap value were undef. If they have externally-visible side
effects, the behavior is undefined.</p>
<p>Here are some examples:</p>
<div class="doc_code">
<pre>
entry:
%trap = sub nuw i32 0, 1 ; Results in a trap value.
%cmp = icmp i32 slt %trap, 0 ; Still trap.
%still_trap = and i32 %trap, 0 ; Whereas (and i32 undef, 0) would return 0.
%trap_yet_again = getelementptr i32* @h, i32 %still_trap
store i32 0, i32* %trap_yet_again ; undefined behavior
store i32 %trap, i32* @g ; Trap value conceptually stored to memory.
%trap2 = load i32* @g ; Returns a trap value, not just undef.
volatile store i32 %trap, i32* @g ; External observation; undefined behavior.
%narrowaddr = bitcast i32* @g to i16*
%wideaddr = bitcast i32* @g to i64*
%trap3 = load 16* %narrowaddr ; Returns a trap value.
%trap4 = load i64* %widaddr ; Returns a trap value.
%cmp = icmp i32 slt %trap, 0 ; Returns a trap value.
%br i1 %cmp, %true, %end ; Branch to either destination.
true:
volatile store i32 0, i32* @g ; Externally visible side effects
; control-dependent on %cmp.
; Undefined behavior.
volatile store i32 0, i32* @g ; This is control-dependent on %cmp, so
; it has undefined behavior.
br label %end
end:
%p = phi i32 [ 0, %entry ], [ 1, %true ]
; Both edges into this PHI are
; control-dependent on %cmp, so this
; results in a trap value.
; always results in a trap value.
volatile store i32 0, i32* @g ; %end is control-equivalent to %entry
; so this is defined (ignoring earlier
; undefined behavior in this example).
</pre>
</div>
<p>There is currently no way of representing a trap constant in the IR; they
only exist when produced by certain instructions, such as an
<a href="#i_add"><tt>add</tt></a> with the <tt>nsw</tt> flag
set, when overflow occurs.</p>
</div>
<!-- ======================================================================= -->