Home | History | Annotate | Download | only in cctest
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Rrdistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Rrdistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Rrdistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include <stdlib.h>
     29 
     30 #include "src/v8.h"
     31 
     32 #include "src/code-stubs.h"
     33 #include "src/factory.h"
     34 #include "src/macro-assembler.h"
     35 #include "src/platform.h"
     36 #include "src/simulator.h"
     37 #include "test/cctest/cctest.h"
     38 #include "test/cctest/test-code-stubs.h"
     39 
     40 using namespace v8::internal;
     41 
     42 #define __ masm.
     43 
     44 ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
     45                                               Register source_reg,
     46                                               Register destination_reg,
     47                                               bool inline_fastpath) {
     48   // Allocate an executable page of memory.
     49   size_t actual_size;
     50   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
     51                                                  &actual_size,
     52                                                  true));
     53   CHECK(buffer);
     54   HandleScope handles(isolate);
     55   MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size));
     56   DoubleToIStub stub(isolate, source_reg, destination_reg, 0, true,
     57                      inline_fastpath);
     58 
     59   byte* start = stub.GetCode()->instruction_start();
     60   Label done;
     61 
     62   // Save callee save registers.
     63   __ Push(r7, r6, r5, r4);
     64   __ Push(lr);
     65 
     66   // For softfp, move the input value into d0.
     67   if (!masm.use_eabi_hardfloat()) {
     68     __ vmov(d0, r0, r1);
     69   }
     70   // Push the double argument.
     71   __ sub(sp, sp, Operand(kDoubleSize));
     72   __ vstr(d0, sp, 0);
     73   if (!source_reg.is(sp)) {
     74     __ mov(source_reg, sp);
     75   }
     76 
     77   // Save registers make sure they don't get clobbered.
     78   int source_reg_offset = kDoubleSize;
     79   int reg_num = 0;
     80   for (;reg_num < Register::NumAllocatableRegisters(); ++reg_num) {
     81     Register reg = Register::from_code(reg_num);
     82     if (!reg.is(destination_reg)) {
     83       __ push(reg);
     84       source_reg_offset += kPointerSize;
     85     }
     86   }
     87 
     88   // Re-push the double argument.
     89   __ sub(sp, sp, Operand(kDoubleSize));
     90   __ vstr(d0, sp, 0);
     91 
     92   // Call through to the actual stub
     93   if (inline_fastpath) {
     94     __ vldr(d0, MemOperand(source_reg));
     95     __ TryInlineTruncateDoubleToI(destination_reg, d0, &done);
     96     if (destination_reg.is(source_reg) && !source_reg.is(sp)) {
     97       // Restore clobbered source_reg.
     98       __ add(source_reg, sp, Operand(source_reg_offset));
     99     }
    100   }
    101   __ Call(start, RelocInfo::EXTERNAL_REFERENCE);
    102   __ bind(&done);
    103 
    104   __ add(sp, sp, Operand(kDoubleSize));
    105 
    106   // Make sure no registers have been unexpectedly clobbered
    107   for (--reg_num; reg_num >= 0; --reg_num) {
    108     Register reg = Register::from_code(reg_num);
    109     if (!reg.is(destination_reg)) {
    110       __ ldr(ip, MemOperand(sp, 0));
    111       __ cmp(reg, ip);
    112       __ Assert(eq, kRegisterWasClobbered);
    113       __ add(sp, sp, Operand(kPointerSize));
    114     }
    115   }
    116 
    117   __ add(sp, sp, Operand(kDoubleSize));
    118 
    119   if (!destination_reg.is(r0))
    120     __ mov(r0, destination_reg);
    121 
    122   // Restore callee save registers.
    123   __ Pop(lr);
    124   __ Pop(r7, r6, r5, r4);
    125 
    126   __ Ret(0);
    127 
    128   CodeDesc desc;
    129   masm.GetCode(&desc);
    130   CPU::FlushICache(buffer, actual_size);
    131   return (reinterpret_cast<ConvertDToIFunc>(
    132       reinterpret_cast<intptr_t>(buffer)));
    133 }
    134 
    135 #undef __
    136 
    137 
    138 static Isolate* GetIsolateFrom(LocalContext* context) {
    139   return reinterpret_cast<Isolate*>((*context)->GetIsolate());
    140 }
    141 
    142 
    143 int32_t RunGeneratedCodeCallWrapper(ConvertDToIFunc func,
    144                                     double from) {
    145 #ifdef USE_SIMULATOR
    146   return CALL_GENERATED_FP_INT(func, from, 0);
    147 #else
    148   return (*func)(from);
    149 #endif
    150 }
    151 
    152 
    153 TEST(ConvertDToI) {
    154   CcTest::InitializeVM();
    155   LocalContext context;
    156   Isolate* isolate = GetIsolateFrom(&context);
    157   HandleScope scope(isolate);
    158 
    159 #if DEBUG
    160   // Verify that the tests actually work with the C version. In the release
    161   // code, the compiler optimizes it away because it's all constant, but does it
    162   // wrong, triggering an assert on gcc.
    163   RunAllTruncationTests(&ConvertDToICVersion);
    164 #endif
    165 
    166   Register source_registers[] = {sp, r0, r1, r2, r3, r4, r5, r6, r7};
    167   Register dest_registers[] = {r0, r1, r2, r3, r4, r5, r6, r7};
    168 
    169   for (size_t s = 0; s < sizeof(source_registers) / sizeof(Register); s++) {
    170     for (size_t d = 0; d < sizeof(dest_registers) / sizeof(Register); d++) {
    171       RunAllTruncationTests(
    172           RunGeneratedCodeCallWrapper,
    173           MakeConvertDToIFuncTrampoline(isolate,
    174                                         source_registers[s],
    175                                         dest_registers[d],
    176                                         false));
    177       RunAllTruncationTests(
    178           RunGeneratedCodeCallWrapper,
    179           MakeConvertDToIFuncTrampoline(isolate,
    180                                         source_registers[s],
    181                                         dest_registers[d],
    182                                         true));
    183     }
    184   }
    185 }
    186