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