1 // Copyright 2010 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions 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 "v8.h" 29 30 #include "disassembler.h" 31 #include "factory.h" 32 #include "macro-assembler.h" 33 #include "mips/macro-assembler-mips.h" 34 #include "mips/simulator-mips.h" 35 36 #include "cctest.h" 37 38 using namespace v8::internal; 39 40 41 // Define these function prototypes to match JSEntryFunction in execution.cc. 42 typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4); 43 typedef Object* (*F2)(int x, int y, int p2, int p3, int p4); 44 typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4); 45 46 47 static v8::Persistent<v8::Context> env; 48 49 50 // The test framework does not accept flags on the command line, so we set them. 51 static void InitializeVM() { 52 // Disable compilation of natives by specifying an empty natives file. 53 FLAG_natives_file = ""; 54 55 // Enable generation of comments. 56 FLAG_debug_code = true; 57 58 if (env.IsEmpty()) { 59 env = v8::Context::New(); 60 } 61 } 62 63 64 #define __ assm. 65 66 TEST(MIPS0) { 67 InitializeVM(); 68 v8::HandleScope scope; 69 70 MacroAssembler assm(NULL, 0); 71 72 // Addition. 73 __ addu(v0, a0, a1); 74 __ jr(ra); 75 __ nop(); 76 77 CodeDesc desc; 78 assm.GetCode(&desc); 79 Object* code = Heap::CreateCode(desc, 80 NULL, 81 Code::ComputeFlags(Code::STUB), 82 Handle<Object>(Heap::undefined_value())); 83 CHECK(code->IsCode()); 84 #ifdef DEBUG 85 Code::cast(code)->Print(); 86 #endif 87 F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry()); 88 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 0xab0, 0xc, 0, 0, 0)); 89 ::printf("f() = %d\n", res); 90 CHECK_EQ(0xabc, res); 91 } 92 93 94 TEST(MIPS1) { 95 InitializeVM(); 96 v8::HandleScope scope; 97 98 MacroAssembler assm(NULL, 0); 99 Label L, C; 100 101 __ mov(a1, a0); 102 __ li(v0, 0); 103 __ b(&C); 104 __ nop(); 105 106 __ bind(&L); 107 __ add(v0, v0, a1); 108 __ addiu(a1, a1, -1); 109 110 __ bind(&C); 111 __ xori(v1, a1, 0); 112 __ Branch(ne, &L, v1, Operand(0)); 113 __ nop(); 114 115 __ jr(ra); 116 __ nop(); 117 118 CodeDesc desc; 119 assm.GetCode(&desc); 120 Object* code = Heap::CreateCode(desc, 121 NULL, 122 Code::ComputeFlags(Code::STUB), 123 Handle<Object>(Heap::undefined_value())); 124 CHECK(code->IsCode()); 125 #ifdef DEBUG 126 Code::cast(code)->Print(); 127 #endif 128 F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry()); 129 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 50, 0, 0, 0, 0)); 130 ::printf("f() = %d\n", res); 131 CHECK_EQ(1275, res); 132 } 133 134 135 TEST(MIPS2) { 136 InitializeVM(); 137 v8::HandleScope scope; 138 139 MacroAssembler assm(NULL, 0); 140 141 Label exit, error; 142 143 // ----- Test all instructions. 144 145 // Test lui, ori, and addiu, used in the li pseudo-instruction. 146 // This way we can then safely load registers with chosen values. 147 148 __ ori(t0, zero_reg, 0); 149 __ lui(t0, 0x1234); 150 __ ori(t0, t0, 0); 151 __ ori(t0, t0, 0x0f0f); 152 __ ori(t0, t0, 0xf0f0); 153 __ addiu(t1, t0, 1); 154 __ addiu(t2, t1, -0x10); 155 156 // Load values in temporary registers. 157 __ li(t0, 0x00000004); 158 __ li(t1, 0x00001234); 159 __ li(t2, 0x12345678); 160 __ li(t3, 0x7fffffff); 161 __ li(t4, 0xfffffffc); 162 __ li(t5, 0xffffedcc); 163 __ li(t6, 0xedcba988); 164 __ li(t7, 0x80000000); 165 166 // SPECIAL class. 167 __ srl(v0, t2, 8); // 0x00123456 168 __ sll(v0, v0, 11); // 0x91a2b000 169 __ sra(v0, v0, 3); // 0xf2345600 170 __ srav(v0, v0, t0); // 0xff234560 171 __ sllv(v0, v0, t0); // 0xf2345600 172 __ srlv(v0, v0, t0); // 0x0f234560 173 __ Branch(ne, &error, v0, Operand(0x0f234560)); 174 __ nop(); 175 176 __ add(v0, t0, t1); // 0x00001238 177 __ sub(v0, v0, t0); // 0x00001234 178 __ Branch(ne, &error, v0, Operand(0x00001234)); 179 __ nop(); 180 __ addu(v1, t3, t0); 181 __ Branch(ne, &error, v1, Operand(0x80000003)); 182 __ nop(); 183 __ subu(v1, t7, t0); // 0x7ffffffc 184 __ Branch(ne, &error, v1, Operand(0x7ffffffc)); 185 __ nop(); 186 187 __ and_(v0, t1, t2); // 0x00001230 188 __ or_(v0, v0, t1); // 0x00001234 189 __ xor_(v0, v0, t2); // 0x1234444c 190 __ nor(v0, v0, t2); // 0xedcba987 191 __ Branch(ne, &error, v0, Operand(0xedcba983)); 192 __ nop(); 193 194 __ slt(v0, t7, t3); 195 __ Branch(ne, &error, v0, Operand(0x1)); 196 __ nop(); 197 __ sltu(v0, t7, t3); 198 __ Branch(ne, &error, v0, Operand(0x0)); 199 __ nop(); 200 // End of SPECIAL class. 201 202 __ addi(v0, zero_reg, 0x7421); // 0x00007421 203 __ addi(v0, v0, -0x1); // 0x00007420 204 __ addiu(v0, v0, -0x20); // 0x00007400 205 __ Branch(ne, &error, v0, Operand(0x00007400)); 206 __ nop(); 207 __ addiu(v1, t3, 0x1); // 0x80000000 208 __ Branch(ne, &error, v1, Operand(0x80000000)); 209 __ nop(); 210 211 __ slti(v0, t1, 0x00002000); // 0x1 212 __ slti(v0, v0, 0xffff8000); // 0x0 213 __ Branch(ne, &error, v0, Operand(0x0)); 214 __ nop(); 215 __ sltiu(v0, t1, 0x00002000); // 0x1 216 __ sltiu(v0, v0, 0x00008000); // 0x1 217 __ Branch(ne, &error, v0, Operand(0x1)); 218 __ nop(); 219 220 __ andi(v0, t1, 0xf0f0); // 0x00001030 221 __ ori(v0, v0, 0x8a00); // 0x00009a30 222 __ xori(v0, v0, 0x83cc); // 0x000019fc 223 __ Branch(ne, &error, v0, Operand(0x000019fc)); 224 __ nop(); 225 __ lui(v1, 0x8123); // 0x81230000 226 __ Branch(ne, &error, v1, Operand(0x81230000)); 227 __ nop(); 228 229 // Everything was correctly executed. Load the expected result. 230 __ li(v0, 0x31415926); 231 __ b(&exit); 232 __ nop(); 233 234 __ bind(&error); 235 // Got an error. Return a wrong result. 236 237 __ bind(&exit); 238 __ jr(ra); 239 __ nop(); 240 241 CodeDesc desc; 242 assm.GetCode(&desc); 243 Object* code = Heap::CreateCode(desc, 244 NULL, 245 Code::ComputeFlags(Code::STUB), 246 Handle<Object>(Heap::undefined_value())); 247 CHECK(code->IsCode()); 248 #ifdef DEBUG 249 Code::cast(code)->Print(); 250 #endif 251 F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry()); 252 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 0xab0, 0xc, 0, 0, 0)); 253 ::printf("f() = %d\n", res); 254 CHECK_EQ(0x31415926, res); 255 } 256 257 #undef __ 258