1/*
2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if ENABLE(B3_JIT)
29
30#include "AirInst.h"
31#include "B3SparseCollection.h"
32#include <wtf/FastMalloc.h>
33#include <wtf/Noncopyable.h>
34#include <wtf/ScopedLambda.h>
35#include <wtf/text/CString.h>
36
37namespace JSC { namespace B3 { namespace Air {
38
39class Code;
40struct GenerationContext;
41
42class Special {
43 WTF_MAKE_NONCOPYABLE(Special);
44 WTF_MAKE_FAST_ALLOCATED;
45public:
46 static const char* const dumpPrefix;
47
48 Special();
49 JS_EXPORT_PRIVATE virtual ~Special();
50
51 Code& code() const { return *m_code; }
52
53 CString name() const;
54
55 virtual void forEachArg(Inst&, const ScopedLambda<Inst::EachArgCallback>&) = 0;
56 virtual bool isValid(Inst&) = 0;
57 virtual bool admitsStack(Inst&, unsigned argIndex) = 0;
58 virtual bool admitsExtendedOffsetAddr(Inst&, unsigned argIndex) = 0;
59 virtual Optional<unsigned> shouldTryAliasingDef(Inst&);
60
61 // This gets called on for each Inst that uses this Special. Note that there is no way to
62 // guarantee that a Special gets used from just one Inst, because Air might taildup late. So,
63 // if you want to pass this information down to generate(), then you have to either:
64 //
65 // 1) Generate Air that starts with a separate Special per Patch Inst, and then merge
66 // usedRegister sets. This is probably not great, but it optimizes for the common case that
67 // Air didn't duplicate code or that such duplication didn't cause any interesting changes to
68 // register assignment.
69 //
70 // 2) Have the Special maintain a HashMap<Inst*, RegisterSet>. This works because the analysis
71 // that feeds into this call is performed just before code generation and there is no way
72 // for the Vector<>'s that contain the Insts to be reallocated. This allows generate() to
73 // consult the HashMap.
74 //
75 // 3) Hybrid: you could use (1) and fire up a HashMap if you see multiple calls.
76 //
77 // Note that it's not possible to rely on reportUsedRegisters() being called in the same order
78 // as generate(). If we could rely on that, then we could just have each Special instance
79 // maintain a Vector of RegisterSet's and then process that vector in the right order in
80 // generate(). But, the ordering difference is unlikely to change since it would harm the
81 // performance of the liveness analysis.
82 //
83 // Currently, we do (1) for B3 stackmaps.
84 virtual void reportUsedRegisters(Inst&, const RegisterSet&) = 0;
85
86 virtual CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&) = 0;
87
88 virtual RegisterSet extraEarlyClobberedRegs(Inst&) = 0;
89 virtual RegisterSet extraClobberedRegs(Inst&) = 0;
90
91 // By default, this returns false.
92 virtual bool isTerminal(Inst&);
93
94 // By default, this returns true.
95 virtual bool hasNonArgEffects(Inst&);
96
97 // By default, this returns true.
98 virtual bool hasNonArgNonControlEffects(Inst&);
99
100 void dump(PrintStream&) const;
101 void deepDump(PrintStream&) const;
102
103protected:
104 virtual void dumpImpl(PrintStream&) const = 0;
105 virtual void deepDumpImpl(PrintStream&) const = 0;
106
107private:
108 friend class Code;
109 friend class SparseCollection<Special>;
110
111 unsigned m_index { UINT_MAX };
112 Code* m_code { nullptr };
113};
114
115class DeepSpecialDump {
116public:
117 DeepSpecialDump(const Special* special)
118 : m_special(special)
119 {
120 }
121
122 void dump(PrintStream& out) const
123 {
124 if (m_special)
125 m_special->deepDump(out);
126 else
127 out.print("<null>");
128 }
129
130private:
131 const Special* m_special;
132};
133
134inline DeepSpecialDump deepDump(const Special* special)
135{
136 return DeepSpecialDump(special);
137}
138
139} } } // namespace JSC::B3::Air
140
141#endif // ENABLE(B3_JIT)
142