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.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@102479 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dan Gohman 2010-04-28 00:49:41 +00:00
parent 1c70c00c28
commit 34b3d993e4

View File

@ -2336,80 +2336,104 @@ has undefined behavior.</p>
effects has nevertheless detected a condition which results in undefined effects has nevertheless detected a condition which results in undefined
behavior.</p> behavior.</p>
<p>Any value other than a non-intrinsic call, invoke, or phi with a trap <p>There is currently no way of representing a trap value in the IR; they
operand has trap as its result value. Any instruction with only exist when produced by instructions such as
a trap operand which may have side effects emits those side effects as <a href="#i_add"><tt>add</tt></a> with the <tt>nsw</tt> flag.</p>
if it had an undef operand instead. If the side effects are externally
visible, the behavior is undefined.</p>
<p>Trap values may be stored to memory; a load from memory including any <p>Trap value behavior is defined in terms of value <i>dependence</i>:</p>
part of a trap value results in a (full) trap value.</p>
<p>For example:</p> <p>
<ul>
<li>Values other than <a href="#i_phi"><tt>phi</tt></a> nodes depend on
their operands.</li>
<!-- FIXME: In the case of multiple threads, this only applies to loads from <li><a href="#i_phi"><tt>Phi</tt></a> nodes depend on the operand corresponding
the same thread as the store, or loads which are sequenced after the 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. --> store by synchronization. -->
<div class="doc_code"> <!-- TODO: floating-point exception state -->
<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
volatile store i32 %trap, i32* @g ; External observation; undefined behavior. <li>An instruction with externally visible side effects depends on the most
%trap2 = load i32* @g ; Returns a trap value, not just undef. recent preceding instruction with externally visible side effects, following
%narrowaddr = bitcast i32* @g to i16* the order in the IR. (This includes volatile loads and stores.)</li>
%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>
<p>If a <a href="#i_br"><tt>br</tt></a> or <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> instruction has a trap value <a href="#i_switch"><tt>switch</tt></a>, or
operand, all non-phi non-void instructions which control-depend on it <a href="#i_indirectbr"><tt>indirectbr</tt></a> if the <tt>br</tt>,
have trap as their result value. A <a href="#i_phi"><tt>phi</tt></a> <tt>switch</tt>, or <tt>indirectbr</tt> has multiple successors and the
node with an incoming value associated with a control edge which is instruction is always executed when control transfers to one of the
control-dependent on it has trap as its result value when control is successors, and may not be executed when control is transfered to
transferred from that block. If any instruction which control-depends another.</li>
on the <tt>br</tt> or <tt>switch</tt> invokes externally visible side
effects, the behavior of the program is undefined. For example:</p>
<!-- 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"> <div class="doc_code">
<pre> <pre>
entry: entry:
%trap = sub nuw i32 0, 1 ; Results in a trap value. %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. %br i1 %cmp, %true, %end ; Branch to either destination.
true: true:
volatile store i32 0, i32* @g ; Externally visible side effects volatile store i32 0, i32* @g ; This is control-dependent on %cmp, so
; control-dependent on %cmp. ; it has undefined behavior.
; Undefined behavior.
br label %end br label %end
end: end:
%p = phi i32 [ 0, %entry ], [ 1, %true ] %p = phi i32 [ 0, %entry ], [ 1, %true ]
; Both edges into this PHI are ; Both edges into this PHI are
; control-dependent on %cmp, so this ; 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 volatile store i32 0, i32* @g ; %end is control-equivalent to %entry
; so this is defined (ignoring earlier ; so this is defined (ignoring earlier
; undefined behavior in this example). ; undefined behavior in this example).
</pre> </pre>
</div> </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> </div>
<!-- ======================================================================= --> <!-- ======================================================================= -->