1 : // Copyright 2012 Google Inc.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : // This file declares implementation classes to generate assembly code.
16 : // The API to the assembler is intentionally very close to the API exposed
17 : // by the V8 assembler.
18 :
19 : #ifndef SYZYGY_CORE_ASSEMBLER_H_
20 : #define SYZYGY_CORE_ASSEMBLER_H_
21 :
22 : #include "base/basictypes.h"
23 : #include "base/logging.h"
24 :
25 : namespace core {
26 :
27 : enum RegisterCode {
28 : kRegisterNone = -1,
29 : kRegisterEax = 0,
30 : kRegisterEcx = 1,
31 : kRegisterEdx = 2,
32 : kRegisterEbx = 3,
33 : kRegisterEsp = 4,
34 : kRegisterEbp = 5,
35 : kRegisterEsi = 6,
36 : kRegisterEdi = 7,
37 : };
38 :
39 : // The condition codes by which conditional branches are determined. This enum
40 : // is taken from the V8 project, and has the property that the conditions are
41 : // defined to be bit-wise ORed into the base conditional branch opcode, and
42 : // they can be easily negated/inverted.
43 : //
44 : // See:
45 : // http://code.google.com/p/v8/source/browse/trunk/src/ia32/assembler-ia32.h
46 : enum ConditionCode {
47 : // Any value < 0 is considered no_condition
48 : kNoCondition = -1,
49 :
50 : kOverflow = 0,
51 : kNoOverflow = 1,
52 : kBelow = 2,
53 : kAboveEqual = 3,
54 : kEqual = 4,
55 : kNotEqual = 5,
56 : kBelowEqual = 6,
57 : kAbove = 7,
58 : kNegative = 8,
59 : kPositive = 9,
60 : kParityEven = 10,
61 : kParityOdd = 11,
62 : kLess = 12,
63 : kGreaterEqual = 13,
64 : kLessEqual = 14,
65 : kGreater = 15,
66 :
67 : // Aliases.
68 : kCarry = kBelow,
69 : kNotCarry = kAboveEqual,
70 : kZero = kEqual,
71 : kNotZero = kNotEqual,
72 : kSign = kNegative,
73 : kNotSign = kPositive,
74 :
75 : // Extents.
76 : kMinConditionCode = 0,
77 : kMaxConditionCode = 15
78 : };
79 :
80 : // The conditions on which a loop instruction should branch. These are modeled
81 : // in the same manner as ConditionCode (above).
82 : enum LoopCode {
83 : kLoopOnCounterAndNotZeroFlag = 0, // LOOPNE and LOOPNZ
84 : kLoopOnCounterAndZeroFlag = 1, // LOOPE and NOOPZ.
85 : kLoopOnCounter = 2, // LOOP.
86 : };
87 :
88 E : inline ConditionCode NegateConditionCode(ConditionCode cc) {
89 E : DCHECK_GT(16, cc);
90 E : return static_cast<ConditionCode>(cc ^ 1);
91 E : }
92 :
93 : // Each instance of this class names a register.
94 : class Register {
95 : public:
96 E : explicit Register(RegisterCode code) : code_(code) {
97 E : DCHECK(code != kRegisterNone);
98 E : }
99 :
100 E : RegisterCode code() const { return code_; }
101 : void set_code(RegisterCode code) { code_ = code; }
102 :
103 : private:
104 : RegisterCode code_;
105 : };
106 :
107 : // Convenience constants for the x86 registers.
108 : extern const Register eax;
109 : extern const Register ecx;
110 : extern const Register edx;
111 : extern const Register ebx;
112 : extern const Register esp;
113 : extern const Register ebp;
114 : extern const Register esi;
115 : extern const Register edi;
116 :
117 : // Selects a scale for the Operand addressing modes.
118 : // The values match the encoding in the x86 SIB bytes.
119 : enum ScaleFactor {
120 : kTimes1 = 0,
121 : kTimes2 = 1,
122 : kTimes4 = 2,
123 : kTimes8 = 3,
124 : };
125 :
126 : // Size for immediate and displacement operands.
127 : enum ValueSize {
128 : kSizeNone,
129 : kSize8Bit,
130 : kSize32Bit,
131 : };
132 :
133 : // An instance of this class is an explicit value, which is either
134 : // an immediate or a displacement.
135 : class ValueImpl {
136 : public:
137 : ValueImpl();
138 : ValueImpl(uint32 value, ValueSize size);
139 : ValueImpl(uint32 value, ValueSize size, const void* imm_ref);
140 :
141 : // @name Accessors.
142 : // @{
143 E : uint32 value() const { return value_; }
144 E : const void* reference() const { return reference_; }
145 E : ValueSize size() const { return size_; }
146 : // @}
147 :
148 : private:
149 : uint32 value_;
150 : const void* reference_;
151 : ValueSize size_;
152 : };
153 :
154 : // Displacements and immediates behave near-identically, but are semantically
155 : // slightly different.
156 : typedef ValueImpl ImmediateImpl;
157 : typedef ValueImpl DisplacementImpl;
158 :
159 : // An operand implies indirection to memory through one of the myriad
160 : // modes supported by IA32.
161 : class OperandImpl {
162 : public:
163 : // A register-indirect mode.
164 : explicit OperandImpl(Register base);
165 :
166 : // A register-indirect with displacement mode.
167 : OperandImpl(Register base, const DisplacementImpl& displ);
168 :
169 : // A displacement-only mode.
170 : explicit OperandImpl(const DisplacementImpl& displ);
171 :
172 : // The full [base + index * scale + displ32] mode.
173 : // @note esp cannot be used as an index register.
174 : OperandImpl(Register base,
175 : Register index,
176 : ScaleFactor scale,
177 : const DisplacementImpl& displ);
178 :
179 : // The [base + index * scale] mode.
180 : // @note esp cannot be used as an index register.
181 : OperandImpl(Register base,
182 : Register index,
183 : ScaleFactor scale);
184 :
185 : // The [index * scale + displ32] mode - e.g. no base.
186 : // @note esp cannot be used as an index register.
187 : OperandImpl(Register index,
188 : ScaleFactor scale,
189 : const DisplacementImpl& displ);
190 :
191 : // Low-level constructor, none of the parameters are checked.
192 : OperandImpl(RegisterCode base,
193 : RegisterCode index,
194 : ScaleFactor scale,
195 : const DisplacementImpl& displacement);
196 :
197 : // @name Accessors.
198 : // @{
199 E : RegisterCode base() const { return base_; }
200 E : RegisterCode index() const { return index_; }
201 E : ScaleFactor scale() const { return scale_; }
202 E : const DisplacementImpl& displacement() const { return displacement_; }
203 : // @}
204 :
205 : private:
206 : // The base register involved, or none.
207 : RegisterCode base_;
208 : // The index register involved, or none.
209 : RegisterCode index_;
210 : // The scaling factor, must be kTimes1 if no index register.
211 : ScaleFactor scale_;
212 : // The displacement, if any.
213 : DisplacementImpl displacement_;
214 : };
215 :
216 : // The assembler takes care of maintaining an output location (address), and
217 : // generating a stream of bytes and references as instructions are assembled.
218 : class AssemblerImpl {
219 : public:
220 : // The assembler pushes instructions and references to
221 : // one of these for serialization.
222 : class InstructionSerializer {
223 : public:
224 : virtual void AppendInstruction(uint32 location,
225 : const uint8* bytes,
226 : size_t num_bytes,
227 : const size_t *ref_locations,
228 : const void* const* refs,
229 : size_t num_refs) = 0;
230 : };
231 :
232 : // Constructs an assembler that assembles to @p delegate
233 : // starting at @p location.
234 : AssemblerImpl(uint32 location, InstructionSerializer* serializer);
235 :
236 : // @name Accessors.
237 : // @{
238 E : uint32 location() const { return location_; }
239 E : void set_location(uint32 location) { location_ = location; }
240 : // @}
241 :
242 : // @name Call instructions.
243 : // @{
244 : void call(const ImmediateImpl& dst);
245 : void call(const OperandImpl& dst);
246 : // @}
247 :
248 : // @name Control flow instructions.
249 : // @{
250 : void j(ConditionCode cc, const ImmediateImpl& dst);
251 : void jecxz(const ImmediateImpl& dst);
252 : void jmp(const ImmediateImpl& dst);
253 : void jmp(const OperandImpl& dst);
254 : void l(LoopCode lc, const ImmediateImpl& dst);
255 : void ret();
256 : void ret(uint16 n);
257 : // @}
258 :
259 : // @name byte mov varieties.
260 : // @{
261 : void mov_b(const OperandImpl& dst, const ImmediateImpl& src);
262 : // @}
263 :
264 : // @name Double-word mov varieties.
265 : // @{
266 : void mov(Register dst, Register src);
267 : void mov(Register dst, const OperandImpl& src);
268 : void mov(const OperandImpl& dst, Register src);
269 : void mov(Register dst, const ImmediateImpl& src);
270 : void mov(const OperandImpl& dst, const ImmediateImpl& src);
271 : // @}
272 :
273 : // @name load effective address.
274 : void lea(Register dst, const OperandImpl& src);
275 :
276 : // @name stack manipulation.
277 : // @{
278 : void push(Register src);
279 : void push(const ImmediateImpl& src);
280 : void push(const OperandImpl& src);
281 :
282 : void pop(Register dst);
283 : void pop(const OperandImpl& src);
284 : // @}
285 :
286 : // @name Aliases
287 : // @{
288 E : void loop(const ImmediateImpl& dst) { l(kLoopOnCounter, dst); }
289 E : void loope(const ImmediateImpl& dst) { l(kLoopOnCounterAndZeroFlag, dst); }
290 E : void loopne(const ImmediateImpl& dst) {
291 E : l(kLoopOnCounterAndNotZeroFlag, dst);
292 E : }
293 : // @}
294 :
295 : // The maximum length a single instruction will assemble to.
296 : static const size_t kMaxInstructionLength;
297 :
298 : private:
299 : class InstructionBuffer;
300 : // Output the instruction data in @p instr to our delegate.
301 : void Output(const InstructionBuffer& instr);
302 :
303 : // Stores the current location of assembly.
304 : uint32 location_;
305 :
306 : // The delegate we push instructions at.
307 : InstructionSerializer* serializer_;
308 : };
309 :
310 : } // namespace core
311 :
312 : #endif // SYZYGY_CORE_ASSEMBLER_H_
|