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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
/*
* Copyright (C) 2015-2016 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 "AirArg.h"
#include "AirKind.h"
#include "CCallHelpers.h"
namespace JSC {
class CCallHelpers;
class RegisterSet;
namespace B3 {
class Value;
namespace Air {
struct GenerationContext;
struct Inst {
public:
typedef Vector<Arg, 3> ArgList;
Inst()
: origin(nullptr)
{
}
Inst(Kind kind, Value* origin)
: origin(origin)
, kind(kind)
{
}
template<typename... Arguments>
Inst(Kind kind, Value* origin, Arg arg, Arguments... arguments)
: args{ arg, arguments... }
, origin(origin)
, kind(kind)
{
}
Inst(Kind kind, Value* origin, const ArgList& arguments)
: args(arguments)
, origin(origin)
, kind(kind)
{
}
Inst(Kind kind, Value* origin, ArgList&& arguments)
: args(WTFMove(arguments))
, origin(origin)
, kind(kind)
{
}
explicit operator bool() const { return origin || kind || args.size(); }
void append() { }
template<typename... Arguments>
void append(Arg arg, Arguments... arguments)
{
args.append(arg);
append(arguments...);
}
// Note that these functors all avoid using "const" because we want to use them for things that
// edit IR. IR is meant to be edited; if you're carrying around a "const Inst&" then you're
// probably doing it wrong.
// This only walks those Tmps that are explicitly mentioned, and it doesn't tell you their role
// or type.
template<typename Functor>
void forEachTmpFast(const Functor& functor)
{
for (Arg& arg : args)
arg.forEachTmpFast(functor);
}
typedef void EachArgCallback(Arg&, Arg::Role, Arg::Type, Arg::Width);
// Calls the functor with (arg, role, type, width). This function is auto-generated by
// opcode_generator.rb.
template<typename Functor>
void forEachArg(const Functor&);
// Calls the functor with (tmp, role, type, width).
template<typename Functor>
void forEachTmp(const Functor& functor)
{
forEachArg(
[&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) {
arg.forEachTmp(role, type, width, functor);
});
}
// Thing can be either Arg, Tmp, or StackSlot*.
template<typename Thing, typename Functor>
void forEach(const Functor&);
// Reports any additional registers clobbered by this operation. Note that for efficiency,
// extraClobberedRegs() only works for the Patch opcode.
RegisterSet extraClobberedRegs();
RegisterSet extraEarlyClobberedRegs();
// Iterate over all Def's that happen at the end of an instruction. You supply a pair
// instructions. The instructions must appear next to each other, in that order, in some basic
// block. You can pass null for the first instruction when analyzing what happens at the top of
// a basic block. You can pass null for the second instruction when analyzing what happens at the
// bottom of a basic block.
template<typename Thing, typename Functor>
static void forEachDef(Inst* prevInst, Inst* nextInst, const Functor&);
// Iterate over all Def's that happen at the end of this instruction, including extra clobbered
// registers. Note that Thing can only be Arg or Tmp when you use this functor.
template<typename Thing, typename Functor>
static void forEachDefWithExtraClobberedRegs(Inst* prevInst, Inst* nextInst, const Functor&);
// Use this to report which registers are live. This should be done just before codegen. Note
// that for efficiency, reportUsedRegisters() only works for the Patch opcode.
void reportUsedRegisters(const RegisterSet&);
// Is this instruction in one of the valid forms right now? This function is auto-generated by
// opcode_generator.rb.
bool isValidForm();
// Assuming this instruction is in a valid form right now, will it still be in one of the valid
// forms if we put an Addr referencing the stack (or a StackSlot or CallArg, of course) in the
// given index? Spilling uses this: it walks the args by index to find Tmps that need spilling;
// if it finds one, it calls this to see if it can replace the Arg::Tmp with an Arg::Addr. If it
// finds a non-Tmp Arg, then it calls that Arg's forEachTmp to do a replacement that way.
//
// This function is auto-generated by opcode_generator.rb.
bool admitsStack(unsigned argIndex);
bool admitsStack(Arg&);
// Defined by opcode_generator.rb.
bool isTerminal();
// Returns true if this instruction can have any effects other than control flow or arguments.
bool hasNonArgNonControlEffects();
// Returns true if this instruction can have any effects other than what is implied by arguments.
// For example, "Move $42, (%rax)" will return false because the effect of storing to (%rax) is
// implied by the second argument.
bool hasNonArgEffects();
// Tells you if this operation has arg effects.
bool hasArgEffects();
// Tells you if this operation has non-control effects.
bool hasNonControlEffects() { return hasNonArgNonControlEffects() || hasArgEffects(); }
// Generate some code for this instruction. This is, like, literally our backend. If this is the
// terminal, it returns the jump that needs to be linked for the "then" case, with the "else"
// case being fall-through. This function is auto-generated by opcode_generator.rb.
CCallHelpers::Jump generate(CCallHelpers&, GenerationContext&);
// If source arguments benefits from being aliased to a destination argument,
// this return the index of the destination argument.
// The source are assumed to be at (index - 1) and (index - 2)
// For example,
// Add Tmp1, Tmp2, Tmp3
// returns 2 if 0 and 1 benefit from aliasing to Tmp3.
std::optional<unsigned> shouldTryAliasingDef();
// This computes a hash for comparing this to JSAir's Inst.
unsigned jsHash() const;
void dump(PrintStream&) const;
ArgList args;
Value* origin; // The B3::Value that this originated from.
Kind kind;
};
} } } // namespace JSC::B3::Air
#endif // ENABLE(B3_JIT)
|