• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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_WASM_LINKAGE_H_
6 #define V8_WASM_WASM_LINKAGE_H_
7 
8 #include "src/assembler-arch.h"
9 #include "src/machine-type.h"
10 #include "src/signature.h"
11 #include "src/wasm/value-type.h"
12 
13 namespace v8 {
14 namespace internal {
15 namespace wasm {
16 
17 #if V8_TARGET_ARCH_IA32
18 // ===========================================================================
19 // == ia32 ===================================================================
20 // ===========================================================================
21 constexpr Register kGpParamRegisters[] = {esi, eax, edx, ecx, ebx};
22 constexpr Register kGpReturnRegisters[] = {eax, edx};
23 constexpr DoubleRegister kFpParamRegisters[] = {xmm1, xmm2, xmm3,
24                                                 xmm4, xmm5, xmm6};
25 constexpr DoubleRegister kFpReturnRegisters[] = {xmm1, xmm2};
26 
27 #elif V8_TARGET_ARCH_X64
28 // ===========================================================================
29 // == x64 ====================================================================
30 // ===========================================================================
31 constexpr Register kGpParamRegisters[] = {rsi, rax, rdx, rcx, rbx, rdi};
32 constexpr Register kGpReturnRegisters[] = {rax, rdx};
33 constexpr DoubleRegister kFpParamRegisters[] = {xmm1, xmm2, xmm3,
34                                                 xmm4, xmm5, xmm6};
35 constexpr DoubleRegister kFpReturnRegisters[] = {xmm1, xmm2};
36 
37 #elif V8_TARGET_ARCH_ARM
38 // ===========================================================================
39 // == arm ====================================================================
40 // ===========================================================================
41 constexpr Register kGpParamRegisters[] = {r3, r0, r1, r2};
42 constexpr Register kGpReturnRegisters[] = {r0, r1};
43 constexpr DoubleRegister kFpParamRegisters[] = {d0, d1, d2, d3, d4, d5, d6, d7};
44 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d1};
45 
46 #elif V8_TARGET_ARCH_ARM64
47 // ===========================================================================
48 // == arm64 ====================================================================
49 // ===========================================================================
50 constexpr Register kGpParamRegisters[] = {x7, x0, x1, x2, x3, x4, x5, x6};
51 constexpr Register kGpReturnRegisters[] = {x0, x1};
52 constexpr DoubleRegister kFpParamRegisters[] = {d0, d1, d2, d3, d4, d5, d6, d7};
53 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d1};
54 
55 #elif V8_TARGET_ARCH_MIPS
56 // ===========================================================================
57 // == mips ===================================================================
58 // ===========================================================================
59 constexpr Register kGpParamRegisters[] = {a0, a1, a2, a3};
60 constexpr Register kGpReturnRegisters[] = {v0, v1};
61 constexpr DoubleRegister kFpParamRegisters[] = {f2, f4, f6, f8, f10, f12, f14};
62 constexpr DoubleRegister kFpReturnRegisters[] = {f2, f4};
63 
64 #elif V8_TARGET_ARCH_MIPS64
65 // ===========================================================================
66 // == mips64 =================================================================
67 // ===========================================================================
68 constexpr Register kGpParamRegisters[] = {a0, a1, a2, a3, a4, a5, a6, a7};
69 constexpr Register kGpReturnRegisters[] = {v0, v1};
70 constexpr DoubleRegister kFpParamRegisters[] = {f2, f4, f6, f8, f10, f12, f14};
71 constexpr DoubleRegister kFpReturnRegisters[] = {f2, f4};
72 
73 #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
74 // ===========================================================================
75 // == ppc & ppc64 ============================================================
76 // ===========================================================================
77 constexpr Register kGpParamRegisters[] = {r10, r3, r4, r5, r6, r7, r8, r9};
78 constexpr Register kGpReturnRegisters[] = {r3, r4};
79 constexpr DoubleRegister kFpParamRegisters[] = {d1, d2, d3, d4, d5, d6, d7, d8};
80 constexpr DoubleRegister kFpReturnRegisters[] = {d1, d2};
81 
82 #elif V8_TARGET_ARCH_S390X
83 // ===========================================================================
84 // == s390x ==================================================================
85 // ===========================================================================
86 constexpr Register kGpParamRegisters[] = {r6, r2, r3, r4, r5};
87 constexpr Register kGpReturnRegisters[] = {r2, r3};
88 constexpr DoubleRegister kFpParamRegisters[] = {d0, d2, d4, d6};
89 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d2, d4, d6};
90 
91 #elif V8_TARGET_ARCH_S390
92 // ===========================================================================
93 // == s390 ===================================================================
94 // ===========================================================================
95 constexpr Register kGpParamRegisters[] = {r6, r2, r3, r4, r5};
96 constexpr Register kGpReturnRegisters[] = {r2, r3};
97 constexpr DoubleRegister kFpParamRegisters[] = {d0, d2};
98 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d2};
99 
100 #else
101 // ===========================================================================
102 // == unknown ================================================================
103 // ===========================================================================
104 // Do not use any registers, we will just always use the stack.
105 constexpr Register kGpParamRegisters[] = {};
106 constexpr Register kGpReturnRegisters[] = {};
107 constexpr DoubleRegister kFpParamRegisters[] = {};
108 constexpr DoubleRegister kFpReturnRegisters[] = {};
109 
110 #endif
111 
112 // The parameter index where the instance parameter should be placed in wasm
113 // call descriptors. This is used by the Int64Lowering::LowerNode method.
114 constexpr int kWasmInstanceParameterIndex = 0;
115 
116 class LinkageAllocator {
117  public:
118   template <size_t kNumGpRegs, size_t kNumFpRegs>
LinkageAllocator(const Register (& gp)[kNumGpRegs],const DoubleRegister (& fp)[kNumFpRegs])119   constexpr LinkageAllocator(const Register (&gp)[kNumGpRegs],
120                              const DoubleRegister (&fp)[kNumFpRegs])
121       : LinkageAllocator(gp, kNumGpRegs, fp, kNumFpRegs) {}
122 
LinkageAllocator(const Register * gp,int gpc,const DoubleRegister * fp,int fpc)123   constexpr LinkageAllocator(const Register* gp, int gpc,
124                              const DoubleRegister* fp, int fpc)
125       : gp_count_(gpc), gp_regs_(gp), fp_count_(fpc), fp_regs_(fp) {}
126 
CanAllocateGP()127   bool CanAllocateGP() const { return gp_offset_ < gp_count_; }
CanAllocateFP(MachineRepresentation rep)128   bool CanAllocateFP(MachineRepresentation rep) const {
129 #if V8_TARGET_ARCH_ARM
130     switch (rep) {
131       case MachineRepresentation::kFloat32:
132         return extra_float_reg >= 0 || fp_offset_ < fp_count_;
133       case MachineRepresentation::kFloat64:
134         return extra_double_reg >= 0 || fp_offset_ < fp_count_;
135       case MachineRepresentation::kSimd128:
136         return ((fp_offset_ + 1) & ~1) + 1 < fp_count_;
137       default:
138         UNREACHABLE();
139         return false;
140     }
141 #endif
142     return fp_offset_ < fp_count_;
143   }
144 
NextGpReg()145   int NextGpReg() {
146     DCHECK_LT(gp_offset_, gp_count_);
147     return gp_regs_[gp_offset_++].code();
148   }
149 
NextFpReg(MachineRepresentation rep)150   int NextFpReg(MachineRepresentation rep) {
151 #if V8_TARGET_ARCH_ARM
152     switch (rep) {
153       case MachineRepresentation::kFloat32: {
154         // Use the extra S-register if we can.
155         if (extra_float_reg >= 0) {
156           int reg_code = extra_float_reg;
157           extra_float_reg = -1;
158           return reg_code;
159         }
160         // Allocate a D-register and split into 2 float registers.
161         int d_reg_code = NextFpReg(MachineRepresentation::kFloat64);
162         DCHECK_GT(16, d_reg_code);  // D-registers 16 - 31 can't split.
163         int reg_code = d_reg_code * 2;
164         // Save the extra S-register.
165         DCHECK_EQ(-1, extra_float_reg);
166         extra_float_reg = reg_code + 1;
167         return reg_code;
168       }
169       case MachineRepresentation::kFloat64: {
170         // Use an extra D-register if we can.
171         if (extra_double_reg >= 0) {
172           int reg_code = extra_double_reg;
173           extra_double_reg = -1;
174           return reg_code;
175         }
176         DCHECK_LT(fp_offset_, fp_count_);
177         return fp_regs_[fp_offset_++].code();
178       }
179       case MachineRepresentation::kSimd128: {
180         // Q-register must be an even-odd pair, so we must try to allocate at
181         // the end, not using extra_double_reg. If we are at an odd D-register,
182         // skip past it (saving it to extra_double_reg).
183         DCHECK_LT(((fp_offset_ + 1) & ~1) + 1, fp_count_);
184         int d_reg1_code = fp_regs_[fp_offset_++].code();
185         if (d_reg1_code % 2 != 0) {
186           // If we're misaligned then extra_double_reg must have been consumed.
187           DCHECK_EQ(-1, extra_double_reg);
188           int odd_double_reg = d_reg1_code;
189           d_reg1_code = fp_regs_[fp_offset_++].code();
190           extra_double_reg = odd_double_reg;
191         }
192         // Combine the current D-register with the next to form a Q-register.
193         int d_reg2_code = fp_regs_[fp_offset_++].code();
194         DCHECK_EQ(0, d_reg1_code % 2);
195         DCHECK_EQ(d_reg1_code + 1, d_reg2_code);
196         USE(d_reg2_code);
197         return d_reg1_code / 2;
198       }
199       default:
200         UNREACHABLE();
201     }
202 #else
203     DCHECK_LT(fp_offset_, fp_count_);
204     return fp_regs_[fp_offset_++].code();
205 #endif
206   }
207 
208   // Stackslots are counted upwards starting from 0 (or the offset set by
209   // {SetStackOffset}.
NumStackSlots(MachineRepresentation type)210   int NumStackSlots(MachineRepresentation type) {
211     return std::max(1, ElementSizeInBytes(type) / kPointerSize);
212   }
213 
214   // Stackslots are counted upwards starting from 0 (or the offset set by
215   // {SetStackOffset}. If {type} needs more than
216   // one stack slot, the lowest used stack slot is returned.
NextStackSlot(MachineRepresentation type)217   int NextStackSlot(MachineRepresentation type) {
218     int num_stack_slots = NumStackSlots(type);
219     int offset = stack_offset_;
220     stack_offset_ += num_stack_slots;
221     return offset;
222   }
223 
224   // Set an offset for the stack slots returned by {NextStackSlot} and
225   // {NumStackSlots}. Can only be called before any call to {NextStackSlot}.
SetStackOffset(int num)226   void SetStackOffset(int num) {
227     DCHECK_LE(0, num);
228     DCHECK_EQ(0, stack_offset_);
229     stack_offset_ = num;
230   }
231 
NumStackSlots()232   int NumStackSlots() const { return stack_offset_; }
233 
234  private:
235   const int gp_count_;
236   int gp_offset_ = 0;
237   const Register* const gp_regs_;
238 
239   const int fp_count_;
240   int fp_offset_ = 0;
241   const DoubleRegister* const fp_regs_;
242 
243 #if V8_TARGET_ARCH_ARM
244   // ARM FP register aliasing may require splitting or merging double registers.
245   // Track fragments of registers below fp_offset_ here. There can only be one
246   // extra float and double register.
247   int extra_float_reg = -1;
248   int extra_double_reg = -1;
249 #endif
250 
251   int stack_offset_ = 0;
252 };
253 
254 }  // namespace wasm
255 }  // namespace internal
256 }  // namespace v8
257 
258 #endif  // V8_WASM_WASM_LINKAGE_H_
259