1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_WASM_BASELINE_LIFTOFF_ASSEMBLER_H_
6 #define V8_WASM_BASELINE_LIFTOFF_ASSEMBLER_H_
7
8 #include <iosfwd>
9 #include <memory>
10
11 #include "src/base/bits.h"
12 #include "src/base/small-vector.h"
13 #include "src/codegen/macro-assembler.h"
14 #include "src/wasm/baseline/liftoff-assembler-defs.h"
15 #include "src/wasm/baseline/liftoff-compiler.h"
16 #include "src/wasm/baseline/liftoff-register.h"
17 #include "src/wasm/function-body-decoder.h"
18 #include "src/wasm/wasm-code-manager.h"
19 #include "src/wasm/wasm-module.h"
20 #include "src/wasm/wasm-opcodes.h"
21 #include "src/wasm/wasm-value.h"
22
23 namespace v8 {
24 namespace internal {
25
26 // Forward declarations.
27 namespace compiler {
28 class CallDescriptor;
29 } // namespace compiler
30
31 namespace wasm {
32
33 enum LiftoffCondition {
34 kEqual,
35 kEqualZero = kEqual, // When used in a unary operation.
36 kUnequal,
37 kNotEqualZero = kUnequal, // When used in a unary operation.
38 kSignedLessThan,
39 kSignedLessEqual,
40 kSignedGreaterThan,
41 kSignedGreaterEqual,
42 kUnsignedLessThan,
43 kUnsignedLessEqual,
44 kUnsignedGreaterThan,
45 kUnsignedGreaterEqual
46 };
47
Negate(LiftoffCondition cond)48 inline constexpr LiftoffCondition Negate(LiftoffCondition cond) {
49 switch (cond) {
50 case kEqual:
51 return kUnequal;
52 case kUnequal:
53 return kEqual;
54 case kSignedLessThan:
55 return kSignedGreaterEqual;
56 case kSignedLessEqual:
57 return kSignedGreaterThan;
58 case kSignedGreaterEqual:
59 return kSignedLessThan;
60 case kSignedGreaterThan:
61 return kSignedLessEqual;
62 case kUnsignedLessThan:
63 return kUnsignedGreaterEqual;
64 case kUnsignedLessEqual:
65 return kUnsignedGreaterThan;
66 case kUnsignedGreaterEqual:
67 return kUnsignedLessThan;
68 case kUnsignedGreaterThan:
69 return kUnsignedLessEqual;
70 }
71 }
72
Flip(LiftoffCondition cond)73 inline constexpr LiftoffCondition Flip(LiftoffCondition cond) {
74 switch (cond) {
75 case kEqual:
76 return kEqual;
77 case kUnequal:
78 return kUnequal;
79 case kSignedLessThan:
80 return kSignedGreaterThan;
81 case kSignedLessEqual:
82 return kSignedGreaterEqual;
83 case kSignedGreaterEqual:
84 return kSignedLessEqual;
85 case kSignedGreaterThan:
86 return kSignedLessThan;
87 case kUnsignedLessThan:
88 return kUnsignedGreaterThan;
89 case kUnsignedLessEqual:
90 return kUnsignedGreaterEqual;
91 case kUnsignedGreaterEqual:
92 return kUnsignedLessEqual;
93 case kUnsignedGreaterThan:
94 return kUnsignedLessThan;
95 }
96 }
97
98 class LiftoffAssembler : public TurboAssembler {
99 public:
100 // Each slot in our stack frame currently has exactly 8 bytes.
101 static constexpr int kStackSlotSize = 8;
102
103 static constexpr ValueKind kPointerKind =
104 kSystemPointerSize == kInt32Size ? kI32 : kI64;
105 static constexpr ValueKind kTaggedKind =
106 kTaggedSize == kInt32Size ? kI32 : kI64;
107 static constexpr ValueKind kSmiKind = kTaggedKind;
108
109 using ValueKindSig = Signature<ValueKind>;
110
111 class VarState {
112 public:
113 enum Location : uint8_t { kStack, kRegister, kIntConst };
114
VarState(ValueKind kind, int offset)115 explicit VarState(ValueKind kind, int offset)
116 : loc_(kStack), kind_(kind), spill_offset_(offset) {}
VarState(ValueKind kind, LiftoffRegister r, int offset)117 explicit VarState(ValueKind kind, LiftoffRegister r, int offset)
118 : loc_(kRegister), kind_(kind), reg_(r), spill_offset_(offset) {
119 DCHECK_EQ(r.reg_class(), reg_class_for(kind));
120 }
VarState(ValueKind kind, int32_t i32_const, int offset)121 explicit VarState(ValueKind kind, int32_t i32_const, int offset)
122 : loc_(kIntConst),
123 kind_(kind),
124 i32_const_(i32_const),
125 spill_offset_(offset) {
126 DCHECK(kind_ == kI32 || kind_ == kI64);
127 }
128
is_stack() const129 bool is_stack() const { return loc_ == kStack; }
is_gp_reg() const130 bool is_gp_reg() const { return loc_ == kRegister && reg_.is_gp(); }
is_fp_reg() const131 bool is_fp_reg() const { return loc_ == kRegister && reg_.is_fp(); }
is_reg() const132 bool is_reg() const { return loc_ == kRegister; }
is_const() const133 bool is_const() const { return loc_ == kIntConst; }
134
kind() const135 ValueKind kind() const { return kind_; }
136
loc() const137 Location loc() const { return loc_; }
138
i32_const() const139 int32_t i32_const() const {
140 DCHECK_EQ(loc_, kIntConst);
141 return i32_const_;
142 }
constant() const143 WasmValue constant() const {
144 DCHECK(kind_ == kI32 || kind_ == kI64);
145 DCHECK_EQ(loc_, kIntConst);
146 return kind_ == kI32 ? WasmValue(i32_const_)
147 : WasmValue(int64_t{i32_const_});
148 }
149
offset() const150 int offset() const { return spill_offset_; }
set_offset(int offset)151 void set_offset(int offset) { spill_offset_ = offset; }
152
gp_reg() const153 Register gp_reg() const { return reg().gp(); }
fp_reg() const154 DoubleRegister fp_reg() const { return reg().fp(); }
reg() const155 LiftoffRegister reg() const {
156 DCHECK_EQ(loc_, kRegister);
157 return reg_;
158 }
reg_class() const159 RegClass reg_class() const { return reg().reg_class(); }
160
MakeStack()161 void MakeStack() { loc_ = kStack; }
162
MakeRegister(LiftoffRegister r)163 void MakeRegister(LiftoffRegister r) {
164 loc_ = kRegister;
165 reg_ = r;
166 }
167
MakeConstant(int32_t i32_const)168 void MakeConstant(int32_t i32_const) {
169 DCHECK(kind_ == kI32 || kind_ == kI64);
170 loc_ = kIntConst;
171 i32_const_ = i32_const;
172 }
173
174 // Copy src to this, except for offset, since src and this could have been
175 // from different stack states.
Copy(VarState src)176 void Copy(VarState src) {
177 loc_ = src.loc();
178 kind_ = src.kind();
179 if (loc_ == kRegister) {
180 reg_ = src.reg();
181 } else if (loc_ == kIntConst) {
182 i32_const_ = src.i32_const();
183 }
184 }
185
186 private:
187 Location loc_;
188 // TODO(wasm): This is redundant, the decoder already knows the type of each
189 // stack value. Try to collapse.
190 ValueKind kind_;
191
192 union {
193 LiftoffRegister reg_; // used if loc_ == kRegister
194 int32_t i32_const_; // used if loc_ == kIntConst
195 };
196 int spill_offset_;
197 };
198
199 ASSERT_TRIVIALLY_COPYABLE(VarState);
200
201 struct CacheState {
202 // Allow default construction, move construction, and move assignment.
203 CacheState() = default;
204 CacheState(CacheState&&) V8_NOEXCEPT = default;
205 CacheState& operator=(CacheState&&) V8_NOEXCEPT = default;
206 // Disallow copy construction.
207 CacheState(const CacheState&) = delete;
208
209 enum class SpillLocation { kTopOfStack, kStackSlots };
210 // Generates two lists of locations that contain references. {slots}
211 // contains the indices of slots on the value stack that contain references.
212 // {spills} contains all registers that contain references. The
213 // {spill_location} defines where register values will be spilled for a
214 // function call within the out-of-line code. {kStackSlots} means that the
215 // values in the registers will be written back to their stack slots.
216 // {kTopOfStack} means that the registers will be spilled on the stack with
217 // a {push} instruction.
218 void GetTaggedSlotsForOOLCode(/*out*/ ZoneVector<int>* slots,
219 /*out*/ LiftoffRegList* spills,
220 SpillLocation spill_location);
221
222 void DefineSafepoint(SafepointTableBuilder::Safepoint& safepoint);
223
224 void DefineSafepointWithCalleeSavedRegisters(
225 SafepointTableBuilder::Safepoint& safepoint);
226
227 base::SmallVector<VarState, 8> stack_state;
228 LiftoffRegList used_registers;
229 uint32_t register_use_count[kAfterMaxLiftoffRegCode] = {0};
230 LiftoffRegList last_spilled_regs;
231 Register cached_instance = no_reg;
232 Register cached_mem_start = no_reg;
233
has_unused_registerv8::internal::wasm::LiftoffAssembler::CacheState234 bool has_unused_register(RegClass rc, LiftoffRegList pinned = {}) const {
235 if (kNeedI64RegPair && rc == kGpRegPair) {
236 LiftoffRegList available_regs =
237 kGpCacheRegList.MaskOut(used_registers).MaskOut(pinned);
238 return available_regs.GetNumRegsSet() >= 2;
239 } else if (kNeedS128RegPair && rc == kFpRegPair) {
240 LiftoffRegList available_regs =
241 kFpCacheRegList.MaskOut(used_registers).MaskOut(pinned);
242 return available_regs.HasAdjacentFpRegsSet();
243 }
244 DCHECK(rc == kGpReg || rc == kFpReg);
245 LiftoffRegList candidates = GetCacheRegList(rc);
246 return has_unused_register(candidates.MaskOut(pinned));
247 }
248
has_unused_registerv8::internal::wasm::LiftoffAssembler::CacheState249 bool has_unused_register(LiftoffRegList candidates) const {
250 LiftoffRegList available_regs = candidates.MaskOut(used_registers);
251 return !available_regs.is_empty();
252 }
253
unused_registerv8::internal::wasm::LiftoffAssembler::CacheState254 LiftoffRegister unused_register(RegClass rc,
255 LiftoffRegList pinned = {}) const {
256 if (kNeedI64RegPair && rc == kGpRegPair) {
257 Register low = pinned.set(unused_register(kGpReg, pinned)).gp();
258 Register high = unused_register(kGpReg, pinned).gp();
259 return LiftoffRegister::ForPair(low, high);
260 } else if (kNeedS128RegPair && rc == kFpRegPair) {
261 LiftoffRegList available_regs =
262 kFpCacheRegList.MaskOut(used_registers).MaskOut(pinned);
263 DoubleRegister low =
264 available_regs.GetAdjacentFpRegsSet().GetFirstRegSet().fp();
265 DCHECK(is_free(LiftoffRegister::ForFpPair(low)));
266 return LiftoffRegister::ForFpPair(low);
267 }
268 DCHECK(rc == kGpReg || rc == kFpReg);
269 LiftoffRegList candidates = GetCacheRegList(rc);
270 return unused_register(candidates, pinned);
271 }
272
unused_registerv8::internal::wasm::LiftoffAssembler::CacheState273 LiftoffRegister unused_register(LiftoffRegList candidates,
274 LiftoffRegList pinned = {}) const {
275 LiftoffRegList available_regs =
276 candidates.MaskOut(used_registers).MaskOut(pinned);
277 return available_regs.GetFirstRegSet();
278 }
279
280 // Volatile registers are registers which are used for caching values that
281 // can easily be reloaded. Those are returned first if we run out of free
282 // registers.
has_volatile_registerv8::internal::wasm::LiftoffAssembler::CacheState283 bool has_volatile_register(LiftoffRegList candidates) {
284 return (cached_instance != no_reg && candidates.has(cached_instance)) ||
285 (cached_mem_start != no_reg && candidates.has(cached_mem_start));
286 }
287
take_volatile_registerv8::internal::wasm::LiftoffAssembler::CacheState288 LiftoffRegister take_volatile_register(LiftoffRegList candidates) {
289 DCHECK(has_volatile_register(candidates));
290 Register reg = no_reg;
291 if (cached_instance != no_reg && candidates.has(cached_instance)) {
292 reg = cached_instance;
293 cached_instance = no_reg;
294 } else {
295 DCHECK(candidates.has(cached_mem_start));
296 reg = cached_mem_start;
297 cached_mem_start = no_reg;
298 }
299
300 LiftoffRegister ret{reg};
301 DCHECK_EQ(1, register_use_count[ret.liftoff_code()]);
302 register_use_count[ret.liftoff_code()] = 0;
303 used_registers.clear(ret);
304 return ret;
305 }
306
SetCacheRegisterv8::internal::wasm::LiftoffAssembler::CacheState307 void SetCacheRegister(Register* cache, Register reg) {
308 DCHECK_EQ(no_reg, *cache);
309 *cache = reg;
310 int liftoff_code = LiftoffRegister{reg}.liftoff_code();
311 DCHECK_EQ(0, register_use_count[liftoff_code]);
312 register_use_count[liftoff_code] = 1;
313 used_registers.set(reg);
314 }
315
SetInstanceCacheRegisterv8::internal::wasm::LiftoffAssembler::CacheState316 void SetInstanceCacheRegister(Register reg) {
317 SetCacheRegister(&cached_instance, reg);
318 }
319
SetMemStartCacheRegisterv8::internal::wasm::LiftoffAssembler::CacheState320 void SetMemStartCacheRegister(Register reg) {
321 SetCacheRegister(&cached_mem_start, reg);
322 }
323
TrySetCachedInstanceRegisterv8::internal::wasm::LiftoffAssembler::CacheState324 Register TrySetCachedInstanceRegister(LiftoffRegList pinned) {
325 DCHECK_EQ(no_reg, cached_instance);
326 LiftoffRegList available_regs =
327 kGpCacheRegList.MaskOut(pinned).MaskOut(used_registers);
328 if (available_regs.is_empty()) return no_reg;
329 // Prefer the {kWasmInstanceRegister}, because that's where the instance
330 // initially is, and where it needs to be for calls.
331 Register new_cache_reg = available_regs.has(kWasmInstanceRegister)
332 ? kWasmInstanceRegister
333 : available_regs.GetFirstRegSet().gp();
334 SetInstanceCacheRegister(new_cache_reg);
335 DCHECK_EQ(new_cache_reg, cached_instance);
336 return new_cache_reg;
337 }
338
ClearCacheRegisterv8::internal::wasm::LiftoffAssembler::CacheState339 void ClearCacheRegister(Register* cache) {
340 DCHECK(cache == &cached_instance || cache == &cached_mem_start);
341 if (*cache == no_reg) return;
342 int liftoff_code = LiftoffRegister{*cache}.liftoff_code();
343 DCHECK_EQ(1, register_use_count[liftoff_code]);
344 register_use_count[liftoff_code] = 0;
345 used_registers.clear(*cache);
346 *cache = no_reg;
347 }
348
ClearCachedInstanceRegisterv8::internal::wasm::LiftoffAssembler::CacheState349 void ClearCachedInstanceRegister() { ClearCacheRegister(&cached_instance); }
350
ClearCachedMemStartRegisterv8::internal::wasm::LiftoffAssembler::CacheState351 void ClearCachedMemStartRegister() {
352 ClearCacheRegister(&cached_mem_start);
353 }
354
ClearAllCacheRegistersv8::internal::wasm::LiftoffAssembler::CacheState355 void ClearAllCacheRegisters() {
356 ClearCacheRegister(&cached_instance);
357 ClearCacheRegister(&cached_mem_start);
358 }
359
inc_usedv8::internal::wasm::LiftoffAssembler::CacheState360 void inc_used(LiftoffRegister reg) {
361 if (reg.is_pair()) {
362 inc_used(reg.low());
363 inc_used(reg.high());
364 return;
365 }
366 used_registers.set(reg);
367 DCHECK_GT(kMaxInt, register_use_count[reg.liftoff_code()]);
368 ++register_use_count[reg.liftoff_code()];
369 }
370
371 // Returns whether this was the last use.
dec_usedv8::internal::wasm::LiftoffAssembler::CacheState372 void dec_used(LiftoffRegister reg) {
373 DCHECK(is_used(reg));
374 if (reg.is_pair()) {
375 dec_used(reg.low());
376 dec_used(reg.high());
377 return;
378 }
379 int code = reg.liftoff_code();
380 DCHECK_LT(0, register_use_count[code]);
381 if (--register_use_count[code] == 0) used_registers.clear(reg);
382 }
383
is_usedv8::internal::wasm::LiftoffAssembler::CacheState384 bool is_used(LiftoffRegister reg) const {
385 if (reg.is_pair()) return is_used(reg.low()) || is_used(reg.high());
386 bool used = used_registers.has(reg);
387 DCHECK_EQ(used, register_use_count[reg.liftoff_code()] != 0);
388 return used;
389 }
390
get_use_countv8::internal::wasm::LiftoffAssembler::CacheState391 uint32_t get_use_count(LiftoffRegister reg) const {
392 if (reg.is_pair()) {
393 DCHECK_EQ(register_use_count[reg.low().liftoff_code()],
394 register_use_count[reg.high().liftoff_code()]);
395 reg = reg.low();
396 }
397 DCHECK_GT(arraysize(register_use_count), reg.liftoff_code());
398 return register_use_count[reg.liftoff_code()];
399 }
400
clear_usedv8::internal::wasm::LiftoffAssembler::CacheState401 void clear_used(LiftoffRegister reg) {
402 if (reg.is_pair()) {
403 clear_used(reg.low());
404 clear_used(reg.high());
405 return;
406 }
407 register_use_count[reg.liftoff_code()] = 0;
408 used_registers.clear(reg);
409 }
410
is_freev8::internal::wasm::LiftoffAssembler::CacheState411 bool is_free(LiftoffRegister reg) const { return !is_used(reg); }
412
reset_used_registersv8::internal::wasm::LiftoffAssembler::CacheState413 void reset_used_registers() {
414 used_registers = {};
415 memset(register_use_count, 0, sizeof(register_use_count));
416 }
417
GetNextSpillRegv8::internal::wasm::LiftoffAssembler::CacheState418 LiftoffRegister GetNextSpillReg(LiftoffRegList candidates) {
419 DCHECK(!candidates.is_empty());
420 // This method should only be called if none of the candidates is free.
421 DCHECK(candidates.MaskOut(used_registers).is_empty());
422 LiftoffRegList unspilled = candidates.MaskOut(last_spilled_regs);
423 if (unspilled.is_empty()) {
424 unspilled = candidates;
425 last_spilled_regs = {};
426 }
427 LiftoffRegister reg = unspilled.GetFirstRegSet();
428 return reg;
429 }
430
431 // TODO(clemensb): Don't copy the full parent state (this makes us N^2).
432 void InitMerge(const CacheState& source, uint32_t num_locals,
433 uint32_t arity, uint32_t stack_depth);
434
435 void Steal(const CacheState& source);
436
437 void Split(const CacheState& source);
438
stack_heightv8::internal::wasm::LiftoffAssembler::CacheState439 uint32_t stack_height() const {
440 return static_cast<uint32_t>(stack_state.size());
441 }
442
443 private:
444 // Make the copy assignment operator private (to be used from {Split()}).
445 CacheState& operator=(const CacheState&) V8_NOEXCEPT = default;
446 };
447
448 explicit LiftoffAssembler(std::unique_ptr<AssemblerBuffer>);
449 ~LiftoffAssembler() override;
450
451 LiftoffRegister LoadToRegister(VarState slot, LiftoffRegList pinned);
452
PopToRegister(LiftoffRegList pinned = {})453 LiftoffRegister PopToRegister(LiftoffRegList pinned = {}) {
454 DCHECK(!cache_state_.stack_state.empty());
455 VarState slot = cache_state_.stack_state.back();
456 cache_state_.stack_state.pop_back();
457 if (slot.is_reg()) {
458 cache_state_.dec_used(slot.reg());
459 return slot.reg();
460 }
461 return LoadToRegister(slot, pinned);
462 }
463
464 // Use this to pop a value into a register that has no other uses, so it
465 // can be modified.
PopToModifiableRegister(LiftoffRegList pinned = {})466 LiftoffRegister PopToModifiableRegister(LiftoffRegList pinned = {}) {
467 ValueKind kind = cache_state_.stack_state.back().kind();
468 LiftoffRegister reg = PopToRegister(pinned);
469 if (cache_state()->is_free(reg)) return reg;
470
471 pinned.set(reg);
472 LiftoffRegister new_reg = GetUnusedRegister(reg.reg_class(), pinned);
473 Move(new_reg, reg, kind);
474 return new_reg;
475 }
476
477 // Returns the register which holds the value of stack slot {index}. If the
478 // value is not stored in a register yet, a register is allocated for it. The
479 // register is then assigned to the stack slot. The value stack height is not
480 // modified. The top of the stack is index 0, i.e. {PopToRegister()} and
481 // {PeekToRegister(0)} should result in the same register.
482 // When the value is finally popped, the use counter of its register has to be
483 // decremented. This can be done by popping the value with {DropValues}.
484 LiftoffRegister PeekToRegister(int index, LiftoffRegList pinned);
485
486 void DropValues(int count);
487
488 // Careful: this indexes "from the other end", i.e. depth=0 is the value
489 // at the bottom of the stack!
490 void DropValue(int depth);
491
492 // Ensure that the loop inputs are either in a register or spilled to the
493 // stack, so that we can merge different values on the back-edge.
494 void PrepareLoopArgs(int num);
495
NextSpillOffset(ValueKind kind, int top_spill_offset)496 V8_INLINE static int NextSpillOffset(ValueKind kind, int top_spill_offset) {
497 int offset = top_spill_offset + SlotSizeForType(kind);
498 if (NeedsAlignment(kind)) {
499 offset = RoundUp(offset, SlotSizeForType(kind));
500 }
501 return offset;
502 }
503
NextSpillOffset(ValueKind kind)504 int NextSpillOffset(ValueKind kind) {
505 return NextSpillOffset(kind, TopSpillOffset());
506 }
507
TopSpillOffset() const508 int TopSpillOffset() const {
509 return cache_state_.stack_state.empty()
510 ? StaticStackFrameSize()
511 : cache_state_.stack_state.back().offset();
512 }
513
PushRegister(ValueKind kind, LiftoffRegister reg)514 void PushRegister(ValueKind kind, LiftoffRegister reg) {
515 DCHECK_EQ(reg_class_for(kind), reg.reg_class());
516 cache_state_.inc_used(reg);
517 cache_state_.stack_state.emplace_back(kind, reg, NextSpillOffset(kind));
518 }
519
520 // Assumes that the exception is in {kReturnRegister0}. This is where the
521 // exception is stored by the unwinder after a throwing call.
PushException()522 void PushException() {
523 LiftoffRegister reg{kReturnRegister0};
524 // This is used after a call, so {kReturnRegister0} is not used yet.
525 DCHECK(cache_state_.is_free(reg));
526 cache_state_.inc_used(reg);
527 cache_state_.stack_state.emplace_back(kRef, reg, NextSpillOffset(kRef));
528 }
529
PushConstant(ValueKind kind, int32_t i32_const)530 void PushConstant(ValueKind kind, int32_t i32_const) {
531 DCHECK(kind == kI32 || kind == kI64);
532 cache_state_.stack_state.emplace_back(kind, i32_const,
533 NextSpillOffset(kind));
534 }
535
PushStack(ValueKind kind)536 void PushStack(ValueKind kind) {
537 cache_state_.stack_state.emplace_back(kind, NextSpillOffset(kind));
538 }
539
540 void SpillRegister(LiftoffRegister);
541
GetNumUses(LiftoffRegister reg) const542 uint32_t GetNumUses(LiftoffRegister reg) const {
543 return cache_state_.get_use_count(reg);
544 }
545
546 // Get an unused register for class {rc}, reusing one of {try_first} if
547 // possible.
GetUnusedRegister( RegClass rc, std::initializer_list<LiftoffRegister> try_first, LiftoffRegList pinned)548 LiftoffRegister GetUnusedRegister(
549 RegClass rc, std::initializer_list<LiftoffRegister> try_first,
550 LiftoffRegList pinned) {
551 for (LiftoffRegister reg : try_first) {
552 DCHECK_EQ(reg.reg_class(), rc);
553 if (cache_state_.is_free(reg)) return reg;
554 }
555 return GetUnusedRegister(rc, pinned);
556 }
557
558 // Get an unused register for class {rc}, potentially spilling to free one.
GetUnusedRegister(RegClass rc, LiftoffRegList pinned)559 LiftoffRegister GetUnusedRegister(RegClass rc, LiftoffRegList pinned) {
560 if (kNeedI64RegPair && rc == kGpRegPair) {
561 LiftoffRegList candidates = kGpCacheRegList.MaskOut(pinned);
562 Register low = candidates.clear(GetUnusedRegister(candidates)).gp();
563 Register high = GetUnusedRegister(candidates).gp();
564 return LiftoffRegister::ForPair(low, high);
565 } else if (kNeedS128RegPair && rc == kFpRegPair) {
566 // kFpRegPair specific logic here because we need adjacent registers, not
567 // just any two registers (like kGpRegPair).
568 if (cache_state_.has_unused_register(rc, pinned)) {
569 return cache_state_.unused_register(rc, pinned);
570 }
571 DoubleRegister low_fp = SpillAdjacentFpRegisters(pinned).fp();
572 return LiftoffRegister::ForFpPair(low_fp);
573 }
574 DCHECK(rc == kGpReg || rc == kFpReg);
575 LiftoffRegList candidates = GetCacheRegList(rc).MaskOut(pinned);
576 return GetUnusedRegister(candidates);
577 }
578
579 // Get an unused register of {candidates}, potentially spilling to free one.
GetUnusedRegister(LiftoffRegList candidates)580 LiftoffRegister GetUnusedRegister(LiftoffRegList candidates) {
581 DCHECK(!candidates.is_empty());
582 if (cache_state_.has_unused_register(candidates)) {
583 return cache_state_.unused_register(candidates);
584 }
585 if (cache_state_.has_volatile_register(candidates)) {
586 return cache_state_.take_volatile_register(candidates);
587 }
588 return SpillOneRegister(candidates);
589 }
590
591 void MaterializeMergedConstants(uint32_t arity);
592
593 enum JumpDirection { kForwardJump, kBackwardJump };
594 void MergeFullStackWith(CacheState& target, const CacheState& source);
595 void MergeStackWith(CacheState& target, uint32_t arity, JumpDirection);
596
597 void Spill(VarState* slot);
598 void SpillLocals();
599 void SpillAllRegisters();
600
601 // Clear any uses of {reg} in both the cache and in {possible_uses}.
602 // Any use in the stack is spilled. If any register in {possible_uses} matches
603 // {reg}, then the content of {reg} is moved to a new temporary register, and
604 // all matches in {possible_uses} are rewritten to that temporary register.
605 void ClearRegister(Register reg,
606 std::initializer_list<Register*> possible_uses,
607 LiftoffRegList pinned);
608
609 // Spills all passed registers.
610 template <typename... Regs>
SpillRegisters(Regs.... regs)611 void SpillRegisters(Regs... regs) {
612 for (LiftoffRegister r : {LiftoffRegister(regs)...}) {
613 if (cache_state_.is_free(r)) continue;
614 if (r.is_gp() && cache_state_.cached_instance == r.gp()) {
615 cache_state_.ClearCachedInstanceRegister();
616 } else if (r.is_gp() && cache_state_.cached_mem_start == r.gp()) {
617 cache_state_.ClearCachedMemStartRegister();
618 } else {
619 SpillRegister(r);
620 }
621 }
622 }
623
624 // Call this method whenever spilling something, such that the number of used
625 // spill slot can be tracked and the stack frame will be allocated big enough.
RecordUsedSpillOffset(int offset)626 void RecordUsedSpillOffset(int offset) {
627 if (offset >= max_used_spill_offset_) max_used_spill_offset_ = offset;
628 }
629
RecordOolSpillSpaceSize(int size)630 void RecordOolSpillSpaceSize(int size) {
631 if (size > ool_spill_space_size_) ool_spill_space_size_ = size;
632 }
633
634 // Load parameters into the right registers / stack slots for the call.
635 void PrepareBuiltinCall(const ValueKindSig* sig,
636 compiler::CallDescriptor* call_descriptor,
637 std::initializer_list<VarState> params);
638
639 // Load parameters into the right registers / stack slots for the call.
640 // Move {*target} into another register if needed and update {*target} to that
641 // register, or {no_reg} if target was spilled to the stack.
642 void PrepareCall(const ValueKindSig*, compiler::CallDescriptor*,
643 Register* target = nullptr,
644 Register* target_instance = nullptr);
645 // Process return values of the call.
646 void FinishCall(const ValueKindSig*, compiler::CallDescriptor*);
647
648 // Move {src} into {dst}. {src} and {dst} must be different.
649 void Move(LiftoffRegister dst, LiftoffRegister src, ValueKind);
650
651 // Parallel register move: For a list of tuples <dst, src, kind>, move the
652 // {src} register of kind {kind} into {dst}. If {src} equals {dst}, ignore
653 // that tuple.
654 struct ParallelRegisterMoveTuple {
655 LiftoffRegister dst;
656 LiftoffRegister src;
657 ValueKind kind;
658 template <typename Dst, typename Src>
ParallelRegisterMoveTuplev8::internal::wasm::LiftoffAssembler::ParallelRegisterMoveTuple659 ParallelRegisterMoveTuple(Dst dst, Src src, ValueKind kind)
660 : dst(dst), src(src), kind(kind) {}
661 };
662
663 void ParallelRegisterMove(base::Vector<const ParallelRegisterMoveTuple>);
664
ParallelRegisterMove( std::initializer_list<ParallelRegisterMoveTuple> moves)665 void ParallelRegisterMove(
666 std::initializer_list<ParallelRegisterMoveTuple> moves) {
667 ParallelRegisterMove(base::VectorOf(moves));
668 }
669
670 void MoveToReturnLocations(const FunctionSig*,
671 compiler::CallDescriptor* descriptor);
672
673 #ifdef ENABLE_SLOW_DCHECKS
674 // Validate that the register use counts reflect the state of the cache.
675 bool ValidateCacheState() const;
676 #endif
677
678 ////////////////////////////////////
679 // Platform-specific part. //
680 ////////////////////////////////////
681
682 // This function emits machine code to prepare the stack frame, before the
683 // size of the stack frame is known. It returns an offset in the machine code
684 // which can later be patched (via {PatchPrepareStackFrame)} when the size of
685 // the frame is known.
686 inline int PrepareStackFrame();
687 inline void PrepareTailCall(int num_callee_stack_params,
688 int stack_param_delta);
689 inline void AlignFrameSize();
690 inline void PatchPrepareStackFrame(int offset, SafepointTableBuilder*);
691 inline void FinishCode();
692 inline void AbortCompilation();
693 inline static constexpr int StaticStackFrameSize();
694 inline static int SlotSizeForType(ValueKind kind);
695 inline static bool NeedsAlignment(ValueKind kind);
696
697 inline void LoadConstant(LiftoffRegister, WasmValue,
698 RelocInfo::Mode rmode = RelocInfo::NO_INFO);
699 inline void LoadInstanceFromFrame(Register dst);
700 inline void LoadFromInstance(Register dst, Register instance, int offset,
701 int size);
702 inline void LoadTaggedPointerFromInstance(Register dst, Register instance,
703 int offset);
704 inline void LoadExternalPointer(Register dst, Register instance, int offset,
705 ExternalPointerTag tag,
706 Register isolate_root);
707 inline void SpillInstance(Register instance);
708 inline void ResetOSRTarget();
709 inline void LoadTaggedPointer(Register dst, Register src_addr,
710 Register offset_reg, int32_t offset_imm,
711 LiftoffRegList pinned);
712 inline void LoadFullPointer(Register dst, Register src_addr,
713 int32_t offset_imm);
714 enum SkipWriteBarrier : bool {
715 kSkipWriteBarrier = true,
716 kNoSkipWriteBarrier = false
717 };
718 inline void StoreTaggedPointer(Register dst_addr, Register offset_reg,
719 int32_t offset_imm, LiftoffRegister src,
720 LiftoffRegList pinned,
721 SkipWriteBarrier = kNoSkipWriteBarrier);
LoadFixedArrayLengthAsInt32(LiftoffRegister dst, Register array, LiftoffRegList pinned)722 void LoadFixedArrayLengthAsInt32(LiftoffRegister dst, Register array,
723 LiftoffRegList pinned) {
724 int offset = FixedArray::kLengthOffset - kHeapObjectTag;
725 LoadSmiAsInt32(dst, array, offset, pinned);
726 }
LoadSmiAsInt32(LiftoffRegister dst, Register src_addr, int32_t offset, LiftoffRegList pinned)727 void LoadSmiAsInt32(LiftoffRegister dst, Register src_addr, int32_t offset,
728 LiftoffRegList pinned) {
729 if (SmiValuesAre32Bits()) {
730 #if V8_TARGET_LITTLE_ENDIAN
731 DCHECK_EQ(kSmiShiftSize + kSmiTagSize, 4 * kBitsPerByte);
732 offset += 4;
733 #endif
734 Load(dst, src_addr, no_reg, offset, LoadType::kI32Load, pinned);
735 } else {
736 DCHECK(SmiValuesAre31Bits());
737 Load(dst, src_addr, no_reg, offset, LoadType::kI32Load, pinned);
738 emit_i32_sari(dst.gp(), dst.gp(), kSmiTagSize);
739 }
740 }
741 inline void IncrementSmi(LiftoffRegister dst, int offset);
742 inline void Load(LiftoffRegister dst, Register src_addr, Register offset_reg,
743 uintptr_t offset_imm, LoadType type, LiftoffRegList pinned,
744 uint32_t* protected_load_pc = nullptr,
745 bool is_load_mem = false, bool i64_offset = false);
746 inline void Store(Register dst_addr, Register offset_reg,
747 uintptr_t offset_imm, LiftoffRegister src, StoreType type,
748 LiftoffRegList pinned,
749 uint32_t* protected_store_pc = nullptr,
750 bool is_store_mem = false);
751 inline void AtomicLoad(LiftoffRegister dst, Register src_addr,
752 Register offset_reg, uintptr_t offset_imm,
753 LoadType type, LiftoffRegList pinned);
754 inline void AtomicStore(Register dst_addr, Register offset_reg,
755 uintptr_t offset_imm, LiftoffRegister src,
756 StoreType type, LiftoffRegList pinned);
757
758 inline void AtomicAdd(Register dst_addr, Register offset_reg,
759 uintptr_t offset_imm, LiftoffRegister value,
760 LiftoffRegister result, StoreType type);
761
762 inline void AtomicSub(Register dst_addr, Register offset_reg,
763 uintptr_t offset_imm, LiftoffRegister value,
764 LiftoffRegister result, StoreType type);
765
766 inline void AtomicAnd(Register dst_addr, Register offset_reg,
767 uintptr_t offset_imm, LiftoffRegister value,
768 LiftoffRegister result, StoreType type);
769
770 inline void AtomicOr(Register dst_addr, Register offset_reg,
771 uintptr_t offset_imm, LiftoffRegister value,
772 LiftoffRegister result, StoreType type);
773
774 inline void AtomicXor(Register dst_addr, Register offset_reg,
775 uintptr_t offset_imm, LiftoffRegister value,
776 LiftoffRegister result, StoreType type);
777
778 inline void AtomicExchange(Register dst_addr, Register offset_reg,
779 uintptr_t offset_imm, LiftoffRegister value,
780 LiftoffRegister result, StoreType type);
781
782 inline void AtomicCompareExchange(Register dst_addr, Register offset_reg,
783 uintptr_t offset_imm,
784 LiftoffRegister expected,
785 LiftoffRegister new_value,
786 LiftoffRegister value, StoreType type);
787
788 inline void AtomicFence();
789
790 inline void LoadCallerFrameSlot(LiftoffRegister, uint32_t caller_slot_idx,
791 ValueKind);
792 inline void StoreCallerFrameSlot(LiftoffRegister, uint32_t caller_slot_idx,
793 ValueKind);
794 inline void LoadReturnStackSlot(LiftoffRegister, int offset, ValueKind);
795 inline void MoveStackValue(uint32_t dst_offset, uint32_t src_offset,
796 ValueKind);
797
798 inline void Move(Register dst, Register src, ValueKind);
799 inline void Move(DoubleRegister dst, DoubleRegister src, ValueKind);
800
801 inline void Spill(int offset, LiftoffRegister, ValueKind);
802 inline void Spill(int offset, WasmValue);
803 inline void Fill(LiftoffRegister, int offset, ValueKind);
804 // Only used on 32-bit systems: Fill a register from a "half stack slot", i.e.
805 // 4 bytes on the stack holding half of a 64-bit value.
806 inline void FillI64Half(Register, int offset, RegPairHalf);
807 inline void FillStackSlotsWithZero(int start, int size);
808
809 // i32 binops.
810 inline void emit_i32_add(Register dst, Register lhs, Register rhs);
811 inline void emit_i32_addi(Register dst, Register lhs, int32_t imm);
812 inline void emit_i32_sub(Register dst, Register lhs, Register rhs);
813 inline void emit_i32_subi(Register dst, Register lhs, int32_t imm);
814 inline void emit_i32_mul(Register dst, Register lhs, Register rhs);
815 inline void emit_i32_divs(Register dst, Register lhs, Register rhs,
816 Label* trap_div_by_zero,
817 Label* trap_div_unrepresentable);
818 inline void emit_i32_divu(Register dst, Register lhs, Register rhs,
819 Label* trap_div_by_zero);
820 inline void emit_i32_rems(Register dst, Register lhs, Register rhs,
821 Label* trap_rem_by_zero);
822 inline void emit_i32_remu(Register dst, Register lhs, Register rhs,
823 Label* trap_rem_by_zero);
824 inline void emit_i32_and(Register dst, Register lhs, Register rhs);
825 inline void emit_i32_andi(Register dst, Register lhs, int32_t imm);
826 inline void emit_i32_or(Register dst, Register lhs, Register rhs);
827 inline void emit_i32_ori(Register dst, Register lhs, int32_t imm);
828 inline void emit_i32_xor(Register dst, Register lhs, Register rhs);
829 inline void emit_i32_xori(Register dst, Register lhs, int32_t imm);
830 inline void emit_i32_shl(Register dst, Register src, Register amount);
831 inline void emit_i32_shli(Register dst, Register src, int32_t amount);
832 inline void emit_i32_sar(Register dst, Register src, Register amount);
833 inline void emit_i32_sari(Register dst, Register src, int32_t amount);
834 inline void emit_i32_shr(Register dst, Register src, Register amount);
835 inline void emit_i32_shri(Register dst, Register src, int32_t amount);
836
837 // i32 unops.
838 inline void emit_i32_clz(Register dst, Register src);
839 inline void emit_i32_ctz(Register dst, Register src);
840 inline bool emit_i32_popcnt(Register dst, Register src);
841
842 // i64 binops.
843 inline void emit_i64_add(LiftoffRegister dst, LiftoffRegister lhs,
844 LiftoffRegister rhs);
845 inline void emit_i64_addi(LiftoffRegister dst, LiftoffRegister lhs,
846 int64_t imm);
847 inline void emit_i64_sub(LiftoffRegister dst, LiftoffRegister lhs,
848 LiftoffRegister rhs);
849 inline void emit_i64_mul(LiftoffRegister dst, LiftoffRegister lhs,
850 LiftoffRegister rhs);
851 inline bool emit_i64_divs(LiftoffRegister dst, LiftoffRegister lhs,
852 LiftoffRegister rhs, Label* trap_div_by_zero,
853 Label* trap_div_unrepresentable);
854 inline bool emit_i64_divu(LiftoffRegister dst, LiftoffRegister lhs,
855 LiftoffRegister rhs, Label* trap_div_by_zero);
856 inline bool emit_i64_rems(LiftoffRegister dst, LiftoffRegister lhs,
857 LiftoffRegister rhs, Label* trap_rem_by_zero);
858 inline bool emit_i64_remu(LiftoffRegister dst, LiftoffRegister lhs,
859 LiftoffRegister rhs, Label* trap_rem_by_zero);
860 inline void emit_i64_and(LiftoffRegister dst, LiftoffRegister lhs,
861 LiftoffRegister rhs);
862 inline void emit_i64_andi(LiftoffRegister dst, LiftoffRegister lhs,
863 int32_t imm);
864 inline void emit_i64_or(LiftoffRegister dst, LiftoffRegister lhs,
865 LiftoffRegister rhs);
866 inline void emit_i64_ori(LiftoffRegister dst, LiftoffRegister lhs,
867 int32_t imm);
868 inline void emit_i64_xor(LiftoffRegister dst, LiftoffRegister lhs,
869 LiftoffRegister rhs);
870 inline void emit_i64_xori(LiftoffRegister dst, LiftoffRegister lhs,
871 int32_t imm);
872 inline void emit_i64_shl(LiftoffRegister dst, LiftoffRegister src,
873 Register amount);
874 inline void emit_i64_shli(LiftoffRegister dst, LiftoffRegister src,
875 int32_t amount);
876 inline void emit_i64_sar(LiftoffRegister dst, LiftoffRegister src,
877 Register amount);
878 inline void emit_i64_sari(LiftoffRegister dst, LiftoffRegister src,
879 int32_t amount);
880 inline void emit_i64_shr(LiftoffRegister dst, LiftoffRegister src,
881 Register amount);
882 inline void emit_i64_shri(LiftoffRegister dst, LiftoffRegister src,
883 int32_t amount);
884
885 // i64 unops.
886 inline void emit_i64_clz(LiftoffRegister dst, LiftoffRegister src);
887 inline void emit_i64_ctz(LiftoffRegister dst, LiftoffRegister src);
888 inline bool emit_i64_popcnt(LiftoffRegister dst, LiftoffRegister src);
889
890 inline void emit_u32_to_uintptr(Register dst, Register src);
891
emit_ptrsize_add(Register dst, Register lhs, Register rhs)892 void emit_ptrsize_add(Register dst, Register lhs, Register rhs) {
893 if (kSystemPointerSize == 8) {
894 emit_i64_add(LiftoffRegister(dst), LiftoffRegister(lhs),
895 LiftoffRegister(rhs));
896 } else {
897 emit_i32_add(dst, lhs, rhs);
898 }
899 }
emit_ptrsize_sub(Register dst, Register lhs, Register rhs)900 void emit_ptrsize_sub(Register dst, Register lhs, Register rhs) {
901 if (kSystemPointerSize == 8) {
902 emit_i64_sub(LiftoffRegister(dst), LiftoffRegister(lhs),
903 LiftoffRegister(rhs));
904 } else {
905 emit_i32_sub(dst, lhs, rhs);
906 }
907 }
emit_ptrsize_and(Register dst, Register lhs, Register rhs)908 void emit_ptrsize_and(Register dst, Register lhs, Register rhs) {
909 if (kSystemPointerSize == 8) {
910 emit_i64_and(LiftoffRegister(dst), LiftoffRegister(lhs),
911 LiftoffRegister(rhs));
912 } else {
913 emit_i32_and(dst, lhs, rhs);
914 }
915 }
emit_ptrsize_shri(Register dst, Register src, int amount)916 void emit_ptrsize_shri(Register dst, Register src, int amount) {
917 if (kSystemPointerSize == 8) {
918 emit_i64_shri(LiftoffRegister(dst), LiftoffRegister(src), amount);
919 } else {
920 emit_i32_shri(dst, src, amount);
921 }
922 }
923
emit_ptrsize_addi(Register dst, Register lhs, intptr_t imm)924 void emit_ptrsize_addi(Register dst, Register lhs, intptr_t imm) {
925 if (kSystemPointerSize == 8) {
926 emit_i64_addi(LiftoffRegister(dst), LiftoffRegister(lhs), imm);
927 } else {
928 emit_i32_addi(dst, lhs, static_cast<int32_t>(imm));
929 }
930 }
931
emit_ptrsize_set_cond(LiftoffCondition condition, Register dst, LiftoffRegister lhs, LiftoffRegister rhs)932 void emit_ptrsize_set_cond(LiftoffCondition condition, Register dst,
933 LiftoffRegister lhs, LiftoffRegister rhs) {
934 if (kSystemPointerSize == 8) {
935 emit_i64_set_cond(condition, dst, lhs, rhs);
936 } else {
937 emit_i32_set_cond(condition, dst, lhs.gp(), rhs.gp());
938 }
939 }
940
emit_ptrsize_zeroextend_i32(Register dst, Register src)941 void emit_ptrsize_zeroextend_i32(Register dst, Register src) {
942 if (kSystemPointerSize == 8) {
943 emit_type_conversion(kExprI64UConvertI32, LiftoffRegister(dst),
944 LiftoffRegister(src));
945 } else if (dst != src) {
946 Move(dst, src, kI32);
947 }
948 }
949
950 // f32 binops.
951 inline void emit_f32_add(DoubleRegister dst, DoubleRegister lhs,
952 DoubleRegister rhs);
953 inline void emit_f32_sub(DoubleRegister dst, DoubleRegister lhs,
954 DoubleRegister rhs);
955 inline void emit_f32_mul(DoubleRegister dst, DoubleRegister lhs,
956 DoubleRegister rhs);
957 inline void emit_f32_div(DoubleRegister dst, DoubleRegister lhs,
958 DoubleRegister rhs);
959 inline void emit_f32_min(DoubleRegister dst, DoubleRegister lhs,
960 DoubleRegister rhs);
961 inline void emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
962 DoubleRegister rhs);
963 inline void emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs,
964 DoubleRegister rhs);
965
966 // f32 unops.
967 inline void emit_f32_abs(DoubleRegister dst, DoubleRegister src);
968 inline void emit_f32_neg(DoubleRegister dst, DoubleRegister src);
969 inline bool emit_f32_ceil(DoubleRegister dst, DoubleRegister src);
970 inline bool emit_f32_floor(DoubleRegister dst, DoubleRegister src);
971 inline bool emit_f32_trunc(DoubleRegister dst, DoubleRegister src);
972 inline bool emit_f32_nearest_int(DoubleRegister dst, DoubleRegister src);
973 inline void emit_f32_sqrt(DoubleRegister dst, DoubleRegister src);
974
975 // f64 binops.
976 inline void emit_f64_add(DoubleRegister dst, DoubleRegister lhs,
977 DoubleRegister rhs);
978 inline void emit_f64_sub(DoubleRegister dst, DoubleRegister lhs,
979 DoubleRegister rhs);
980 inline void emit_f64_mul(DoubleRegister dst, DoubleRegister lhs,
981 DoubleRegister rhs);
982 inline void emit_f64_div(DoubleRegister dst, DoubleRegister lhs,
983 DoubleRegister rhs);
984 inline void emit_f64_min(DoubleRegister dst, DoubleRegister lhs,
985 DoubleRegister rhs);
986 inline void emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
987 DoubleRegister rhs);
988 inline void emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs,
989 DoubleRegister rhs);
990
991 // f64 unops.
992 inline void emit_f64_abs(DoubleRegister dst, DoubleRegister src);
993 inline void emit_f64_neg(DoubleRegister dst, DoubleRegister src);
994 inline bool emit_f64_ceil(DoubleRegister dst, DoubleRegister src);
995 inline bool emit_f64_floor(DoubleRegister dst, DoubleRegister src);
996 inline bool emit_f64_trunc(DoubleRegister dst, DoubleRegister src);
997 inline bool emit_f64_nearest_int(DoubleRegister dst, DoubleRegister src);
998 inline void emit_f64_sqrt(DoubleRegister dst, DoubleRegister src);
999
1000 inline bool emit_type_conversion(WasmOpcode opcode, LiftoffRegister dst,
1001 LiftoffRegister src, Label* trap = nullptr);
1002
1003 inline void emit_i32_signextend_i8(Register dst, Register src);
1004 inline void emit_i32_signextend_i16(Register dst, Register src);
1005 inline void emit_i64_signextend_i8(LiftoffRegister dst, LiftoffRegister src);
1006 inline void emit_i64_signextend_i16(LiftoffRegister dst, LiftoffRegister src);
1007 inline void emit_i64_signextend_i32(LiftoffRegister dst, LiftoffRegister src);
1008
1009 inline void emit_jump(Label*);
1010 inline void emit_jump(Register);
1011
1012 inline void emit_cond_jump(LiftoffCondition, Label*, ValueKind value,
1013 Register lhs, Register rhs = no_reg);
1014 inline void emit_i32_cond_jumpi(LiftoffCondition, Label*, Register lhs,
1015 int imm);
1016 inline void emit_i32_subi_jump_negative(Register value, int subtrahend,
1017 Label* result_negative);
1018 // Set {dst} to 1 if condition holds, 0 otherwise.
1019 inline void emit_i32_eqz(Register dst, Register src);
1020 inline void emit_i32_set_cond(LiftoffCondition, Register dst, Register lhs,
1021 Register rhs);
1022 inline void emit_i64_eqz(Register dst, LiftoffRegister src);
1023 inline void emit_i64_set_cond(LiftoffCondition condition, Register dst,
1024 LiftoffRegister lhs, LiftoffRegister rhs);
1025 inline void emit_f32_set_cond(LiftoffCondition condition, Register dst,
1026 DoubleRegister lhs, DoubleRegister rhs);
1027 inline void emit_f64_set_cond(LiftoffCondition condition, Register dst,
1028 DoubleRegister lhs, DoubleRegister rhs);
1029
1030 // Optional select support: Returns false if generic code (via branches)
1031 // should be emitted instead.
1032 inline bool emit_select(LiftoffRegister dst, Register condition,
1033 LiftoffRegister true_value,
1034 LiftoffRegister false_value, ValueKind kind);
1035
1036 enum SmiCheckMode { kJumpOnSmi, kJumpOnNotSmi };
1037 inline void emit_smi_check(Register obj, Label* target, SmiCheckMode mode);
1038
1039 inline void LoadTransform(LiftoffRegister dst, Register src_addr,
1040 Register offset_reg, uintptr_t offset_imm,
1041 LoadType type, LoadTransformationKind transform,
1042 uint32_t* protected_load_pc);
1043 inline void LoadLane(LiftoffRegister dst, LiftoffRegister src, Register addr,
1044 Register offset_reg, uintptr_t offset_imm, LoadType type,
1045 uint8_t lane, uint32_t* protected_load_pc);
1046 inline void StoreLane(Register dst, Register offset, uintptr_t offset_imm,
1047 LiftoffRegister src, StoreType type, uint8_t lane,
1048 uint32_t* protected_store_pc);
1049 inline void emit_i8x16_shuffle(LiftoffRegister dst, LiftoffRegister lhs,
1050 LiftoffRegister rhs, const uint8_t shuffle[16],
1051 bool is_swizzle);
1052 inline void emit_i8x16_swizzle(LiftoffRegister dst, LiftoffRegister lhs,
1053 LiftoffRegister rhs);
1054 inline void emit_i8x16_popcnt(LiftoffRegister dst, LiftoffRegister src);
1055 inline void emit_i8x16_splat(LiftoffRegister dst, LiftoffRegister src);
1056 inline void emit_i16x8_splat(LiftoffRegister dst, LiftoffRegister src);
1057 inline void emit_i32x4_splat(LiftoffRegister dst, LiftoffRegister src);
1058 inline void emit_i64x2_splat(LiftoffRegister dst, LiftoffRegister src);
1059 inline void emit_f32x4_splat(LiftoffRegister dst, LiftoffRegister src);
1060 inline void emit_f64x2_splat(LiftoffRegister dst, LiftoffRegister src);
1061 inline void emit_i8x16_eq(LiftoffRegister dst, LiftoffRegister lhs,
1062 LiftoffRegister rhs);
1063 inline void emit_i8x16_ne(LiftoffRegister dst, LiftoffRegister lhs,
1064 LiftoffRegister rhs);
1065 inline void emit_i8x16_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
1066 LiftoffRegister rhs);
1067 inline void emit_i8x16_gt_u(LiftoffRegister dst, LiftoffRegister lhs,
1068 LiftoffRegister rhs);
1069 inline void emit_i8x16_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
1070 LiftoffRegister rhs);
1071 inline void emit_i8x16_ge_u(LiftoffRegister dst, LiftoffRegister lhs,
1072 LiftoffRegister rhs);
1073 inline void emit_i16x8_eq(LiftoffRegister dst, LiftoffRegister lhs,
1074 LiftoffRegister rhs);
1075 inline void emit_i16x8_ne(LiftoffRegister dst, LiftoffRegister lhs,
1076 LiftoffRegister rhs);
1077 inline void emit_i16x8_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
1078 LiftoffRegister rhs);
1079 inline void emit_i16x8_gt_u(LiftoffRegister dst, LiftoffRegister lhs,
1080 LiftoffRegister rhs);
1081 inline void emit_i16x8_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
1082 LiftoffRegister rhs);
1083 inline void emit_i16x8_ge_u(LiftoffRegister dst, LiftoffRegister lhs,
1084 LiftoffRegister rhs);
1085 inline void emit_i32x4_eq(LiftoffRegister dst, LiftoffRegister lhs,
1086 LiftoffRegister rhs);
1087 inline void emit_i32x4_ne(LiftoffRegister dst, LiftoffRegister lhs,
1088 LiftoffRegister rhs);
1089 inline void emit_i32x4_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
1090 LiftoffRegister rhs);
1091 inline void emit_i32x4_gt_u(LiftoffRegister dst, LiftoffRegister lhs,
1092 LiftoffRegister rhs);
1093 inline void emit_i32x4_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
1094 LiftoffRegister rhs);
1095 inline void emit_i32x4_ge_u(LiftoffRegister dst, LiftoffRegister lhs,
1096 LiftoffRegister rhs);
1097 inline void emit_i64x2_eq(LiftoffRegister dst, LiftoffRegister lhs,
1098 LiftoffRegister rhs);
1099 inline void emit_i64x2_ne(LiftoffRegister dst, LiftoffRegister lhs,
1100 LiftoffRegister rhs);
1101 inline void emit_i64x2_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
1102 LiftoffRegister rhs);
1103 inline void emit_i64x2_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
1104 LiftoffRegister rhs);
1105 inline void emit_f32x4_eq(LiftoffRegister dst, LiftoffRegister lhs,
1106 LiftoffRegister rhs);
1107 inline void emit_f32x4_ne(LiftoffRegister dst, LiftoffRegister lhs,
1108 LiftoffRegister rhs);
1109 inline void emit_f32x4_lt(LiftoffRegister dst, LiftoffRegister lhs,
1110 LiftoffRegister rhs);
1111 inline void emit_f32x4_le(LiftoffRegister dst, LiftoffRegister lhs,
1112 LiftoffRegister rhs);
1113 inline void emit_f64x2_eq(LiftoffRegister dst, LiftoffRegister lhs,
1114 LiftoffRegister rhs);
1115 inline void emit_f64x2_ne(LiftoffRegister dst, LiftoffRegister lhs,
1116 LiftoffRegister rhs);
1117 inline void emit_f64x2_lt(LiftoffRegister dst, LiftoffRegister lhs,
1118 LiftoffRegister rhs);
1119 inline void emit_f64x2_le(LiftoffRegister dst, LiftoffRegister lhs,
1120 LiftoffRegister rhs);
1121 inline void emit_s128_const(LiftoffRegister dst, const uint8_t imms[16]);
1122 inline void emit_s128_not(LiftoffRegister dst, LiftoffRegister src);
1123 inline void emit_s128_and(LiftoffRegister dst, LiftoffRegister lhs,
1124 LiftoffRegister rhs);
1125 inline void emit_s128_or(LiftoffRegister dst, LiftoffRegister lhs,
1126 LiftoffRegister rhs);
1127 inline void emit_s128_xor(LiftoffRegister dst, LiftoffRegister lhs,
1128 LiftoffRegister rhs);
1129 inline void emit_s128_select(LiftoffRegister dst, LiftoffRegister src1,
1130 LiftoffRegister src2, LiftoffRegister mask);
1131 inline void emit_i8x16_neg(LiftoffRegister dst, LiftoffRegister src);
1132 inline void emit_v128_anytrue(LiftoffRegister dst, LiftoffRegister src);
1133 inline void emit_i8x16_alltrue(LiftoffRegister dst, LiftoffRegister src);
1134 inline void emit_i8x16_bitmask(LiftoffRegister dst, LiftoffRegister src);
1135 inline void emit_i8x16_shl(LiftoffRegister dst, LiftoffRegister lhs,
1136 LiftoffRegister rhs);
1137 inline void emit_i8x16_shli(LiftoffRegister dst, LiftoffRegister lhs,
1138 int32_t rhs);
1139 inline void emit_i8x16_shr_s(LiftoffRegister dst, LiftoffRegister lhs,
1140 LiftoffRegister rhs);
1141 inline void emit_i8x16_shri_s(LiftoffRegister dst, LiftoffRegister lhs,
1142 int32_t rhs);
1143 inline void emit_i8x16_shr_u(LiftoffRegister dst, LiftoffRegister lhs,
1144 LiftoffRegister rhs);
1145 inline void emit_i8x16_shri_u(LiftoffRegister dst, LiftoffRegister lhs,
1146 int32_t rhs);
1147 inline void emit_i8x16_add(LiftoffRegister dst, LiftoffRegister lhs,
1148 LiftoffRegister rhs);
1149 inline void emit_i8x16_add_sat_s(LiftoffRegister dst, LiftoffRegister lhs,
1150 LiftoffRegister rhs);
1151 inline void emit_i8x16_add_sat_u(LiftoffRegister dst, LiftoffRegister lhs,
1152 LiftoffRegister rhs);
1153 inline void emit_i8x16_sub(LiftoffRegister dst, LiftoffRegister lhs,
1154 LiftoffRegister rhs);
1155 inline void emit_i8x16_sub_sat_s(LiftoffRegister dst, LiftoffRegister lhs,
1156 LiftoffRegister rhs);
1157 inline void emit_i8x16_sub_sat_u(LiftoffRegister dst, LiftoffRegister lhs,
1158 LiftoffRegister rhs);
1159 inline void emit_i8x16_min_s(LiftoffRegister dst, LiftoffRegister lhs,
1160 LiftoffRegister rhs);
1161 inline void emit_i8x16_min_u(LiftoffRegister dst, LiftoffRegister lhs,
1162 LiftoffRegister rhs);
1163 inline void emit_i8x16_max_s(LiftoffRegister dst, LiftoffRegister lhs,
1164 LiftoffRegister rhs);
1165 inline void emit_i8x16_max_u(LiftoffRegister dst, LiftoffRegister lhs,
1166 LiftoffRegister rhs);
1167 inline void emit_i16x8_neg(LiftoffRegister dst, LiftoffRegister src);
1168 inline void emit_i16x8_alltrue(LiftoffRegister dst, LiftoffRegister src);
1169 inline void emit_i16x8_bitmask(LiftoffRegister dst, LiftoffRegister src);
1170 inline void emit_i16x8_shl(LiftoffRegister dst, LiftoffRegister lhs,
1171 LiftoffRegister rhs);
1172 inline void emit_i16x8_shli(LiftoffRegister dst, LiftoffRegister lhs,
1173 int32_t rhs);
1174 inline void emit_i16x8_shr_s(LiftoffRegister dst, LiftoffRegister lhs,
1175 LiftoffRegister rhs);
1176 inline void emit_i16x8_shri_s(LiftoffRegister dst, LiftoffRegister lhs,
1177 int32_t rhs);
1178 inline void emit_i16x8_shr_u(LiftoffRegister dst, LiftoffRegister lhs,
1179 LiftoffRegister rhs);
1180 inline void emit_i16x8_shri_u(LiftoffRegister dst, LiftoffRegister lhs,
1181 int32_t rhs);
1182 inline void emit_i16x8_add(LiftoffRegister dst, LiftoffRegister lhs,
1183 LiftoffRegister rhs);
1184 inline void emit_i16x8_add_sat_s(LiftoffRegister dst, LiftoffRegister lhs,
1185 LiftoffRegister rhs);
1186 inline void emit_i16x8_add_sat_u(LiftoffRegister dst, LiftoffRegister lhs,
1187 LiftoffRegister rhs);
1188 inline void emit_i16x8_sub(LiftoffRegister dst, LiftoffRegister lhs,
1189 LiftoffRegister rhs);
1190 inline void emit_i16x8_sub_sat_s(LiftoffRegister dst, LiftoffRegister lhs,
1191 LiftoffRegister rhs);
1192 inline void emit_i16x8_sub_sat_u(LiftoffRegister dst, LiftoffRegister lhs,
1193 LiftoffRegister rhs);
1194 inline void emit_i16x8_mul(LiftoffRegister dst, LiftoffRegister lhs,
1195 LiftoffRegister rhs);
1196 inline void emit_i16x8_min_s(LiftoffRegister dst, LiftoffRegister lhs,
1197 LiftoffRegister rhs);
1198 inline void emit_i16x8_min_u(LiftoffRegister dst, LiftoffRegister lhs,
1199 LiftoffRegister rhs);
1200 inline void emit_i16x8_max_s(LiftoffRegister dst, LiftoffRegister lhs,
1201 LiftoffRegister rhs);
1202 inline void emit_i16x8_max_u(LiftoffRegister dst, LiftoffRegister lhs,
1203 LiftoffRegister rhs);
1204 inline void emit_i16x8_extadd_pairwise_i8x16_s(LiftoffRegister dst,
1205 LiftoffRegister src);
1206 inline void emit_i16x8_extadd_pairwise_i8x16_u(LiftoffRegister dst,
1207 LiftoffRegister src);
1208 inline void emit_i16x8_extmul_low_i8x16_s(LiftoffRegister dst,
1209 LiftoffRegister src1,
1210 LiftoffRegister src2);
1211 inline void emit_i16x8_extmul_low_i8x16_u(LiftoffRegister dst,
1212 LiftoffRegister src1,
1213 LiftoffRegister src2);
1214 inline void emit_i16x8_extmul_high_i8x16_s(LiftoffRegister dst,
1215 LiftoffRegister src1,
1216 LiftoffRegister src2);
1217 inline void emit_i16x8_extmul_high_i8x16_u(LiftoffRegister dst,
1218 LiftoffRegister src1,
1219 LiftoffRegister src2);
1220 inline void emit_i16x8_q15mulr_sat_s(LiftoffRegister dst,
1221 LiftoffRegister src1,
1222 LiftoffRegister src2);
1223 inline void emit_i32x4_neg(LiftoffRegister dst, LiftoffRegister src);
1224 inline void emit_i32x4_alltrue(LiftoffRegister dst, LiftoffRegister src);
1225 inline void emit_i32x4_bitmask(LiftoffRegister dst, LiftoffRegister src);
1226 inline void emit_i32x4_shl(LiftoffRegister dst, LiftoffRegister lhs,
1227 LiftoffRegister rhs);
1228 inline void emit_i32x4_shli(LiftoffRegister dst, LiftoffRegister lhs,
1229 int32_t rhs);
1230 inline void emit_i32x4_shr_s(LiftoffRegister dst, LiftoffRegister lhs,
1231 LiftoffRegister rhs);
1232 inline void emit_i32x4_shri_s(LiftoffRegister dst, LiftoffRegister lhs,
1233 int32_t rhs);
1234 inline void emit_i32x4_shr_u(LiftoffRegister dst, LiftoffRegister lhs,
1235 LiftoffRegister rhs);
1236 inline void emit_i32x4_shri_u(LiftoffRegister dst, LiftoffRegister lhs,
1237 int32_t rhs);
1238 inline void emit_i32x4_add(LiftoffRegister dst, LiftoffRegister lhs,
1239 LiftoffRegister rhs);
1240 inline void emit_i32x4_sub(LiftoffRegister dst, LiftoffRegister lhs,
1241 LiftoffRegister rhs);
1242 inline void emit_i32x4_mul(LiftoffRegister dst, LiftoffRegister lhs,
1243 LiftoffRegister rhs);
1244 inline void emit_i32x4_min_s(LiftoffRegister dst, LiftoffRegister lhs,
1245 LiftoffRegister rhs);
1246 inline void emit_i32x4_min_u(LiftoffRegister dst, LiftoffRegister lhs,
1247 LiftoffRegister rhs);
1248 inline void emit_i32x4_max_s(LiftoffRegister dst, LiftoffRegister lhs,
1249 LiftoffRegister rhs);
1250 inline void emit_i32x4_max_u(LiftoffRegister dst, LiftoffRegister lhs,
1251 LiftoffRegister rhs);
1252 inline void emit_i32x4_dot_i16x8_s(LiftoffRegister dst, LiftoffRegister lhs,
1253 LiftoffRegister rhs);
1254 inline void emit_i32x4_extadd_pairwise_i16x8_s(LiftoffRegister dst,
1255 LiftoffRegister src);
1256 inline void emit_i32x4_extadd_pairwise_i16x8_u(LiftoffRegister dst,
1257 LiftoffRegister src);
1258 inline void emit_i32x4_extmul_low_i16x8_s(LiftoffRegister dst,
1259 LiftoffRegister src1,
1260 LiftoffRegister src2);
1261 inline void emit_i32x4_extmul_low_i16x8_u(LiftoffRegister dst,
1262 LiftoffRegister src1,
1263 LiftoffRegister src2);
1264 inline void emit_i32x4_extmul_high_i16x8_s(LiftoffRegister dst,
1265 LiftoffRegister src1,
1266 LiftoffRegister src2);
1267 inline void emit_i32x4_extmul_high_i16x8_u(LiftoffRegister dst,
1268 LiftoffRegister src1,
1269 LiftoffRegister src2);
1270 inline void emit_i64x2_neg(LiftoffRegister dst, LiftoffRegister src);
1271 inline void emit_i64x2_alltrue(LiftoffRegister dst, LiftoffRegister src);
1272 inline void emit_i64x2_shl(LiftoffRegister dst, LiftoffRegister lhs,
1273 LiftoffRegister rhs);
1274 inline void emit_i64x2_shli(LiftoffRegister dst, LiftoffRegister lhs,
1275 int32_t rhs);
1276 inline void emit_i64x2_shr_s(LiftoffRegister dst, LiftoffRegister lhs,
1277 LiftoffRegister rhs);
1278 inline void emit_i64x2_shri_s(LiftoffRegister dst, LiftoffRegister lhs,
1279 int32_t rhs);
1280 inline void emit_i64x2_shr_u(LiftoffRegister dst, LiftoffRegister lhs,
1281 LiftoffRegister rhs);
1282 inline void emit_i64x2_shri_u(LiftoffRegister dst, LiftoffRegister lhs,
1283 int32_t rhs);
1284 inline void emit_i64x2_add(LiftoffRegister dst, LiftoffRegister lhs,
1285 LiftoffRegister rhs);
1286 inline void emit_i64x2_sub(LiftoffRegister dst, LiftoffRegister lhs,
1287 LiftoffRegister rhs);
1288 inline void emit_i64x2_mul(LiftoffRegister dst, LiftoffRegister lhs,
1289 LiftoffRegister rhs);
1290 inline void emit_i64x2_extmul_low_i32x4_s(LiftoffRegister dst,
1291 LiftoffRegister src1,
1292 LiftoffRegister src2);
1293 inline void emit_i64x2_extmul_low_i32x4_u(LiftoffRegister dst,
1294 LiftoffRegister src1,
1295 LiftoffRegister src2);
1296 inline void emit_i64x2_extmul_high_i32x4_s(LiftoffRegister dst,
1297 LiftoffRegister src1,
1298 LiftoffRegister src2);
1299 inline void emit_i64x2_extmul_high_i32x4_u(LiftoffRegister dst,
1300 LiftoffRegister src1,
1301 LiftoffRegister src2);
1302 inline void emit_i64x2_bitmask(LiftoffRegister dst, LiftoffRegister src);
1303 inline void emit_i64x2_sconvert_i32x4_low(LiftoffRegister dst,
1304 LiftoffRegister src);
1305 inline void emit_i64x2_sconvert_i32x4_high(LiftoffRegister dst,
1306 LiftoffRegister src);
1307 inline void emit_i64x2_uconvert_i32x4_low(LiftoffRegister dst,
1308 LiftoffRegister src);
1309 inline void emit_i64x2_uconvert_i32x4_high(LiftoffRegister dst,
1310 LiftoffRegister src);
1311 inline void emit_f32x4_abs(LiftoffRegister dst, LiftoffRegister src);
1312 inline void emit_f32x4_neg(LiftoffRegister dst, LiftoffRegister src);
1313 inline void emit_f32x4_sqrt(LiftoffRegister dst, LiftoffRegister src);
1314 inline bool emit_f32x4_ceil(LiftoffRegister dst, LiftoffRegister src);
1315 inline bool emit_f32x4_floor(LiftoffRegister dst, LiftoffRegister src);
1316 inline bool emit_f32x4_trunc(LiftoffRegister dst, LiftoffRegister src);
1317 inline bool emit_f32x4_nearest_int(LiftoffRegister dst, LiftoffRegister src);
1318 inline void emit_f32x4_add(LiftoffRegister dst, LiftoffRegister lhs,
1319 LiftoffRegister rhs);
1320 inline void emit_f32x4_sub(LiftoffRegister dst, LiftoffRegister lhs,
1321 LiftoffRegister rhs);
1322 inline void emit_f32x4_mul(LiftoffRegister dst, LiftoffRegister lhs,
1323 LiftoffRegister rhs);
1324 inline void emit_f32x4_div(LiftoffRegister dst, LiftoffRegister lhs,
1325 LiftoffRegister rhs);
1326 inline void emit_f32x4_min(LiftoffRegister dst, LiftoffRegister lhs,
1327 LiftoffRegister rhs);
1328 inline void emit_f32x4_max(LiftoffRegister dst, LiftoffRegister lhs,
1329 LiftoffRegister rhs);
1330 inline void emit_f32x4_pmin(LiftoffRegister dst, LiftoffRegister lhs,
1331 LiftoffRegister rhs);
1332 inline void emit_f32x4_pmax(LiftoffRegister dst, LiftoffRegister lhs,
1333 LiftoffRegister rhs);
1334 inline void emit_f64x2_abs(LiftoffRegister dst, LiftoffRegister src);
1335 inline void emit_f64x2_neg(LiftoffRegister dst, LiftoffRegister src);
1336 inline void emit_f64x2_sqrt(LiftoffRegister dst, LiftoffRegister src);
1337 inline bool emit_f64x2_ceil(LiftoffRegister dst, LiftoffRegister src);
1338 inline bool emit_f64x2_floor(LiftoffRegister dst, LiftoffRegister src);
1339 inline bool emit_f64x2_trunc(LiftoffRegister dst, LiftoffRegister src);
1340 inline bool emit_f64x2_nearest_int(LiftoffRegister dst, LiftoffRegister src);
1341 inline void emit_f64x2_add(LiftoffRegister dst, LiftoffRegister lhs,
1342 LiftoffRegister rhs);
1343 inline void emit_f64x2_sub(LiftoffRegister dst, LiftoffRegister lhs,
1344 LiftoffRegister rhs);
1345 inline void emit_f64x2_mul(LiftoffRegister dst, LiftoffRegister lhs,
1346 LiftoffRegister rhs);
1347 inline void emit_f64x2_div(LiftoffRegister dst, LiftoffRegister lhs,
1348 LiftoffRegister rhs);
1349 inline void emit_f64x2_min(LiftoffRegister dst, LiftoffRegister lhs,
1350 LiftoffRegister rhs);
1351 inline void emit_f64x2_max(LiftoffRegister dst, LiftoffRegister lhs,
1352 LiftoffRegister rhs);
1353 inline void emit_f64x2_pmin(LiftoffRegister dst, LiftoffRegister lhs,
1354 LiftoffRegister rhs);
1355 inline void emit_f64x2_pmax(LiftoffRegister dst, LiftoffRegister lhs,
1356 LiftoffRegister rhs);
1357 inline void emit_f64x2_convert_low_i32x4_s(LiftoffRegister dst,
1358 LiftoffRegister src);
1359 inline void emit_f64x2_convert_low_i32x4_u(LiftoffRegister dst,
1360 LiftoffRegister src);
1361 inline void emit_i32x4_trunc_sat_f64x2_s_zero(LiftoffRegister dst,
1362 LiftoffRegister src);
1363 inline void emit_i32x4_trunc_sat_f64x2_u_zero(LiftoffRegister dst,
1364 LiftoffRegister src);
1365 inline void emit_f32x4_demote_f64x2_zero(LiftoffRegister dst,
1366 LiftoffRegister src);
1367 inline void emit_f64x2_promote_low_f32x4(LiftoffRegister dst,
1368 LiftoffRegister src);
1369 inline void emit_i32x4_sconvert_f32x4(LiftoffRegister dst,
1370 LiftoffRegister src);
1371 inline void emit_i32x4_uconvert_f32x4(LiftoffRegister dst,
1372 LiftoffRegister src);
1373 inline void emit_f32x4_sconvert_i32x4(LiftoffRegister dst,
1374 LiftoffRegister src);
1375 inline void emit_f32x4_uconvert_i32x4(LiftoffRegister dst,
1376 LiftoffRegister src);
1377 inline void emit_i8x16_sconvert_i16x8(LiftoffRegister dst,
1378 LiftoffRegister lhs,
1379 LiftoffRegister rhs);
1380 inline void emit_i8x16_uconvert_i16x8(LiftoffRegister dst,
1381 LiftoffRegister lhs,
1382 LiftoffRegister rhs);
1383 inline void emit_i16x8_sconvert_i32x4(LiftoffRegister dst,
1384 LiftoffRegister lhs,
1385 LiftoffRegister rhs);
1386 inline void emit_i16x8_uconvert_i32x4(LiftoffRegister dst,
1387 LiftoffRegister lhs,
1388 LiftoffRegister rhs);
1389 inline void emit_i16x8_sconvert_i8x16_low(LiftoffRegister dst,
1390 LiftoffRegister src);
1391 inline void emit_i16x8_sconvert_i8x16_high(LiftoffRegister dst,
1392 LiftoffRegister src);
1393 inline void emit_i16x8_uconvert_i8x16_low(LiftoffRegister dst,
1394 LiftoffRegister src);
1395 inline void emit_i16x8_uconvert_i8x16_high(LiftoffRegister dst,
1396 LiftoffRegister src);
1397 inline void emit_i32x4_sconvert_i16x8_low(LiftoffRegister dst,
1398 LiftoffRegister src);
1399 inline void emit_i32x4_sconvert_i16x8_high(LiftoffRegister dst,
1400 LiftoffRegister src);
1401 inline void emit_i32x4_uconvert_i16x8_low(LiftoffRegister dst,
1402 LiftoffRegister src);
1403 inline void emit_i32x4_uconvert_i16x8_high(LiftoffRegister dst,
1404 LiftoffRegister src);
1405 inline void emit_s128_and_not(LiftoffRegister dst, LiftoffRegister lhs,
1406 LiftoffRegister rhs);
1407 inline void emit_i8x16_rounding_average_u(LiftoffRegister dst,
1408 LiftoffRegister lhs,
1409 LiftoffRegister rhs);
1410 inline void emit_i16x8_rounding_average_u(LiftoffRegister dst,
1411 LiftoffRegister lhs,
1412 LiftoffRegister rhs);
1413 inline void emit_i8x16_abs(LiftoffRegister dst, LiftoffRegister src);
1414 inline void emit_i16x8_abs(LiftoffRegister dst, LiftoffRegister src);
1415 inline void emit_i32x4_abs(LiftoffRegister dst, LiftoffRegister src);
1416 inline void emit_i64x2_abs(LiftoffRegister dst, LiftoffRegister src);
1417 inline void emit_i8x16_extract_lane_s(LiftoffRegister dst,
1418 LiftoffRegister lhs,
1419 uint8_t imm_lane_idx);
1420 inline void emit_i8x16_extract_lane_u(LiftoffRegister dst,
1421 LiftoffRegister lhs,
1422 uint8_t imm_lane_idx);
1423 inline void emit_i16x8_extract_lane_s(LiftoffRegister dst,
1424 LiftoffRegister lhs,
1425 uint8_t imm_lane_idx);
1426 inline void emit_i16x8_extract_lane_u(LiftoffRegister dst,
1427 LiftoffRegister lhs,
1428 uint8_t imm_lane_idx);
1429 inline void emit_i32x4_extract_lane(LiftoffRegister dst, LiftoffRegister lhs,
1430 uint8_t imm_lane_idx);
1431 inline void emit_i64x2_extract_lane(LiftoffRegister dst, LiftoffRegister lhs,
1432 uint8_t imm_lane_idx);
1433 inline void emit_f32x4_extract_lane(LiftoffRegister dst, LiftoffRegister lhs,
1434 uint8_t imm_lane_idx);
1435 inline void emit_f64x2_extract_lane(LiftoffRegister dst, LiftoffRegister lhs,
1436 uint8_t imm_lane_idx);
1437 inline void emit_i8x16_replace_lane(LiftoffRegister dst, LiftoffRegister src1,
1438 LiftoffRegister src2,
1439 uint8_t imm_lane_idx);
1440 inline void emit_i16x8_replace_lane(LiftoffRegister dst, LiftoffRegister src1,
1441 LiftoffRegister src2,
1442 uint8_t imm_lane_idx);
1443 inline void emit_i32x4_replace_lane(LiftoffRegister dst, LiftoffRegister src1,
1444 LiftoffRegister src2,
1445 uint8_t imm_lane_idx);
1446 inline void emit_i64x2_replace_lane(LiftoffRegister dst, LiftoffRegister src1,
1447 LiftoffRegister src2,
1448 uint8_t imm_lane_idx);
1449 inline void emit_f32x4_replace_lane(LiftoffRegister dst, LiftoffRegister src1,
1450 LiftoffRegister src2,
1451 uint8_t imm_lane_idx);
1452 inline void emit_f64x2_replace_lane(LiftoffRegister dst, LiftoffRegister src1,
1453 LiftoffRegister src2,
1454 uint8_t imm_lane_idx);
1455
1456 inline void StackCheck(Label* ool_code, Register limit_address);
1457
1458 inline void CallTrapCallbackForTesting();
1459
1460 inline void AssertUnreachable(AbortReason reason);
1461
1462 inline void PushRegisters(LiftoffRegList);
1463 inline void PopRegisters(LiftoffRegList);
1464
1465 inline void RecordSpillsInSafepoint(
1466 SafepointTableBuilder::Safepoint& safepoint, LiftoffRegList all_spills,
1467 LiftoffRegList ref_spills, int spill_offset);
1468
1469 inline void DropStackSlotsAndRet(uint32_t num_stack_slots);
1470
1471 // Execute a C call. Arguments are pushed to the stack and a pointer to this
1472 // region is passed to the C function. If {out_argument_kind != kVoid},
1473 // this is the return value of the C function, stored in {rets[0]}. Further
1474 // outputs (specified in {sig->returns()}) are read from the buffer and stored
1475 // in the remaining {rets} registers.
1476 inline void CallC(const ValueKindSig* sig, const LiftoffRegister* args,
1477 const LiftoffRegister* rets, ValueKind out_argument_kind,
1478 int stack_bytes, ExternalReference ext_ref);
1479
1480 inline void CallNativeWasmCode(Address addr);
1481 inline void TailCallNativeWasmCode(Address addr);
1482 // Indirect call: If {target == no_reg}, then pop the target from the stack.
1483 inline void CallIndirect(const ValueKindSig* sig,
1484 compiler::CallDescriptor* call_descriptor,
1485 Register target);
1486 inline void TailCallIndirect(Register target);
1487 inline void CallRuntimeStub(WasmCode::RuntimeStubId sid);
1488
1489 // Reserve space in the current frame, store address to space in {addr}.
1490 inline void AllocateStackSlot(Register addr, uint32_t size);
1491 inline void DeallocateStackSlot(uint32_t size);
1492
1493 // Instrumentation for shadow-stack-compatible OSR on x64.
1494 inline void MaybeOSR();
1495
1496 // Set the i32 at address dst to a non-zero value if src is a NaN.
1497 inline void emit_set_if_nan(Register dst, DoubleRegister src, ValueKind kind);
1498
1499 // Set the i32 at address dst to a non-zero value if src contains a NaN.
1500 inline void emit_s128_set_if_nan(Register dst, LiftoffRegister src,
1501 Register tmp_gp, LiftoffRegister tmp_s128,
1502 ValueKind lane_kind);
1503
1504 ////////////////////////////////////
1505 // End of platform-specific part. //
1506 ////////////////////////////////////
1507
num_locals() const1508 uint32_t num_locals() const { return num_locals_; }
1509 void set_num_locals(uint32_t num_locals);
1510
1511 int GetTotalFrameSlotCountForGC() const;
1512
GetTotalFrameSize() const1513 int GetTotalFrameSize() const { return max_used_spill_offset_; }
1514
local_kind(uint32_t index)1515 ValueKind local_kind(uint32_t index) {
1516 DCHECK_GT(num_locals_, index);
1517 ValueKind* locals =
1518 num_locals_ <= kInlineLocalKinds ? local_kinds_ : more_local_kinds_;
1519 return locals[index];
1520 }
1521
set_local_kind(uint32_t index, ValueKind kind)1522 void set_local_kind(uint32_t index, ValueKind kind) {
1523 ValueKind* locals =
1524 num_locals_ <= kInlineLocalKinds ? local_kinds_ : more_local_kinds_;
1525 locals[index] = kind;
1526 }
1527
cache_state()1528 CacheState* cache_state() { return &cache_state_; }
cache_state() const1529 const CacheState* cache_state() const { return &cache_state_; }
1530
did_bailout()1531 bool did_bailout() { return bailout_reason_ != kSuccess; }
bailout_reason() const1532 LiftoffBailoutReason bailout_reason() const { return bailout_reason_; }
bailout_detail() const1533 const char* bailout_detail() const { return bailout_detail_; }
1534
bailout(LiftoffBailoutReason reason, const char* detail)1535 void bailout(LiftoffBailoutReason reason, const char* detail) {
1536 DCHECK_NE(kSuccess, reason);
1537 if (bailout_reason_ != kSuccess) return;
1538 AbortCompilation();
1539 bailout_reason_ = reason;
1540 bailout_detail_ = detail;
1541 }
1542
1543 private:
1544 LiftoffRegister LoadI64HalfIntoRegister(VarState slot, RegPairHalf half);
1545
1546 V8_NOINLINE LiftoffRegister SpillOneRegister(LiftoffRegList candidates);
1547 // Spill one or two fp registers to get a pair of adjacent fp registers.
1548 LiftoffRegister SpillAdjacentFpRegisters(LiftoffRegList pinned);
1549
1550 uint32_t num_locals_ = 0;
1551 static constexpr uint32_t kInlineLocalKinds = 16;
1552 union {
1553 ValueKind local_kinds_[kInlineLocalKinds];
1554 ValueKind* more_local_kinds_;
1555 };
1556 static_assert(sizeof(ValueKind) == 1,
1557 "Reconsider this inlining if ValueKind gets bigger");
1558 CacheState cache_state_;
1559 // The maximum spill offset for slots in the value stack.
1560 int max_used_spill_offset_ = StaticStackFrameSize();
1561 // The amount of memory needed for register spills in OOL code.
1562 int ool_spill_space_size_ = 0;
1563 LiftoffBailoutReason bailout_reason_ = kSuccess;
1564 const char* bailout_detail_ = nullptr;
1565 };
1566
1567 std::ostream& operator<<(std::ostream& os, LiftoffAssembler::VarState);
1568
1569 // =======================================================================
1570 // Partially platform-independent implementations of the platform-dependent
1571 // part.
1572
1573 #ifdef V8_TARGET_ARCH_32_BIT
1574
1575 namespace liftoff {
1576 template <void (LiftoffAssembler::*op)(Register, Register, Register)>
EmitI64IndependentHalfOperation(LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)1577 void EmitI64IndependentHalfOperation(LiftoffAssembler* assm,
1578 LiftoffRegister dst, LiftoffRegister lhs,
1579 LiftoffRegister rhs) {
1580 // If {dst.low_gp()} does not overlap with {lhs.high_gp()} or {rhs.high_gp()},
1581 // just first compute the lower half, then the upper half.
1582 if (dst.low() != lhs.high() && dst.low() != rhs.high()) {
1583 (assm->*op)(dst.low_gp(), lhs.low_gp(), rhs.low_gp());
1584 (assm->*op)(dst.high_gp(), lhs.high_gp(), rhs.high_gp());
1585 return;
1586 }
1587 // If {dst.high_gp()} does not overlap with {lhs.low_gp()} or {rhs.low_gp()},
1588 // we can compute this the other way around.
1589 if (dst.high() != lhs.low() && dst.high() != rhs.low()) {
1590 (assm->*op)(dst.high_gp(), lhs.high_gp(), rhs.high_gp());
1591 (assm->*op)(dst.low_gp(), lhs.low_gp(), rhs.low_gp());
1592 return;
1593 }
1594 // Otherwise, we need a temporary register.
1595 Register tmp = assm->GetUnusedRegister(kGpReg, LiftoffRegList{lhs, rhs}).gp();
1596 (assm->*op)(tmp, lhs.low_gp(), rhs.low_gp());
1597 (assm->*op)(dst.high_gp(), lhs.high_gp(), rhs.high_gp());
1598 assm->Move(dst.low_gp(), tmp, kI32);
1599 }
1600
1601 template <void (LiftoffAssembler::*op)(Register, Register, int32_t)>
EmitI64IndependentHalfOperationImm(LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister lhs, int64_t imm)1602 void EmitI64IndependentHalfOperationImm(LiftoffAssembler* assm,
1603 LiftoffRegister dst,
1604 LiftoffRegister lhs, int64_t imm) {
1605 int32_t low_word = static_cast<int32_t>(imm);
1606 int32_t high_word = static_cast<int32_t>(imm >> 32);
1607 // If {dst.low_gp()} does not overlap with {lhs.high_gp()},
1608 // just first compute the lower half, then the upper half.
1609 if (dst.low() != lhs.high()) {
1610 (assm->*op)(dst.low_gp(), lhs.low_gp(), low_word);
1611 (assm->*op)(dst.high_gp(), lhs.high_gp(), high_word);
1612 return;
1613 }
1614 // If {dst.high_gp()} does not overlap with {lhs.low_gp()},
1615 // we can compute this the other way around.
1616 if (dst.high() != lhs.low()) {
1617 (assm->*op)(dst.high_gp(), lhs.high_gp(), high_word);
1618 (assm->*op)(dst.low_gp(), lhs.low_gp(), low_word);
1619 return;
1620 }
1621 // Otherwise, we need a temporary register.
1622 Register tmp = assm->GetUnusedRegister(kGpReg, LiftoffRegList{lhs}).gp();
1623 (assm->*op)(tmp, lhs.low_gp(), low_word);
1624 (assm->*op)(dst.high_gp(), lhs.high_gp(), high_word);
1625 assm->Move(dst.low_gp(), tmp, kI32);
1626 }
1627 } // namespace liftoff
1628
emit_i64_and(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)1629 void LiftoffAssembler::emit_i64_and(LiftoffRegister dst, LiftoffRegister lhs,
1630 LiftoffRegister rhs) {
1631 liftoff::EmitI64IndependentHalfOperation<&LiftoffAssembler::emit_i32_and>(
1632 this, dst, lhs, rhs);
1633 }
1634
emit_i64_andi(LiftoffRegister dst, LiftoffRegister lhs, int32_t imm)1635 void LiftoffAssembler::emit_i64_andi(LiftoffRegister dst, LiftoffRegister lhs,
1636 int32_t imm) {
1637 liftoff::EmitI64IndependentHalfOperationImm<&LiftoffAssembler::emit_i32_andi>(
1638 this, dst, lhs, imm);
1639 }
1640
emit_i64_or(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)1641 void LiftoffAssembler::emit_i64_or(LiftoffRegister dst, LiftoffRegister lhs,
1642 LiftoffRegister rhs) {
1643 liftoff::EmitI64IndependentHalfOperation<&LiftoffAssembler::emit_i32_or>(
1644 this, dst, lhs, rhs);
1645 }
1646
emit_i64_ori(LiftoffRegister dst, LiftoffRegister lhs, int32_t imm)1647 void LiftoffAssembler::emit_i64_ori(LiftoffRegister dst, LiftoffRegister lhs,
1648 int32_t imm) {
1649 liftoff::EmitI64IndependentHalfOperationImm<&LiftoffAssembler::emit_i32_ori>(
1650 this, dst, lhs, imm);
1651 }
1652
emit_i64_xor(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)1653 void LiftoffAssembler::emit_i64_xor(LiftoffRegister dst, LiftoffRegister lhs,
1654 LiftoffRegister rhs) {
1655 liftoff::EmitI64IndependentHalfOperation<&LiftoffAssembler::emit_i32_xor>(
1656 this, dst, lhs, rhs);
1657 }
1658
emit_i64_xori(LiftoffRegister dst, LiftoffRegister lhs, int32_t imm)1659 void LiftoffAssembler::emit_i64_xori(LiftoffRegister dst, LiftoffRegister lhs,
1660 int32_t imm) {
1661 liftoff::EmitI64IndependentHalfOperationImm<&LiftoffAssembler::emit_i32_xori>(
1662 this, dst, lhs, imm);
1663 }
1664
emit_u32_to_uintptr(Register dst, Register src)1665 void LiftoffAssembler::emit_u32_to_uintptr(Register dst, Register src) {
1666 // This is a no-op on 32-bit systems.
1667 }
1668
1669 #endif // V8_TARGET_ARCH_32_BIT
1670
1671 // End of the partially platform-independent implementations of the
1672 // platform-dependent part.
1673 // =======================================================================
1674
1675 class LiftoffStackSlots {
1676 public:
LiftoffStackSlots(LiftoffAssembler* wasm_asm)1677 explicit LiftoffStackSlots(LiftoffAssembler* wasm_asm) : asm_(wasm_asm) {}
1678 LiftoffStackSlots(const LiftoffStackSlots&) = delete;
1679 LiftoffStackSlots& operator=(const LiftoffStackSlots&) = delete;
1680
Add(const LiftoffAssembler::VarState& src, uint32_t src_offset, RegPairHalf half, int dst_slot)1681 void Add(const LiftoffAssembler::VarState& src, uint32_t src_offset,
1682 RegPairHalf half, int dst_slot) {
1683 DCHECK_LE(0, dst_slot);
1684 slots_.emplace_back(src, src_offset, half, dst_slot);
1685 }
1686
Add(const LiftoffAssembler::VarState& src, int dst_slot)1687 void Add(const LiftoffAssembler::VarState& src, int dst_slot) {
1688 DCHECK_LE(0, dst_slot);
1689 slots_.emplace_back(src, dst_slot);
1690 }
1691
SortInPushOrder()1692 void SortInPushOrder() {
1693 std::sort(slots_.begin(), slots_.end(), [](const Slot& a, const Slot& b) {
1694 return a.dst_slot_ > b.dst_slot_;
1695 });
1696 }
1697
1698 inline void Construct(int param_slots);
1699
1700 private:
1701 // A logical slot, which may occupy multiple stack slots.
1702 struct Slot {
Slotv8::internal::wasm::LiftoffAssembler::LiftoffStackSlots::Slot1703 Slot(const LiftoffAssembler::VarState& src, uint32_t src_offset,
1704 RegPairHalf half, int dst_slot)
1705 : src_(src),
1706 src_offset_(src_offset),
1707 half_(half),
1708 dst_slot_(dst_slot) {}
Slotv8::internal::wasm::LiftoffAssembler::LiftoffStackSlots::Slot1709 Slot(const LiftoffAssembler::VarState& src, int dst_slot)
1710 : src_(src), half_(kLowWord), dst_slot_(dst_slot) {}
1711
1712 LiftoffAssembler::VarState src_;
1713 uint32_t src_offset_ = 0;
1714 RegPairHalf half_;
1715 int dst_slot_ = 0;
1716 };
1717
1718 // Returns the size in bytes of the given logical slot.
SlotSizeInBytes(const Slot& slot)1719 static int SlotSizeInBytes(const Slot& slot) {
1720 const ValueKind kind = slot.src_.kind();
1721 if (kind == kS128) return kSimd128Size;
1722 if (kind == kF64) return kDoubleSize;
1723 return kSystemPointerSize;
1724 }
1725
1726 base::SmallVector<Slot, 8> slots_;
1727 LiftoffAssembler* const asm_;
1728 };
1729
1730 #if DEBUG
1731 bool CheckCompatibleStackSlotTypes(ValueKind a, ValueKind b);
1732 #endif
1733
1734 } // namespace wasm
1735 } // namespace internal
1736 } // namespace v8
1737
1738 // Include platform specific implementation.
1739 #if V8_TARGET_ARCH_IA32
1740 #include "src/wasm/baseline/ia32/liftoff-assembler-ia32.h"
1741 #elif V8_TARGET_ARCH_X64
1742 #include "src/wasm/baseline/x64/liftoff-assembler-x64.h"
1743 #elif V8_TARGET_ARCH_ARM64
1744 #include "src/wasm/baseline/arm64/liftoff-assembler-arm64.h"
1745 #elif V8_TARGET_ARCH_ARM
1746 #include "src/wasm/baseline/arm/liftoff-assembler-arm.h"
1747 #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
1748 #include "src/wasm/baseline/ppc/liftoff-assembler-ppc.h"
1749 #elif V8_TARGET_ARCH_MIPS
1750 #include "src/wasm/baseline/mips/liftoff-assembler-mips.h"
1751 #elif V8_TARGET_ARCH_MIPS64
1752 #include "src/wasm/baseline/mips64/liftoff-assembler-mips64.h"
1753 #elif V8_TARGET_ARCH_LOONG64
1754 #include "src/wasm/baseline/loong64/liftoff-assembler-loong64.h"
1755 #elif V8_TARGET_ARCH_S390
1756 #include "src/wasm/baseline/s390/liftoff-assembler-s390.h"
1757 #elif V8_TARGET_ARCH_RISCV64
1758 #include "src/wasm/baseline/riscv64/liftoff-assembler-riscv64.h"
1759 #else
1760 #error Unsupported architecture.
1761 #endif
1762
1763 #endif // V8_WASM_BASELINE_LIFTOFF_ASSEMBLER_H_
1764