Home | History | Annotate | Download | only in compiler
      1 // Copyright 2015 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 #include "src/assembler.h"
      6 #include "src/macro-assembler.h"
      7 #include "src/register-configuration.h"
      8 
      9 #include "src/wasm/wasm-module.h"
     10 
     11 #include "src/compiler/linkage.h"
     12 
     13 #include "src/zone.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 // TODO(titzer): this should not be in the WASM namespace.
     18 namespace wasm {
     19 
     20 using compiler::LocationSignature;
     21 using compiler::CallDescriptor;
     22 using compiler::LinkageLocation;
     23 
     24 namespace {
     25 MachineType MachineTypeFor(LocalType type) {
     26   switch (type) {
     27     case kAstI32:
     28       return MachineType::Int32();
     29     case kAstI64:
     30       return MachineType::Int64();
     31     case kAstF64:
     32       return MachineType::Float64();
     33     case kAstF32:
     34       return MachineType::Float32();
     35     case kAstS128:
     36       return MachineType::Simd128();
     37     default:
     38       UNREACHABLE();
     39       return MachineType::AnyTagged();
     40   }
     41 }
     42 
     43 
     44 // Platform-specific configuration for C calling convention.
     45 LinkageLocation regloc(Register reg) {
     46   return LinkageLocation::ForRegister(reg.code());
     47 }
     48 
     49 
     50 LinkageLocation regloc(DoubleRegister reg) {
     51   return LinkageLocation::ForRegister(reg.code());
     52 }
     53 
     54 
     55 LinkageLocation stackloc(int i) {
     56   return LinkageLocation::ForCallerFrameSlot(i);
     57 }
     58 
     59 
     60 #if V8_TARGET_ARCH_IA32
     61 // ===========================================================================
     62 // == ia32 ===================================================================
     63 // ===========================================================================
     64 #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi
     65 #define GP_RETURN_REGISTERS eax, edx
     66 #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
     67 #define FP_RETURN_REGISTERS xmm1, xmm2
     68 
     69 #elif V8_TARGET_ARCH_X64
     70 // ===========================================================================
     71 // == x64 ====================================================================
     72 // ===========================================================================
     73 #define GP_PARAM_REGISTERS rax, rdx, rcx, rbx, rsi, rdi
     74 #define GP_RETURN_REGISTERS rax, rdx
     75 #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
     76 #define FP_RETURN_REGISTERS xmm1, xmm2
     77 
     78 #elif V8_TARGET_ARCH_X87
     79 // ===========================================================================
     80 // == x87 ====================================================================
     81 // ===========================================================================
     82 #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi
     83 #define GP_RETURN_REGISTERS eax, edx
     84 #define FP_RETURN_REGISTERS stX_0
     85 
     86 #elif V8_TARGET_ARCH_ARM
     87 // ===========================================================================
     88 // == arm ====================================================================
     89 // ===========================================================================
     90 #define GP_PARAM_REGISTERS r0, r1, r2, r3
     91 #define GP_RETURN_REGISTERS r0, r1
     92 #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
     93 #define FP_RETURN_REGISTERS d0, d1
     94 
     95 #elif V8_TARGET_ARCH_ARM64
     96 // ===========================================================================
     97 // == arm64 ====================================================================
     98 // ===========================================================================
     99 #define GP_PARAM_REGISTERS x0, x1, x2, x3, x4, x5, x6, x7
    100 #define GP_RETURN_REGISTERS x0, x1
    101 #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
    102 #define FP_RETURN_REGISTERS d0, d1
    103 
    104 #elif V8_TARGET_ARCH_MIPS
    105 // ===========================================================================
    106 // == mips ===================================================================
    107 // ===========================================================================
    108 #define GP_PARAM_REGISTERS a0, a1, a2, a3
    109 #define GP_RETURN_REGISTERS v0, v1
    110 #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
    111 #define FP_RETURN_REGISTERS f2, f4
    112 
    113 #elif V8_TARGET_ARCH_MIPS64
    114 // ===========================================================================
    115 // == mips64 =================================================================
    116 // ===========================================================================
    117 #define GP_PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
    118 #define GP_RETURN_REGISTERS v0, v1
    119 #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
    120 #define FP_RETURN_REGISTERS f2, f4
    121 
    122 #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
    123 // ===========================================================================
    124 // == ppc & ppc64 ============================================================
    125 // ===========================================================================
    126 #define GP_PARAM_REGISTERS r3, r4, r5, r6, r7, r8, r9, r10
    127 #define GP_RETURN_REGISTERS r3, r4
    128 #define FP_PARAM_REGISTERS d1, d2, d3, d4, d5, d6, d7, d8
    129 #define FP_RETURN_REGISTERS d1, d2
    130 
    131 #elif V8_TARGET_ARCH_S390X
    132 // ===========================================================================
    133 // == s390x ==================================================================
    134 // ===========================================================================
    135 #define GP_PARAM_REGISTERS r2, r3, r4, r5, r6
    136 #define GP_RETURN_REGISTERS r2
    137 #define FP_PARAM_REGISTERS d0, d2, d4, d6
    138 #define FP_RETURN_REGISTERS d0, d2, d4, d6
    139 
    140 #elif V8_TARGET_ARCH_S390
    141 // ===========================================================================
    142 // == s390 ===================================================================
    143 // ===========================================================================
    144 #define GP_PARAM_REGISTERS r2, r3, r4, r5, r6
    145 #define GP_RETURN_REGISTERS r2, r3
    146 #define FP_PARAM_REGISTERS d0, d2
    147 #define FP_RETURN_REGISTERS d0, d2
    148 
    149 #else
    150 // ===========================================================================
    151 // == unknown ================================================================
    152 // ===========================================================================
    153 // Don't define anything. We'll just always use the stack.
    154 #endif
    155 
    156 
    157 // Helper for allocating either an GP or FP reg, or the next stack slot.
    158 struct Allocator {
    159   Allocator(const Register* gp, int gpc, const DoubleRegister* fp, int fpc)
    160       : gp_count(gpc),
    161         gp_offset(0),
    162         gp_regs(gp),
    163         fp_count(fpc),
    164         fp_offset(0),
    165         fp_regs(fp),
    166         stack_offset(0) {}
    167 
    168   int gp_count;
    169   int gp_offset;
    170   const Register* gp_regs;
    171 
    172   int fp_count;
    173   int fp_offset;
    174   const DoubleRegister* fp_regs;
    175 
    176   int stack_offset;
    177 
    178   LinkageLocation Next(LocalType type) {
    179     if (IsFloatingPoint(type)) {
    180       // Allocate a floating point register/stack location.
    181       if (fp_offset < fp_count) {
    182         DoubleRegister reg = fp_regs[fp_offset++];
    183 #if V8_TARGET_ARCH_ARM
    184         // Allocate floats using a double register, but modify the code to
    185         // reflect how ARM FP registers alias.
    186         // TODO(bbudge) Modify wasm linkage to allow use of all float regs.
    187         if (type == kAstF32) {
    188           int float_reg_code = reg.code() * 2;
    189           DCHECK(float_reg_code < RegisterConfiguration::kMaxFPRegisters);
    190           return regloc(DoubleRegister::from_code(float_reg_code));
    191         }
    192 #endif
    193         return regloc(reg);
    194       } else {
    195         int offset = -1 - stack_offset;
    196         stack_offset += Words(type);
    197         return stackloc(offset);
    198       }
    199     } else {
    200       // Allocate a general purpose register/stack location.
    201       if (gp_offset < gp_count) {
    202         return regloc(gp_regs[gp_offset++]);
    203       } else {
    204         int offset = -1 - stack_offset;
    205         stack_offset += Words(type);
    206         return stackloc(offset);
    207       }
    208     }
    209   }
    210   bool IsFloatingPoint(LocalType type) {
    211     return type == kAstF32 || type == kAstF64;
    212   }
    213   int Words(LocalType type) {
    214     if (kPointerSize < 8 && (type == kAstI64 || type == kAstF64)) {
    215       return 2;
    216     }
    217     return 1;
    218   }
    219 };
    220 }  // namespace
    221 
    222 static Allocator GetReturnRegisters() {
    223 #ifdef GP_RETURN_REGISTERS
    224   static const Register kGPReturnRegisters[] = {GP_RETURN_REGISTERS};
    225   static const int kGPReturnRegistersCount =
    226       static_cast<int>(arraysize(kGPReturnRegisters));
    227 #else
    228   static const Register* kGPReturnRegisters = nullptr;
    229   static const int kGPReturnRegistersCount = 0;
    230 #endif
    231 
    232 #ifdef FP_RETURN_REGISTERS
    233   static const DoubleRegister kFPReturnRegisters[] = {FP_RETURN_REGISTERS};
    234   static const int kFPReturnRegistersCount =
    235       static_cast<int>(arraysize(kFPReturnRegisters));
    236 #else
    237   static const DoubleRegister* kFPReturnRegisters = nullptr;
    238   static const int kFPReturnRegistersCount = 0;
    239 #endif
    240 
    241   Allocator rets(kGPReturnRegisters, kGPReturnRegistersCount,
    242                  kFPReturnRegisters, kFPReturnRegistersCount);
    243 
    244   return rets;
    245 }
    246 
    247 static Allocator GetParameterRegisters() {
    248 #ifdef GP_PARAM_REGISTERS
    249   static const Register kGPParamRegisters[] = {GP_PARAM_REGISTERS};
    250   static const int kGPParamRegistersCount =
    251       static_cast<int>(arraysize(kGPParamRegisters));
    252 #else
    253   static const Register* kGPParamRegisters = nullptr;
    254   static const int kGPParamRegistersCount = 0;
    255 #endif
    256 
    257 #ifdef FP_PARAM_REGISTERS
    258   static const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
    259   static const int kFPParamRegistersCount =
    260       static_cast<int>(arraysize(kFPParamRegisters));
    261 #else
    262   static const DoubleRegister* kFPParamRegisters = nullptr;
    263   static const int kFPParamRegistersCount = 0;
    264 #endif
    265 
    266   Allocator params(kGPParamRegisters, kGPParamRegistersCount, kFPParamRegisters,
    267                    kFPParamRegistersCount);
    268 
    269   return params;
    270 }
    271 
    272 // General code uses the above configuration data.
    273 CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
    274                                                  FunctionSig* fsig) {
    275   MachineSignature::Builder msig(zone, fsig->return_count(),
    276                                  fsig->parameter_count());
    277   LocationSignature::Builder locations(zone, fsig->return_count(),
    278                                        fsig->parameter_count());
    279 
    280   Allocator rets = GetReturnRegisters();
    281 
    282   // Add return location(s).
    283   const int return_count = static_cast<int>(locations.return_count_);
    284   for (int i = 0; i < return_count; i++) {
    285     LocalType ret = fsig->GetReturn(i);
    286     msig.AddReturn(MachineTypeFor(ret));
    287     locations.AddReturn(rets.Next(ret));
    288   }
    289 
    290   Allocator params = GetParameterRegisters();
    291 
    292   // Add register and/or stack parameter(s).
    293   const int parameter_count = static_cast<int>(fsig->parameter_count());
    294   for (int i = 0; i < parameter_count; i++) {
    295     LocalType param = fsig->GetParam(i);
    296     msig.AddParam(MachineTypeFor(param));
    297     locations.AddParam(params.Next(param));
    298   }
    299 
    300   const RegList kCalleeSaveRegisters = 0;
    301   const RegList kCalleeSaveFPRegisters = 0;
    302 
    303   // The target for WASM calls is always a code object.
    304   MachineType target_type = MachineType::AnyTagged();
    305   LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
    306 
    307   return new (zone) CallDescriptor(       // --
    308       CallDescriptor::kCallCodeObject,    // kind
    309       target_type,                        // target MachineType
    310       target_loc,                         // target location
    311       msig.Build(),                       // machine_sig
    312       locations.Build(),                  // location_sig
    313       params.stack_offset,                // stack_parameter_count
    314       compiler::Operator::kNoProperties,  // properties
    315       kCalleeSaveRegisters,               // callee-saved registers
    316       kCalleeSaveFPRegisters,             // callee-saved fp regs
    317       CallDescriptor::kUseNativeStack,    // flags
    318       "wasm-call");
    319 }
    320 
    321 CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor(
    322     Zone* zone, CallDescriptor* descriptor) {
    323   const MachineSignature* signature = descriptor->GetMachineSignature();
    324   size_t parameter_count = signature->parameter_count();
    325   size_t return_count = signature->return_count();
    326   for (size_t i = 0; i < signature->parameter_count(); i++) {
    327     if (signature->GetParam(i) == MachineType::Int64()) {
    328       // For each int64 input we get two int32 inputs.
    329       parameter_count++;
    330     }
    331   }
    332   for (size_t i = 0; i < signature->return_count(); i++) {
    333     if (signature->GetReturn(i) == MachineType::Int64()) {
    334       // For each int64 return we get two int32 returns.
    335       return_count++;
    336     }
    337   }
    338   if (parameter_count == signature->parameter_count() &&
    339       return_count == signature->return_count()) {
    340     // If there is no int64 parameter or return value, we can just return the
    341     // original descriptor.
    342     return descriptor;
    343   }
    344 
    345   MachineSignature::Builder msig(zone, return_count, parameter_count);
    346   LocationSignature::Builder locations(zone, return_count, parameter_count);
    347 
    348   Allocator rets = GetReturnRegisters();
    349 
    350   for (size_t i = 0; i < signature->return_count(); i++) {
    351     if (signature->GetReturn(i) == MachineType::Int64()) {
    352       // For each int64 return we get two int32 returns.
    353       msig.AddReturn(MachineType::Int32());
    354       msig.AddReturn(MachineType::Int32());
    355       locations.AddReturn(rets.Next(MachineRepresentation::kWord32));
    356       locations.AddReturn(rets.Next(MachineRepresentation::kWord32));
    357     } else {
    358       msig.AddReturn(signature->GetReturn(i));
    359       locations.AddReturn(rets.Next(signature->GetReturn(i).representation()));
    360     }
    361   }
    362 
    363   Allocator params = GetParameterRegisters();
    364 
    365   for (size_t i = 0; i < signature->parameter_count(); i++) {
    366     if (signature->GetParam(i) == MachineType::Int64()) {
    367       // For each int64 input we get two int32 inputs.
    368       msig.AddParam(MachineType::Int32());
    369       msig.AddParam(MachineType::Int32());
    370       locations.AddParam(params.Next(MachineRepresentation::kWord32));
    371       locations.AddParam(params.Next(MachineRepresentation::kWord32));
    372     } else {
    373       msig.AddParam(signature->GetParam(i));
    374       locations.AddParam(params.Next(signature->GetParam(i).representation()));
    375     }
    376   }
    377 
    378   return new (zone) CallDescriptor(          // --
    379       descriptor->kind(),                    // kind
    380       descriptor->GetInputType(0),           // target MachineType
    381       descriptor->GetInputLocation(0),       // target location
    382       msig.Build(),                          // machine_sig
    383       locations.Build(),                     // location_sig
    384       params.stack_offset,                   // stack_parameter_count
    385       descriptor->properties(),              // properties
    386       descriptor->CalleeSavedRegisters(),    // callee-saved registers
    387       descriptor->CalleeSavedFPRegisters(),  // callee-saved fp regs
    388       descriptor->flags(),                   // flags
    389       descriptor->debug_name());
    390 
    391   return descriptor;
    392 }
    393 
    394 }  // namespace wasm
    395 }  // namespace internal
    396 }  // namespace v8
    397