1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
/*
* Copyright (C) 2015-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if ENABLE(B3_JIT)
#include "B3HeapRange.h"
#include <wtf/PrintStream.h>
namespace JSC { namespace B3 {
enum class Mutability : uint8_t {
Mutable,
Immutable,
};
struct Effects {
// True if this cannot continue execution in the current block.
bool terminal : 1 { false };
// True if this value can cause execution to terminate abruptly, and that this abrupt termination is
// observable. An example of how this gets used is to limit the hoisting of controlDependent values.
// Note that if exitsSideways is set to true but reads is bottom, then B3 is free to assume that
// after abrupt termination of this procedure, none of the heap will be read. That's usually false,
// so make sure that reads corresponds to the set of things that are readable after this function
// terminates abruptly.
bool exitsSideways : 1 { false };
// True if the instruction may change semantics if hoisted above some control flow. For example,
// loads are usually control-dependent because we must assume that any control construct (either
// a terminal like Branch or anything that exits sideways, like Check) validates whether the
// pointer is valid. Hoisting the load above control may cause the load to trap even though it
// would not have otherwise trapped.
bool controlDependent : 1 { false };
// Mutability::Immutable if the instruction is readings an immutable value. This read itself can
// be control dependent, but once it succeeds, the subsequent code must be producing the same value.
// CSE leverages this information and eliminate redundant loads when the target and preceding load
// are the same and Mutability::Immutable.
Mutability readsMutability : 1 { Mutability::Mutable };
// True if this writes to the local state. Operations that write local state don't write to anything
// in "memory" but they have a side-effect anyway. This is for modeling Upsilons, Sets, and Fences.
// This is a way of saying: even though this operation is not a terminal, does not exit sideways,
// and does not write to the heap, you still cannot kill this operation.
bool writesLocalState : 1 { false };
// True if this reads from the local state. This is only used for Phi and Get.
bool readsLocalState : 1 { false };
// B3 understands things about pinned registers. Therefore, it needs to know who reads them and
// who writes them. We don't track this on a per-register basis because that would be harder and
// we don't need it. Note that if you want to construct an immutable pinned register while also
// having other pinned registers that are mutable, then you can use ArgumentReg. Also note that
// nobody will stop you from making this get out-of-sync with your clobbered register sets in
// Patchpoint. It's recommended that you err on the side of being conservative.
// FIXME: Explore making these be RegisterSetBuilders. That's mainly hard because it would be awkward to
// reconcile with StackmapValue's support for clobbered regs.
// https://bugs.webkit.org/show_bug.cgi?id=163173
bool readsPinned : 1 { false };
bool writesPinned : 1 { false };
// Memory fences cannot be reordered around each other regardless of their effects. This is flagged
// if the operation is a memory fence.
bool fence : 1 { false };
// WARNING: The B3::hoistLoopInvariantValues() phase thinks that it understands this exhaustively. If you
// add any new kinds of things that can be read or written, you should check that phase.
HeapRange writes;
HeapRange reads;
static Effects none()
{
return Effects();
}
static Effects forCall()
{
Effects result;
result.exitsSideways = true;
result.controlDependent = true;
result.writes = HeapRange::top();
result.reads = HeapRange::top();
result.readsPinned = true;
result.writesPinned = true;
result.fence = true;
return result;
}
static Effects forCheck()
{
Effects result;
result.exitsSideways = true;
// The program could read anything after exiting, and it's on us to declare this.
result.reads = HeapRange::top();
return result;
}
bool mustExecute() const
{
return terminal || exitsSideways || writesLocalState || writes || writesPinned || fence;
}
// Returns true if reordering instructions with these respective effects would change program
// behavior in an observable way.
bool interferes(const Effects&) const;
friend bool operator==(const Effects&, const Effects&) = default;
JS_EXPORT_PRIVATE void dump(PrintStream& out) const;
};
} } // namespace JSC::B3
#endif // ENABLE(B3_JIT)
|