mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
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:
parent
1c70c00c28
commit
34b3d993e4
@ -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>
|
||||||
|
|
||||||
<!-- ======================================================================= -->
|
<!-- ======================================================================= -->
|
||||||
|
Loading…
Reference in New Issue
Block a user