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 
      8 #include "src/wasm/wasm-module.h"
      9 
     10 #include "src/compiler/linkage.h"
     11 
     12 #include "src/zone.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 // TODO(titzer): this should not be in the WASM namespace.
     17 namespace wasm {
     18 
     19 using compiler::LocationSignature;
     20 using compiler::CallDescriptor;
     21 using compiler::LinkageLocation;
     22 
     23 namespace {
     24 MachineType MachineTypeFor(LocalType type) {
     25   switch (type) {
     26     case kAstI32:
     27       return MachineType::Int32();
     28     case kAstI64:
     29       return MachineType::Int64();
     30     case kAstF64:
     31       return MachineType::Float64();
     32     case kAstF32:
     33       return MachineType::Float32();
     34     default:
     35       UNREACHABLE();
     36       return MachineType::AnyTagged();
     37   }
     38 }
     39 
     40 
     41 // Platform-specific configuration for C calling convention.
     42 LinkageLocation regloc(Register reg) {
     43   return LinkageLocation::ForRegister(reg.code());
     44 }
     45 
     46 
     47 LinkageLocation regloc(DoubleRegister reg) {
     48   return LinkageLocation::ForRegister(reg.code());
     49 }
     50 
     51 
     52 LinkageLocation stackloc(int i) {
     53   return LinkageLocation::ForCallerFrameSlot(i);
     54 }
     55 
     56 
     57 #if V8_TARGET_ARCH_IA32
     58 // ===========================================================================
     59 // == ia32 ===================================================================
     60 // ===========================================================================
     61 #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi, edi
     62 #define GP_RETURN_REGISTERS eax, edx
     63 #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
     64 #define FP_RETURN_REGISTERS xmm1, xmm2
     65 
     66 #elif V8_TARGET_ARCH_X64
     67 // ===========================================================================
     68 // == x64 ====================================================================
     69 // ===========================================================================
     70 #define GP_PARAM_REGISTERS rax, rdx, rcx, rbx, rsi, rdi
     71 #define GP_RETURN_REGISTERS rax, rdx
     72 #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
     73 #define FP_RETURN_REGISTERS xmm1, xmm2
     74 
     75 #elif V8_TARGET_ARCH_X87
     76 // ===========================================================================
     77 // == x87 ====================================================================
     78 // ===========================================================================
     79 #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi, edi
     80 #define GP_RETURN_REGISTERS eax, edx
     81 #define FP_RETURN_REGISTERS stX_0
     82 
     83 #elif V8_TARGET_ARCH_ARM
     84 // ===========================================================================
     85 // == arm ====================================================================
     86 // ===========================================================================
     87 #define GP_PARAM_REGISTERS r0, r1, r2, r3
     88 #define GP_RETURN_REGISTERS r0, r1
     89 #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
     90 #define FP_RETURN_REGISTERS d0, d1
     91 
     92 #elif V8_TARGET_ARCH_ARM64
     93 // ===========================================================================
     94 // == arm64 ====================================================================
     95 // ===========================================================================
     96 #define GP_PARAM_REGISTERS x0, x1, x2, x3, x4, x5, x6, x7
     97 #define GP_RETURN_REGISTERS x0, x1
     98 #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
     99 #define FP_RETURN_REGISTERS d0, d1
    100 
    101 #elif V8_TARGET_ARCH_MIPS
    102 // ===========================================================================
    103 // == mips ===================================================================
    104 // ===========================================================================
    105 #define GP_PARAM_REGISTERS a0, a1, a2, a3
    106 #define GP_RETURN_REGISTERS v0, v1
    107 #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
    108 #define FP_RETURN_REGISTERS f2, f4
    109 
    110 #elif V8_TARGET_ARCH_MIPS64
    111 // ===========================================================================
    112 // == mips64 =================================================================
    113 // ===========================================================================
    114 #define GP_PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
    115 #define GP_RETURN_REGISTERS v0, v1
    116 #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
    117 #define FP_RETURN_REGISTERS f2, f4
    118 
    119 #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
    120 // ===========================================================================
    121 // == ppc & ppc64 ============================================================
    122 // ===========================================================================
    123 #define GP_PARAM_REGISTERS r3, r4, r5, r6, r7, r8, r9, r10
    124 #define GP_RETURN_REGISTERS r3, r4
    125 #define FP_PARAM_REGISTERS d1, d2, d3, d4, d5, d6, d7, d8
    126 #define FP_RETURN_REGISTERS d1, d2
    127 
    128 #else
    129 // ===========================================================================
    130 // == unknown ================================================================
    131 // ===========================================================================
    132 // Don't define anything. We'll just always use the stack.
    133 #endif
    134 
    135 
    136 // Helper for allocating either an GP or FP reg, or the next stack slot.
    137 struct Allocator {
    138   Allocator(const Register* gp, int gpc, const DoubleRegister* fp, int fpc)
    139       : gp_count(gpc),
    140         gp_offset(0),
    141         gp_regs(gp),
    142         fp_count(fpc),
    143         fp_offset(0),
    144         fp_regs(fp),
    145         stack_offset(0) {}
    146 
    147   int gp_count;
    148   int gp_offset;
    149   const Register* gp_regs;
    150 
    151   int fp_count;
    152   int fp_offset;
    153   const DoubleRegister* fp_regs;
    154 
    155   int stack_offset;
    156 
    157   LinkageLocation Next(LocalType type) {
    158     if (IsFloatingPoint(type)) {
    159       // Allocate a floating point register/stack location.
    160       if (fp_offset < fp_count) {
    161         return regloc(fp_regs[fp_offset++]);
    162       } else {
    163         int offset = -1 - stack_offset;
    164         stack_offset += Words(type);
    165         return stackloc(offset);
    166       }
    167     } else {
    168       // Allocate a general purpose register/stack location.
    169       if (gp_offset < gp_count) {
    170         return regloc(gp_regs[gp_offset++]);
    171       } else {
    172         int offset = -1 - stack_offset;
    173         stack_offset += Words(type);
    174         return stackloc(offset);
    175       }
    176     }
    177   }
    178   bool IsFloatingPoint(LocalType type) {
    179     return type == kAstF32 || type == kAstF64;
    180   }
    181   int Words(LocalType type) {
    182     // The code generation for pushing parameters on the stack does not
    183     // distinguish between float32 and float64. Therefore also float32 needs
    184     // two words.
    185     if (kPointerSize < 8 &&
    186         (type == kAstI64 || type == kAstF64 || type == kAstF32)) {
    187       return 2;
    188     }
    189     return 1;
    190   }
    191 };
    192 }  // namespace
    193 
    194 
    195 // General code uses the above configuration data.
    196 CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
    197                                                  FunctionSig* fsig) {
    198   MachineSignature::Builder msig(zone, fsig->return_count(),
    199                                  fsig->parameter_count());
    200   LocationSignature::Builder locations(zone, fsig->return_count(),
    201                                        fsig->parameter_count());
    202 
    203 #ifdef GP_RETURN_REGISTERS
    204   static const Register kGPReturnRegisters[] = {GP_RETURN_REGISTERS};
    205   static const int kGPReturnRegistersCount =
    206       static_cast<int>(arraysize(kGPReturnRegisters));
    207 #else
    208   static const Register* kGPReturnRegisters = nullptr;
    209   static const int kGPReturnRegistersCount = 0;
    210 #endif
    211 
    212 #ifdef FP_RETURN_REGISTERS
    213   static const DoubleRegister kFPReturnRegisters[] = {FP_RETURN_REGISTERS};
    214   static const int kFPReturnRegistersCount =
    215       static_cast<int>(arraysize(kFPReturnRegisters));
    216 #else
    217   static const DoubleRegister* kFPReturnRegisters = nullptr;
    218   static const int kFPReturnRegistersCount = 0;
    219 #endif
    220 
    221   Allocator rets(kGPReturnRegisters, kGPReturnRegistersCount,
    222                  kFPReturnRegisters, kFPReturnRegistersCount);
    223 
    224   // Add return location(s).
    225   const int return_count = static_cast<int>(locations.return_count_);
    226   for (int i = 0; i < return_count; i++) {
    227     LocalType ret = fsig->GetReturn(i);
    228     msig.AddReturn(MachineTypeFor(ret));
    229     locations.AddReturn(rets.Next(ret));
    230   }
    231 
    232 #ifdef GP_PARAM_REGISTERS
    233   static const Register kGPParamRegisters[] = {GP_PARAM_REGISTERS};
    234   static const int kGPParamRegistersCount =
    235       static_cast<int>(arraysize(kGPParamRegisters));
    236 #else
    237   static const Register* kGPParamRegisters = nullptr;
    238   static const int kGPParamRegistersCount = 0;
    239 #endif
    240 
    241 #ifdef FP_PARAM_REGISTERS
    242   static const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
    243   static const int kFPParamRegistersCount =
    244       static_cast<int>(arraysize(kFPParamRegisters));
    245 #else
    246   static const DoubleRegister* kFPParamRegisters = nullptr;
    247   static const int kFPParamRegistersCount = 0;
    248 #endif
    249 
    250   Allocator params(kGPParamRegisters, kGPParamRegistersCount, kFPParamRegisters,
    251                    kFPParamRegistersCount);
    252 
    253   // Add register and/or stack parameter(s).
    254   const int parameter_count = static_cast<int>(fsig->parameter_count());
    255   for (int i = 0; i < parameter_count; i++) {
    256     LocalType param = fsig->GetParam(i);
    257     msig.AddParam(MachineTypeFor(param));
    258     locations.AddParam(params.Next(param));
    259   }
    260 
    261   const RegList kCalleeSaveRegisters = 0;
    262   const RegList kCalleeSaveFPRegisters = 0;
    263 
    264   // The target for WASM calls is always a code object.
    265   MachineType target_type = MachineType::AnyTagged();
    266   LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
    267   return new (zone) CallDescriptor(       // --
    268       CallDescriptor::kCallCodeObject,    // kind
    269       target_type,                        // target MachineType
    270       target_loc,                         // target location
    271       msig.Build(),                       // machine_sig
    272       locations.Build(),                  // location_sig
    273       params.stack_offset,                // stack_parameter_count
    274       compiler::Operator::kNoProperties,  // properties
    275       kCalleeSaveRegisters,               // callee-saved registers
    276       kCalleeSaveFPRegisters,             // callee-saved fp regs
    277       CallDescriptor::kUseNativeStack,    // flags
    278       "c-call");
    279 }
    280 }  // namespace wasm
    281 }  // namespace internal
    282 }  // namespace v8
    283