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/mips/constants-mips.h" 37#include "src/simulator.h" 38#include "test/cctest/cctest.h" 39#include "test/cctest/test-code-stubs.h" 40 41using namespace v8::internal; 42 43#define __ masm. 44 45ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, 46 Register source_reg, 47 Register destination_reg, 48 bool inline_fastpath) { 49 // Allocate an executable page of memory. 50 size_t actual_size; 51 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( 52 Assembler::kMinimalBufferSize, &actual_size, 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 __ MultiPush(kCalleeSaved | ra.bit()); 64 65 // For softfp, move the input value into f12. 66 if (IsMipsSoftFloatABI) { 67 __ Move(f12, a0, a1); 68 } 69 // Push the double argument. 70 __ Subu(sp, sp, Operand(kDoubleSize)); 71 __ sdc1(f12, MemOperand(sp)); 72 __ Move(source_reg, sp); 73 74 // Save registers make sure they don't get clobbered. 75 int source_reg_offset = kDoubleSize; 76 int reg_num = 2; 77 for (;reg_num < Register::NumAllocatableRegisters(); ++reg_num) { 78 Register reg = Register::from_code(reg_num); 79 if (!reg.is(destination_reg)) { 80 __ push(reg); 81 source_reg_offset += kPointerSize; 82 } 83 } 84 85 // Re-push the double argument. 86 __ Subu(sp, sp, Operand(kDoubleSize)); 87 __ sdc1(f12, MemOperand(sp)); 88 89 // Call through to the actual stub 90 if (inline_fastpath) { 91 __ ldc1(f12, MemOperand(source_reg)); 92 __ TryInlineTruncateDoubleToI(destination_reg, f12, &done); 93 if (destination_reg.is(source_reg) && !source_reg.is(sp)) { 94 // Restore clobbered source_reg. 95 __ Addu(source_reg, sp, Operand(source_reg_offset)); 96 } 97 } 98 __ Call(start, RelocInfo::EXTERNAL_REFERENCE); 99 __ bind(&done); 100 101 __ Addu(sp, sp, Operand(kDoubleSize)); 102 103 // Make sure no registers have been unexpectedly clobbered 104 for (--reg_num; reg_num >= 2; --reg_num) { 105 Register reg = Register::from_code(reg_num); 106 if (!reg.is(destination_reg)) { 107 __ lw(at, MemOperand(sp, 0)); 108 __ Assert(eq, kRegisterWasClobbered, reg, Operand(at)); 109 __ Addu(sp, sp, Operand(kPointerSize)); 110 } 111 } 112 113 __ Addu(sp, sp, Operand(kDoubleSize)); 114 115 __ Move(v0, destination_reg); 116 Label ok; 117 __ Branch(&ok, eq, v0, Operand(zero_reg)); 118 __ bind(&ok); 119 120 // Restore callee save registers. 121 __ MultiPop(kCalleeSaved | ra.bit()); 122 123 Label ok1; 124 __ Branch(&ok1, eq, v0, Operand(zero_reg)); 125 __ bind(&ok1); 126 __ Ret(); 127 128 CodeDesc desc; 129 masm.GetCode(&desc); 130 CpuFeatures::FlushICache(buffer, actual_size); 131 return (reinterpret_cast<ConvertDToIFunc>( 132 reinterpret_cast<intptr_t>(buffer))); 133} 134 135#undef __ 136 137 138static Isolate* GetIsolateFrom(LocalContext* context) { 139 return reinterpret_cast<Isolate*>((*context)->GetIsolate()); 140} 141 142 143int32_t RunGeneratedCodeCallWrapper(ConvertDToIFunc func, 144 double from) { 145#ifdef USE_SIMULATOR 146 Simulator::current(Isolate::Current())->CallFP(FUNCTION_ADDR(func), from, 0.); 147 return Simulator::current(Isolate::Current())->get_register(v0.code()); 148#else 149 return (*func)(from); 150#endif 151} 152 153 154TEST(ConvertDToI) { 155 CcTest::InitializeVM(); 156 LocalContext context; 157 Isolate* isolate = GetIsolateFrom(&context); 158 HandleScope scope(isolate); 159 160#if DEBUG 161 // Verify that the tests actually work with the C version. In the release 162 // code, the compiler optimizes it away because it's all constant, but does it 163 // wrong, triggering an assert on gcc. 164 RunAllTruncationTests(&ConvertDToICVersion); 165#endif 166 167 Register source_registers[] = { 168 sp, v0, v1, a0, a1, a2, a3, t0, t1, t2, t3, t4, t5}; 169 Register dest_registers[] = { 170 v0, v1, a0, a1, a2, a3, t0, t1, t2, t3, t4, t5}; 171 172 for (size_t s = 0; s < sizeof(source_registers) / sizeof(Register); s++) { 173 for (size_t d = 0; d < sizeof(dest_registers) / sizeof(Register); d++) { 174 RunAllTruncationTests( 175 RunGeneratedCodeCallWrapper, 176 MakeConvertDToIFuncTrampoline(isolate, 177 source_registers[s], 178 dest_registers[d], 179 false)); 180 RunAllTruncationTests( 181 RunGeneratedCodeCallWrapper, 182 MakeConvertDToIFuncTrampoline(isolate, 183 source_registers[s], 184 dest_registers[d], 185 true)); 186 } 187 } 188} 189