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/base/platform/platform.h" 33#include "src/code-stubs.h" 34#include "src/factory.h" 35#include "src/macro-assembler.h" 36#include "src/simulator.h" 37#include "test/cctest/cctest.h" 38#include "test/cctest/test-code-stubs.h" 39 40using namespace v8::internal; 41 42#define __ masm. 43 44ConvertDToIFunc 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*>(v8::base::OS::Allocate( 51 Assembler::kMinimalBufferSize, &actual_size, true)); 52 CHECK(buffer); 53 HandleScope handles(isolate); 54 MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size)); 55 DoubleToIStub stub(isolate, source_reg, destination_reg, 0, true, 56 inline_fastpath); 57 58 byte* start = stub.GetCode()->instruction_start(); 59 Label done; 60 61 // Save callee save registers. 62 __ Push(r7, r6, r5, r4); 63 __ Push(lr); 64 65 // For softfp, move the input value into d0. 66 if (!masm.use_eabi_hardfloat()) { 67 __ vmov(d0, r0, r1); 68 } 69 // Push the double argument. 70 __ sub(sp, sp, Operand(kDoubleSize)); 71 __ vstr(d0, sp, 0); 72 if (!source_reg.is(sp)) { 73 __ mov(source_reg, sp); 74 } 75 76 // Save registers make sure they don't get clobbered. 77 int source_reg_offset = kDoubleSize; 78 int reg_num = 0; 79 for (;reg_num < Register::NumAllocatableRegisters(); ++reg_num) { 80 Register reg = Register::from_code(reg_num); 81 if (!reg.is(destination_reg)) { 82 __ push(reg); 83 source_reg_offset += kPointerSize; 84 } 85 } 86 87 // Re-push the double argument. 88 __ sub(sp, sp, Operand(kDoubleSize)); 89 __ vstr(d0, sp, 0); 90 91 // Call through to the actual stub 92 if (inline_fastpath) { 93 __ vldr(d0, MemOperand(source_reg)); 94 __ TryInlineTruncateDoubleToI(destination_reg, d0, &done); 95 if (destination_reg.is(source_reg) && !source_reg.is(sp)) { 96 // Restore clobbered source_reg. 97 __ add(source_reg, sp, Operand(source_reg_offset)); 98 } 99 } 100 __ Call(start, RelocInfo::EXTERNAL_REFERENCE); 101 __ bind(&done); 102 103 __ add(sp, sp, Operand(kDoubleSize)); 104 105 // Make sure no registers have been unexpectedly clobbered 106 for (--reg_num; reg_num >= 0; --reg_num) { 107 Register reg = Register::from_code(reg_num); 108 if (!reg.is(destination_reg)) { 109 __ ldr(ip, MemOperand(sp, 0)); 110 __ cmp(reg, ip); 111 __ Assert(eq, kRegisterWasClobbered); 112 __ add(sp, sp, Operand(kPointerSize)); 113 } 114 } 115 116 __ add(sp, sp, Operand(kDoubleSize)); 117 118 if (!destination_reg.is(r0)) 119 __ mov(r0, destination_reg); 120 121 // Restore callee save registers. 122 __ Pop(lr); 123 __ Pop(r7, r6, r5, r4); 124 125 __ Ret(0); 126 127 CodeDesc desc; 128 masm.GetCode(&desc); 129 CpuFeatures::FlushICache(buffer, actual_size); 130 return (reinterpret_cast<ConvertDToIFunc>( 131 reinterpret_cast<intptr_t>(buffer))); 132} 133 134#undef __ 135 136 137static Isolate* GetIsolateFrom(LocalContext* context) { 138 return reinterpret_cast<Isolate*>((*context)->GetIsolate()); 139} 140 141 142int32_t RunGeneratedCodeCallWrapper(ConvertDToIFunc func, 143 double from) { 144#ifdef USE_SIMULATOR 145 return CALL_GENERATED_FP_INT(func, from, 0); 146#else 147 return (*func)(from); 148#endif 149} 150 151 152TEST(ConvertDToI) { 153 CcTest::InitializeVM(); 154 LocalContext context; 155 Isolate* isolate = GetIsolateFrom(&context); 156 HandleScope scope(isolate); 157 158#if DEBUG 159 // Verify that the tests actually work with the C version. In the release 160 // code, the compiler optimizes it away because it's all constant, but does it 161 // wrong, triggering an assert on gcc. 162 RunAllTruncationTests(&ConvertDToICVersion); 163#endif 164 165 Register source_registers[] = {sp, r0, r1, r2, r3, r4, r5, r6, r7}; 166 Register dest_registers[] = {r0, r1, r2, r3, r4, r5, r6, r7}; 167 168 for (size_t s = 0; s < sizeof(source_registers) / sizeof(Register); s++) { 169 for (size_t d = 0; d < sizeof(dest_registers) / sizeof(Register); d++) { 170 RunAllTruncationTests( 171 RunGeneratedCodeCallWrapper, 172 MakeConvertDToIFuncTrampoline(isolate, 173 source_registers[s], 174 dest_registers[d], 175 false)); 176 RunAllTruncationTests( 177 RunGeneratedCodeCallWrapper, 178 MakeConvertDToIFuncTrampoline(isolate, 179 source_registers[s], 180 dest_registers[d], 181 true)); 182 } 183 } 184} 185