diff options
author | Balazs Kilvady <kilvadyb@homejinni.com> | 2013-01-07 19:40:10 +0000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-05-23 13:38:48 +0200 |
commit | 9147a90a7bdf8a0791efa9d677a0f36ffdb75533 (patch) | |
tree | b5b8f2bc485afc532ab8730c482bcf9d68fd58b3 | |
parent | d7fff220c897ab0eebcd6ca8087efd4b9477beb9 (diff) | |
download | qtwebkit-9147a90a7bdf8a0791efa9d677a0f36ffdb75533.tar.gz |
MIPS LLInt implementation.
https://bugs.webkit.org/show_bug.cgi?id=99706
Patch by Balazs Kilvady <kilvadyb@homejinni.com> on 2013-01-07
Reviewed by Filip Pizlo.
LLInt implementation for MIPS.
Source/JavaScriptCore:
* assembler/MacroAssemblerMIPS.h:
(JSC::MacroAssemblerMIPS::jump):
* dfg/DFGOperations.cpp:
(JSC):
* jit/JITStubs.cpp:
(JSC):
* jit/JITStubs.h:
(JITStackFrame):
* llint/LLIntOfflineAsmConfig.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* offlineasm/backends.rb:
* offlineasm/instructions.rb:
* offlineasm/mips.rb: Added.
Source/WTF:
* wtf/Platform.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@138970 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Conflicts:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/jit/JITStubs.h
Change-Id: I1677d54c1641cf60e517772944582c8f387eeb6d
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
-rw-r--r-- | Source/JavaScriptCore/ChangeLog | 24 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h | 3 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGOperations.cpp | 69 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JITStubs.cpp | 29 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JITStubs.h | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h | 20 | ||||
-rw-r--r-- | Source/JavaScriptCore/llint/LowLevelInterpreter.asm | 12 | ||||
-rw-r--r-- | Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm | 24 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/backends.rb | 3 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/instructions.rb | 12 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/mips.rb | 867 | ||||
-rw-r--r-- | Source/WTF/ChangeLog | 11 | ||||
-rw-r--r-- | Source/WTF/wtf/Platform.h | 2 |
13 files changed, 1059 insertions, 19 deletions
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index d21e34a30..a83ef8e78 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,27 @@ +2013-01-07 Balazs Kilvady <kilvadyb@homejinni.com> + + MIPS LLInt implementation. + https://bugs.webkit.org/show_bug.cgi?id=99706 + + Reviewed by Filip Pizlo. + + LLInt implementation for MIPS. + + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::jump): + * dfg/DFGOperations.cpp: + (JSC): + * jit/JITStubs.cpp: + (JSC): + * jit/JITStubs.h: + (JITStackFrame): + * llint/LLIntOfflineAsmConfig.h: + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * offlineasm/backends.rb: + * offlineasm/instructions.rb: + * offlineasm/mips.rb: Added. + 2013-02-27 Simon Hausmann <simon.hausmann@digia.com> [Qt][Mac] Fix massive parallel builds diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h index 4f81b4599..44f94caec 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h @@ -1304,7 +1304,8 @@ public: void jump(RegisterID target) { - m_assembler.jr(target); + move(target, MIPSRegisters::t9); + m_assembler.jr(MIPSRegisters::t9); m_assembler.nop(); } diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index ad595ae1b..bb9ccc37d 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -47,6 +47,18 @@ #if ENABLE(JIT) +#if CPU(MIPS) +#if WTF_MIPS_PIC +#define LOAD_FUNCTION_TO_T9(function) \ + ".set noreorder" "\n" \ + ".cpload $25" "\n" \ + ".set reorder" "\n" \ + "la $t9, " LOCAL_REFERENCE(function) "\n" +#else +#define LOAD_FUNCTION_TO_T9(function) "" "\n" +#endif +#endif + #if ENABLE(DFG_JIT) #if COMPILER(GCC) && CPU(X86_64) @@ -201,6 +213,52 @@ "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ ); +#elif COMPILER(GCC) && CPU(MIPS) + +#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ + asm( \ + ".text" "\n" \ + ".globl " SYMBOL_STRING(function) "\n" \ + HIDE_SYMBOL(function) "\n" \ + SYMBOL_STRING(function) ":" "\n" \ + LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ + "move $a1, $ra" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ + ); + +#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ + asm( \ + ".text" "\n" \ + ".globl " SYMBOL_STRING(function) "\n" \ + HIDE_SYMBOL(function) "\n" \ + SYMBOL_STRING(function) ":" "\n" \ + LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ + "move $a3, $ra" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ + ); + +#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ + asm( \ + ".text" "\n" \ + ".globl " SYMBOL_STRING(function) "\n" \ + HIDE_SYMBOL(function) "\n" \ + SYMBOL_STRING(function) ":" "\n" \ + LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ + "sw $ra, 20($sp)" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ + ); + +#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ + asm( \ + ".text" "\n" \ + ".globl " SYMBOL_STRING(function) "\n" \ + HIDE_SYMBOL(function) "\n" \ + SYMBOL_STRING(function) ":" "\n" \ + LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ + "sw $ra, 24($sp)" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ + ); + #endif #define P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ @@ -1607,6 +1665,17 @@ SYMBOL_STRING(getHostCallReturnValue) ":" "\n" "mov r0, r5" "\n" "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); +#elif COMPILER(GCC) && CPU(MIPS) +asm( +".text" "\n" +".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" +HIDE_SYMBOL(getHostCallReturnValue) "\n" +SYMBOL_STRING(getHostCallReturnValue) ":" "\n" + LOAD_FUNCTION_TO_T9(getHostCallReturnValueWithExecState) + "lw $s0, -40($s0)" "\n" + "move $a0, $s0" "\n" + "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" +); #endif extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState* exec) diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index 64acfeef5..168769c12 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -280,11 +280,13 @@ extern "C" { #define PRESERVED_S0_OFFSET 64 #define PRESERVED_S1_OFFSET 68 #define PRESERVED_S2_OFFSET 72 -#define PRESERVED_RETURN_ADDRESS_OFFSET 76 -#define THUNK_RETURN_ADDRESS_OFFSET 80 -#define REGISTER_FILE_OFFSET 84 -#define GLOBAL_DATA_OFFSET 100 -#define STACK_LENGTH 104 +#define PRESERVED_S3_OFFSET 76 +#define PRESERVED_S4_OFFSET 80 +#define PRESERVED_RETURN_ADDRESS_OFFSET 84 +#define THUNK_RETURN_ADDRESS_OFFSET 88 +#define REGISTER_FILE_OFFSET 92 +#define GLOBAL_DATA_OFFSET 108 +#define STACK_LENGTH 112 #elif CPU(SH4) #define SYMBOL_STRING(name) #name /* code (r4), JSStack* (r5), CallFrame* (r6), void* unused1 (r7), void* unused2(sp), JSGlobalData (sp)*/ @@ -527,6 +529,8 @@ asm ( SYMBOL_STRING(ctiTrampoline) ":" "\n" "addiu $29,$29,-" STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" "sw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" + "sw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n" + "sw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" "sw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" "sw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" "sw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" @@ -543,12 +547,17 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" + "lw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" + "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n" "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" "jr $31" "\n" "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" ".set reorder" "\n" ".set macro" "\n" ".end " SYMBOL_STRING(ctiTrampoline) "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); asm ( @@ -561,8 +570,8 @@ asm ( ".ent " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" #if WTF_MIPS_PIC - "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" ".set macro" "\n" +".cpload $31" "\n" "la $25," SYMBOL_STRING(cti_vm_throw) "\n" ".set nomacro" "\n" "bal " SYMBOL_STRING(cti_vm_throw) "\n" @@ -574,6 +583,8 @@ SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" + "lw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" + "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n" "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" "jr $31" "\n" "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" @@ -594,6 +605,8 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" + "lw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" + "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n" "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" "jr $31" "\n" "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" @@ -1194,9 +1207,9 @@ template<typename T> static T throwExceptionFromOpCall(JITStackFrame& jitStackFr ".globl " SYMBOL_STRING(cti_##op) "\n" \ ".ent " SYMBOL_STRING(cti_##op) "\n" \ SYMBOL_STRING(cti_##op) ":" "\n" \ - "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" \ - "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ ".set macro" "\n" \ + ".cpload $25" "\n" \ + "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ "la $25," SYMBOL_STRING(JITStubThunked_##op) "\n" \ ".set nomacro" "\n" \ ".reloc 1f,R_MIPS_JALR," SYMBOL_STRING(JITStubThunked_##op) "\n" \ diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h index fe64cd9bc..c03bc929e 100644 --- a/Source/JavaScriptCore/jit/JITStubs.h +++ b/Source/JavaScriptCore/jit/JITStubs.h @@ -256,6 +256,8 @@ namespace JSC { void* preservedS0; void* preservedS1; void* preservedS2; + void* preservedS3; + void* preservedS4; void* preservedReturnAddress; ReturnAddressPtr thunkReturnAddress; diff --git a/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h b/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h index da2d510b5..157521373 100644 --- a/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h +++ b/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h @@ -38,6 +38,7 @@ #define OFFLINE_ASM_ARMv7 0 #define OFFLINE_ASM_X86_64 0 #define OFFLINE_ASM_ARMv7s 0 +#define OFFLINE_ASM_MIPS 0 #else // !ENABLE(LLINT_C_LOOP) @@ -67,6 +68,12 @@ #define OFFLINE_ASM_X86_64 0 #endif +#if CPU(MIPS) +#define OFFLINE_ASM_MIPS 1 +#else +#define OFFLINE_ASM_MIPS 0 +#endif + #endif // !ENABLE(LLINT_C_LOOP) #if USE(JSVALUE64) @@ -111,4 +118,17 @@ #define OFFLINE_ASM_VALUE_PROFILER 0 #endif +#if CPU(MIPS) +#ifdef WTF_MIPS_PIC +#define S(x) #x +#define SX(x) S(x) +#define OFFLINE_ASM_CPLOAD(reg) \ + ".set noreorder\n" \ + ".cpload " SX(reg) "\n" \ + ".set reorder\n" +#else +#define OFFLINE_ASM_CPLOAD(reg) +#endif +#endif + #endif // LLIntOfflineAsmConfig_h diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm index 00d5c4f6f..9de48f1f6 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm @@ -182,10 +182,8 @@ macro assert(assertion) end macro preserveReturnAddressAfterCall(destinationRegister) - if C_LOOP - # In our case, we're only preserving the bytecode vPC. - move lr, destinationRegister - elsif ARMv7 + if C_LOOP or ARMv7 or MIPS + # In C_LOOP case, we're only preserving the bytecode vPC. move lr, destinationRegister elsif X86 or X86_64 pop destinationRegister @@ -195,10 +193,8 @@ macro preserveReturnAddressAfterCall(destinationRegister) end macro restoreReturnAddressBeforeReturn(sourceRegister) - if C_LOOP - # In our case, we're only restoring the bytecode vPC. - move sourceRegister, lr - elsif ARMv7 + if C_LOOP or ARMv7 or MIPS + # In C_LOOP case, we're only restoring the bytecode vPC. move sourceRegister, lr elsif X86 or X86_64 push sourceRegister diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index 8d5cdf108..9a17985bc 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -113,6 +113,10 @@ macro cCall2(function, arg1, arg2) poke arg1, 0 poke arg2, 1 call function + elsif MIPS + move arg1, a0 + move arg2, a1 + call function elsif C_LOOP cloopCallSlowPath function, arg1, arg2 else @@ -134,6 +138,12 @@ macro cCall4(function, arg1, arg2, arg3, arg4) poke arg3, 2 poke arg4, 3 call function + elsif MIPS + move arg1, a0 + move arg2, a1 + move arg3, a2 + move arg4, a3 + call function elsif C_LOOP error else @@ -1818,6 +1828,20 @@ macro nativeCallTrampoline(executableOffsetToFunction) call executableOffsetToFunction[t1] restoreReturnAddressBeforeReturn(t3) loadp JITStackFrame::globalData[sp], t3 + elsif MIPS + loadp JITStackFrame::globalData[sp], t3 + storep cfr, JSGlobalData::topCallFrame[t3] + move t0, t2 + preserveReturnAddressAfterCall(t3) + storep t3, ReturnPC[cfr] + move cfr, t0 + loadi Callee + PayloadOffset[cfr], t1 + loadp JSFunction::m_executable[t1], t1 + move t2, cfr + move t0, a0 + call executableOffsetToFunction[t1] + restoreReturnAddressBeforeReturn(t3) + loadp JITStackFrame::globalData[sp], t3 elsif C_LOOP loadp JITStackFrame::globalData[sp], t3 storep cfr, JSGlobalData::topCallFrame[t3] diff --git a/Source/JavaScriptCore/offlineasm/backends.rb b/Source/JavaScriptCore/offlineasm/backends.rb index 78e545738..ef9358c0b 100644 --- a/Source/JavaScriptCore/offlineasm/backends.rb +++ b/Source/JavaScriptCore/offlineasm/backends.rb @@ -25,6 +25,7 @@ require "config" require "armv7" require "ast" require "x86" +require "mips" require "cloop" BACKENDS = @@ -32,6 +33,7 @@ BACKENDS = "X86", "X86_64", "ARMv7", + "MIPS", "C_LOOP" ] @@ -45,6 +47,7 @@ WORKING_BACKENDS = "X86", "X86_64", "ARMv7", + "MIPS", "C_LOOP" ] diff --git a/Source/JavaScriptCore/offlineasm/instructions.rb b/Source/JavaScriptCore/offlineasm/instructions.rb index e047b2a16..4e70625c2 100644 --- a/Source/JavaScriptCore/offlineasm/instructions.rb +++ b/Source/JavaScriptCore/offlineasm/instructions.rb @@ -265,6 +265,16 @@ ARMv7_INSTRUCTIONS = "oris" ] +MIPS_INSTRUCTIONS = + [ + "movz", + "movn", + "slt", + "sltu", + "pichdr", + "pichdrra" + ] + CXX_INSTRUCTIONS = [ "cloopCrash", # no operands @@ -281,7 +291,7 @@ CXX_INSTRUCTIONS = "cloopDo", # no operands ] -INSTRUCTIONS = MACRO_INSTRUCTIONS + X86_INSTRUCTIONS + ARMv7_INSTRUCTIONS + CXX_INSTRUCTIONS +INSTRUCTIONS = MACRO_INSTRUCTIONS + X86_INSTRUCTIONS + ARMv7_INSTRUCTIONS + MIPS_INSTRUCTIONS + CXX_INSTRUCTIONS INSTRUCTION_PATTERN = Regexp.new('\\A((' + INSTRUCTIONS.join(')|(') + '))\\Z') diff --git a/Source/JavaScriptCore/offlineasm/mips.rb b/Source/JavaScriptCore/offlineasm/mips.rb new file mode 100644 index 000000000..80aa4fec7 --- /dev/null +++ b/Source/JavaScriptCore/offlineasm/mips.rb @@ -0,0 +1,867 @@ +# Copyright (C) 2012 Apple Inc. All rights reserved. +# Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'risc' + +class Assembler + def putStr(str) + @outp.puts str + end +end + +class Node + def mipsSingleHi + doubleOperand = mipsOperand + raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/ + "$f" + ($~.post_match.to_i + 1).to_s + end + def mipsSingleLo + doubleOperand = mipsOperand + raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/ + doubleOperand + end +end + +class SpecialRegister < NoChildren + def mipsOperand + @name + end + + def dump + @name + end + + def register? + true + end +end + +MIPS_TEMP_GPRS = [SpecialRegister.new("$t5"), SpecialRegister.new("$t6"), SpecialRegister.new("$t7"), + SpecialRegister.new("$t8")] +MIPS_ZERO_REG = SpecialRegister.new("$zero") +MIPS_GP_REG = SpecialRegister.new("$gp") +MIPS_GPSAVE_REG = SpecialRegister.new("$s4") +MIPS_JUMP_REG = SpecialRegister.new("$ra") +MIPS_CALL_REG = SpecialRegister.new("$t9") +MIPS_TEMP_FPRS = [SpecialRegister.new("$f16")] +MIPS_SCRATCH_FPR = SpecialRegister.new("$f18") + +def mipsMoveImmediate(value, register) + if value == 0 + $asm.puts "add #{register.mipsOperand}, $zero, $zero" + else + $asm.puts "li #{register.mipsOperand}, #{value}" + end +end + +class RegisterID + def mipsOperand + case name + when "a0" + "$a0" + when "a1" + "$a1" + when "r0", "t0" + "$v0" + when "r1", "t1" + "$v1" + when "t2" + "$t2" + when "t3" + "$s3" + when "t4" # PC reg in llint + "$s2" + when "t5" + "$t5" + when "t6" + "$t6" + when "t7" + "$t7" + when "t8" + "$t8" + when "cfr" + "$s0" + when "lr" + "$ra" + when "sp" + "$sp" + else + raise "Bad register #{name} for MIPS at #{codeOriginString}" + end + end +end + +class FPRegisterID + def mipsOperand + case name + when "ft0", "fr" + "$f0" + when "ft1" + "$f2" + when "ft2" + "$f4" + when "ft3" + "$f6" + when "ft4" + "$f8" + when "ft5" + "$f10" + when "fa0" + "$f12" + when "fa1" + "$f14" + else + raise "Bad register #{name} for MIPS at #{codeOriginString}" + end + end +end + +class Immediate + def mipsOperand + raise "Invalid immediate #{value} at #{codeOriginString}" if value < -0x7fff or value > 0x7fff + "#{value}" + end +end + +class Address + def mipsOperand + raise "Bad offset at #{codeOriginString}" if offset.value < -0x7fff or offset.value > 0x7fff + "#{offset.value}(#{base.mipsOperand})" + end +end + +class AbsoluteAddress + def mipsOperand + raise "Unconverted absolute address at #{codeOriginString}" + end +end + +# +# Lower 'and' masked branches +# + +def lowerMIPSCondBranch(list, condOp, node) + if node.operands.size == 2 + list << Instruction.new(node.codeOrigin, + condOp, + [node.operands[0], MIPS_ZERO_REG, node.operands[-1]], + node.annotation) + elsif node.operands.size == 3 + tmp = Tmp.new(node.codeOrigin, :gpr) + list << Instruction.new(node.codeOrigin, + "andi", + [node.operands[0], node.operands[1], tmp], + node.annotation) + list << Instruction.new(node.codeOrigin, + condOp, + [tmp, MIPS_ZERO_REG, node.operands[-1]]) + else + raise "Expected 2 or 3 operands but got #{node.operands.size} at #{node.codeOriginString}" + end +end + +# +# Lowering of branch ops. For example: +# +# baddiz foo, bar, baz +# +# will become: +# +# addi foo, bar +# bz baz +# + +def mipsLowerSimpleBranchOps(list) + newList = [] + list.each { + | node | + if node.is_a? Instruction + annotation = node.annotation + case node.opcode + when /^b(addi|subi|ori|addp)/ + op = $1 + bc = $~.post_match + branch = "b" + bc + + case op + when "addi", "addp" + op = "addi" + when "subi" + op = "subi" + when "ori" + op = "ori" + end + + if bc == "o" + case op + when "addi" + # addu $s0, $s1, $s2 + # xor $t0, $s1, $s2 + # blt $t0, $zero, no overflow + # xor $t0, $s0, $s1 + # blt $t0, $zero, overflow + # no overflow: + # + tr = Tmp.new(node.codeOrigin, :gpr) + tmp = Tmp.new(node.codeOrigin, :gpr) + noFlow = LocalLabel.unique("noflow") + noFlowRef = LocalLabelReference.new(node.codeOrigin, noFlow) + newList << Instruction.new(node.codeOrigin, op, [node.operands[0], node.operands[1], tr], annotation) + newList << Instruction.new(node.codeOrigin, "xori", [node.operands[0], node.operands[1], tmp]) + newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, noFlowRef]) + newList << Instruction.new(node.codeOrigin, "xori", [tr, node.operands[0], tmp]) + newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, node.operands[2]]) + newList << noFlow + newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]]) + when "subi" + # subu $s0, $s1, $s2 + # xor $t0, $s1, $s2 + # bge $t0, $zero, no overflow + # xor $t0, $s0, $s1 + # blt $t0, $zero, overflow + # no overflow: + # + tr = Tmp.new(node.codeOrigin, :gpr) + tmp = Tmp.new(node.codeOrigin, :gpr) + noFlow = LocalLabel.unique("noflow") + noFlowRef = LocalLabelReference.new(node.codeOrigin, noFlow) + newList << Instruction.new(node.codeOrigin, op, [node.operands[1], node.operands[0], tr], annotation) + newList << Instruction.new(node.codeOrigin, "xori", [node.operands[1], node.operands[0], tmp]) + newList << Instruction.new(node.codeOrigin, "bigteq", [tmp, MIPS_ZERO_REG, noFlowRef]) + newList << Instruction.new(node.codeOrigin, "xori", [tr, node.operands[1], tmp]) + newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, node.operands[2]]) + newList << noFlow + newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]]) + when "ori" + # no ovwerflow at ori + newList << Instruction.new(node.codeOrigin, op, node.operands[0..1], annotation) + end + else + if node.operands[1].is_a? Address + addr = node.operands[1] + tr = Tmp.new(node.codeOrigin, :gpr) + newList << Instruction.new(node.codeOrigin, "loadp", [addr, tr], annotation) + newList << Instruction.new(node.codeOrigin, op, [node.operands[0], tr]) + newList << Instruction.new(node.codeOrigin, "storep", [tr, addr]) + else + tr = node.operands[1] + newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation) + end + newList << Instruction.new(node.codeOrigin, branch, [tr, MIPS_ZERO_REG, node.operands[-1]]) + end + when "bia", "bpa", "bba" + tmp = Tmp.new(node.codeOrigin, :gpr) + comp = node.opcode[1] == ?b ? "sltub" : "sltu" + newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[1], node.operands[0]], annotation) + newList << Instruction.new(node.codeOrigin, "bnz", [tmp, MIPS_ZERO_REG, node.operands[2]]) + when "biaeq", "bpaeq", "bbaeq" + tmp = Tmp.new(node.codeOrigin, :gpr) + comp = node.opcode[1] == ?b ? "sltub" : "sltu" + newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[0], node.operands[1]], annotation) + newList << Instruction.new(node.codeOrigin, "bz", [tmp, MIPS_ZERO_REG, node.operands[2]]) + when "bib", "bpb", "bbb" + tmp = Tmp.new(node.codeOrigin, :gpr) + comp = node.opcode[1] == ?b ? "sltub" : "sltu" + newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[0], node.operands[1]], annotation) + newList << Instruction.new(node.codeOrigin, "bnz", [tmp, MIPS_ZERO_REG, node.operands[2]]) + when "bibeq", "bpbeq", "bbbeq" + tmp = Tmp.new(node.codeOrigin, :gpr) + comp = node.opcode[1] == ?b ? "sltub" : "sltu" + newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[1], node.operands[0]], annotation) + newList << Instruction.new(node.codeOrigin, "bz", [tmp, MIPS_ZERO_REG, node.operands[2]]) + when "btiz", "btpz", "btbz" + lowerMIPSCondBranch(newList, "bz", node) + when "btinz", "btpnz", "btbnz" + lowerMIPSCondBranch(newList, "bnz", node) + when "btio", "btpo", "btbo" + newList << node + when "btis", "btps", "btbs" + lowerMIPSCondBranch(newList, "bs", node) + else + newList << node + end + else + newList << node + end + } + newList +end + +# +# Specialization of lowering of malformed BaseIndex addresses. +# + +class BaseIndex + def riscLowerMalformedAddressesRecurse(list, node, &block) + if scaleShift == 0 + tmp0 = Tmp.new(codeOrigin, :gpr) + list << Instruction.new(codeOrigin, "addp", [base, index, tmp0]) + Address.new(codeOrigin, tmp0, Immediate.new(codeOrigin, offset.value)); + else + tmp0 = Tmp.new(codeOrigin, :gpr) + list << Instruction.new(codeOrigin, "lshifti", [index, Immediate.new(codeOrigin, scaleShift), tmp0]); + list << Instruction.new(codeOrigin, "addp", [base, tmp0]) + Address.new(codeOrigin, tmp0, Immediate.new(codeOrigin, offset.value)); + end + end +end + +# +# Lowering of misplaced immediates of MIPS specific instructions. For example: +# +# sltu reg, 4, 2 +# +# will become: +# +# move 4, tmp +# sltu reg, tmp, 2 +# + +def mipsLowerMisplacedImmediates(list) + newList = [] + list.each { + | node | + if node.is_a? Instruction + case node.opcode + when "slt", "sltu", "sltb", "sltub" + if node.operands[1].is_a? Immediate + tmp = Tmp.new(node.codeOrigin, :gpr) + newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp], node.annotation) + newList << Instruction.new(node.codeOrigin, node.opcode, + [node.operands[0], tmp, node.operands[2]], + node.annotation) + else + newList << node + end + else + newList << node + end + else + newList << node + end + } + newList +end + +# +# Specialization of lowering of misplaced addresses. +# + +def mipsLowerMisplacedAddresses(list) + newList = [] + list.each { + | node | + if node.is_a? Instruction + postInstructions = [] + annotation = node.annotation + case node.opcode + when "jmp" + if node.operands[0].address? + newList << Instruction.new(node.operands[0].codeOrigin, "loadi", [node.operands[0], MIPS_JUMP_REG]) + newList << Instruction.new(node.codeOrigin, node.opcode, [MIPS_JUMP_REG]) + else + newList << Instruction.new(node.codeOrigin, + node.opcode, + [riscAsRegister(newList, postInstructions, node.operands[0], "p", false)]) + end + when "call" + restoreGP = false; + tmp = MIPS_CALL_REG + if node.operands[0].address? + newList << Instruction.new(node.operands[0].codeOrigin, "loadp", [node.operands[0], MIPS_CALL_REG]) + restoreGP = true; + elsif node.operands[0].is_a? LabelReference + tmp = node.operands[0] + restoreGP = true; + elsif node.operands[0].register? + newList << Instruction.new(node.operands[0].codeOrigin, "move", [node.operands[0], MIPS_CALL_REG]) + restoreGP = true; + else + tmp = node.operands[0] + end + newList << Instruction.new(node.codeOrigin, node.opcode, [tmp]) + if restoreGP + newList << Instruction.new(node.codeOrigin, "move", [MIPS_GPSAVE_REG, MIPS_GP_REG]) + end + when "slt", "sltu" + newList << Instruction.new(node.codeOrigin, + node.opcode, + riscAsRegisters(newList, [], node.operands, "i")) + when "sltub", "sltb" + newList << Instruction.new(node.codeOrigin, + node.opcode, + riscAsRegisters(newList, [], node.operands, "b")) + when "bz", "bnz", "bs", "bo" + newList << Instruction.new(node.codeOrigin, + node.opcode, + riscAsRegisters(newList, [], node.operands, "i")) + else + newList << node + end + newList += postInstructions + else + newList << node + end + } + newList +end + +# +# Lowering compares and tests. +# + +def mipsLowerCompareTemplate(list, node, opCmp, opMov) + tmp0 = Tmp.new(node.codeOrigin, :gpr) + tmp1 = Tmp.new(node.codeOrigin, :gpr) + list << Instruction.new(node.codeOrigin, "move", [Immediate.new(nil, 0), node.operands[2]]) + list << Instruction.new(node.codeOrigin, opCmp, [node.operands[1], node.operands[0], tmp0]) + list << Instruction.new(node.codeOrigin, "move", [Immediate.new(nil, 1), tmp1]) + list << Instruction.new(node.codeOrigin, opMov, [node.operands[2], tmp1, tmp0]) +end + +def mipsLowerCompares(list) + newList = [] + list.each { + | node | + if node.is_a? Instruction + case node.opcode + when "cieq", "cpeq", "cbeq" + mipsLowerCompareTemplate(newList, node, "subp", "movz") + when "cineq", "cpneq", "cbneq" + mipsLowerCompareTemplate(newList, node, "subp", "movn") + when "tiz", "tbz", "tpz" + mipsLowerCompareTemplate(newList, node, "andp", "movz") + when "tinz", "tbnz", "tpnz" + mipsLowerCompareTemplate(newList, node, "andp", "movn") + when "tio", "tbo", "tpo" + tmp = Tmp.new(node.codeOrigin, :gpr) + list << Instruction.new(node.codeOrigin, "andp", [node.operands[1], node.operands[0], tmp]) + list << Instruction.new(node.codeOrigin, "slt", [node.operands[2], MIPS_ZERO_REG, tmp]) + when "tis", "tbs", "tps" + tmp = Tmp.new(node.codeOrigin, :gpr) + list << Instruction.new(node.codeOrigin, "andp", [node.operands[1], node.operands[0], tmp]) + list << Instruction.new(node.codeOrigin, "slt", [node.operands[2], tmp, MIPS_ZERO_REG]) + else + newList << node + end + else + newList << node + end + } + newList +end + +# +# Lea support. +# + +class Address + def mipsEmitLea(destination) + if destination == base + $asm.puts "addiu #{destination.mipsOperand}, #{offset.value}" + else + $asm.puts "addiu #{destination.mipsOperand}, #{base.mipsOperand}, #{offset.value}" + end + end +end + +# +# Add PIC compatible header code to prologue/entry rutins. +# + +def mipsAddPICCode(list) + myList = [] + list.each { + | node | + myList << node + if node.is_a? Label + if /_prologue$/.match(node.name) || /^_llint_function_/.match(node.name) + # Functions called from trampoline/JIT codes. + myList << Instruction.new(node.codeOrigin, "pichdr", []) + elsif /_llint_op_catch/.match(node.name) + # Exception cactcher entry point function. + myList << Instruction.new(node.codeOrigin, "pichdrra", []) + end + end + } + myList +end + +# +# Actual lowering code follows. +# + +class Sequence + def getModifiedListMIPS + result = @list + + # Verify that we will only see instructions and labels. + result.each { + | node | + unless node.is_a? Instruction or + node.is_a? Label or + node.is_a? LocalLabel or + node.is_a? Skip + raise "Unexpected #{node.inspect} at #{node.codeOrigin}" + end + } + + result = mipsAddPICCode(result) + result = mipsLowerSimpleBranchOps(result) + result = riscLowerSimpleBranchOps(result) + result = riscLowerHardBranchOps(result) + result = riscLowerShiftOps(result) + result = riscLowerMalformedAddresses(result) { + | node, address | + if address.is_a? Address + (-0xffff..0xffff).include? address.offset.value + else + false + end + } + result = riscLowerMalformedAddressesDouble(result) + result = riscLowerMisplacedImmediates(result) + result = mipsLowerMisplacedImmediates(result) + result = riscLowerMalformedImmediates(result, -0xffff..0xffff) + result = mipsLowerMisplacedAddresses(result) + result = riscLowerMisplacedAddresses(result) + result = riscLowerRegisterReuse(result) + result = mipsLowerCompares(result) + result = assignRegistersToTemporaries(result, :gpr, MIPS_TEMP_GPRS) + result = assignRegistersToTemporaries(result, :fpr, MIPS_TEMP_FPRS) + + return result + end +end + +def mipsOperands(operands) + operands.map{|v| v.mipsOperand}.join(", ") +end + +def mipsFlippedOperands(operands) + mipsOperands([operands[-1]] + operands[0..-2]) +end + +def getMIPSOpcode(opcode, suffix) + +end + +def emitMIPSCompact(opcode, opcodei, operands) + postfix = "" + if opcode == "sub" + if operands[0].is_a? Immediate + opcode = "add" + operands[0] = Immediate.new(operands[0].codeOrigin, -1 * operands[0].value) + elsif operands[1].is_a? Immediate + opcode = "add" + operands[1] = Immediate.new(operands[1].codeOrigin, -1 * operands[1].value) + end + postfix = "u" + elsif opcode == "add" + postfix = "u" + end + if operands.size == 3 + if operands[0].is_a? Immediate + $asm.puts "#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}" + elsif operands[1].is_a? Immediate + $asm.puts "#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}" + else + $asm.puts "#{opcode}#{postfix} #{mipsFlippedOperands(operands)}" + end + else + raise unless operands.size == 2 + raise unless operands[1].register? + if operands[0].is_a? Immediate + $asm.puts "#{opcode}i#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + else + $asm.puts "#{opcode}#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + end + end +end + +def emitMIPSShiftCompact(opcode, operands) + if operands.size == 3 + if (operands[1].is_a? Immediate) + $asm.puts "#{opcode} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}" + else + $asm.puts "#{opcode}v #{mipsFlippedOperands(operands)}" + end + else + raise unless operands.size == 2 + if operands[0].register? + $asm.puts "#{opcode}v #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + else + $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}" + end + end +end + +def emitMIPS(opcode, operands) + if operands.size == 3 + $asm.puts "#{opcode} #{mipsFlippedOperands(operands)}" + else + raise unless operands.size == 2 + $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + end +end + +def emitMIPSDoubleBranch(branchOpcode, neg, operands) + $asm.puts "c.#{branchOpcode}.d #{mipsOperands(operands[0..1])}" + if (!neg) + $asm.puts "bc1t #{operands[2].asmLabel}" + else + $asm.puts "bc1f #{operands[2].asmLabel}" + end +end + +class Instruction + def lowerMIPS + $asm.comment codeOriginString + case opcode + when "addi", "addp", "addis" + if operands.size == 3 and operands[0].is_a? Immediate + raise unless operands[1].register? + raise unless operands[2].register? + if operands[0].value == 0 #and suffix.empty? + unless operands[1] == operands[2] + $asm.puts "move #{operands[2].mipsOperand}, #{operands[1].mipsOperand}" + end + else + $asm.puts "addiu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + end + elsif operands.size == 3 and operands[0].register? + raise unless operands[1].register? + raise unless operands[2].register? + $asm.puts "addu #{mipsFlippedOperands(operands)}" + else + if operands[0].is_a? Immediate + unless Immediate.new(nil, 0) == operands[0] + $asm.puts "addiu #{operands[1].mipsOperand}, #{mipsFlippedOperands(operands)}" + end + else + $asm.puts "addu #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + end + end + when "andi", "andp" + emitMIPSCompact("and", "and", operands) + when "ori", "orp" + emitMIPSCompact("or", "orr", operands) + when "oris" + emitMIPSCompact("or", "orrs", operands) + when "xori", "xorp" + emitMIPSCompact("xor", "eor", operands) + when "lshifti", "lshiftp" + emitMIPSShiftCompact("sll", operands) + when "rshifti", "rshiftp" + emitMIPSShiftCompact("sra", operands) + when "urshifti", "urshiftp" + emitMIPSShiftCompact("srl", operands) + when "muli", "mulp" + emitMIPS("mul", operands) + when "subi", "subp", "subis" + emitMIPSCompact("sub", "subs", operands) + when "negi", "negp" + $asm.puts "negu #{operands[0].mipsOperand}, #{operands[0].mipsOperand}" + when "noti" + $asm.puts "nor #{operands[0].mipsOperand}, #{operands[0].mipsOperand}, $zero" + when "loadi", "loadis", "loadp" + $asm.puts "lw #{mipsFlippedOperands(operands)}" + when "storei", "storep" + $asm.puts "sw #{mipsOperands(operands)}" + when "loadb" + $asm.puts "lbu #{mipsFlippedOperands(operands)}" + when "loadbs" + $asm.puts "lb #{mipsFlippedOperands(operands)}" + when "storeb" + $asm.puts "sb #{mipsOperands(operands)}" + when "loadh" + $asm.puts "lhu #{mipsFlippedOperands(operands)}" + when "loadhs" + $asm.puts "lh #{mipsFlippedOperands(operands)}" + when "storeh" + $asm.puts "shv #{mipsOperands(operands)}" + when "loadd" + $asm.puts "ldc1 #{mipsFlippedOperands(operands)}" + when "stored" + $asm.puts "sdc1 #{mipsOperands(operands)}" + when "addd" + emitMIPS("add.d", operands) + when "divd" + emitMIPS("div.d", operands) + when "subd" + emitMIPS("sub.d", operands) + when "muld" + emitMIPS("mul.d", operands) + when "sqrtd" + $asm.puts "sqrt.d #{mipsFlippedOperands(operands)}" + when "ci2d" + raise "invalid ops of #{self.inspect} at #{codeOriginString}" unless operands[1].is_a? FPRegisterID and operands[0].register? + $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + $asm.puts "cvt.d.w #{operands[1].mipsOperand}, #{operands[1].mipsOperand}" + when "bdeq" + emitMIPSDoubleBranch("eq", false, operands) + when "bdneq" + emitMIPSDoubleBranch("ueq", true, operands) + when "bdgt" + emitMIPSDoubleBranch("ule", true, operands) + when "bdgteq" + emitMIPSDoubleBranch("ult", true, operands) + when "bdlt" + emitMIPSDoubleBranch("olt", false, operands) + when "bdlteq" + emitMIPSDoubleBranch("ole", false, operands) + when "bdequn" + emitMIPSDoubleBranch("ueq", false, operands) + when "bdnequn" + emitMIPSDoubleBranch("eq", true, operands) + when "bdgtun" + emitMIPSDoubleBranch("ole", true, operands) + when "bdgtequn" + emitMIPSDoubleBranch("olt", true, operands) + when "bdltun" + emitMIPSDoubleBranch("ult", false, operands) + when "bdltequn" + emitMIPSDoubleBranch("ule", false, operands) + when "btd2i" + # FIXME: may be a good idea to just get rid of this instruction, since the interpreter + # currently does not use it. + raise "MIPS does not support this opcode yet, #{codeOrigin}" + when "td2i" + $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}" + $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}" + when "bcd2i" + $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}" + $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}" + $asm.puts "cvt.d.w #{MIPS_SCRATCH_FPR.mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}" + emitMIPSDoubleBranch("eq", true, [MIPS_SCRATCH_FPR, operands[0], operands[2]]) + $asm.puts "beq #{operands[1].mipsOperand}, $zero, #{operands[2].asmLabel}" + when "movdz" + # FIXME: either support this or remove it. + raise "MIPS does not support this opcode yet, #{codeOrigin}" + when "pop" + $asm.puts "lw #{operands[0].mipsOperand}, 0($sp)" + $asm.puts "addiu $sp, $sp, 4" + when "push" + $asm.puts "addiu $sp, $sp, -4" + $asm.puts "sw #{operands[0].mipsOperand}, 0($sp)" + when "move", "sxi2p", "zxi2p" + if operands[0].is_a? Immediate + mipsMoveImmediate(operands[0].value, operands[1]) + else + $asm.puts "move #{mipsFlippedOperands(operands)}" + end + when "nop" + $asm.puts "nop" + when "bieq", "bpeq", "bbeq" + $asm.puts "beq #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "bineq", "bpneq", "bbneq" + $asm.puts "bne #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "bigt", "bpgt", "bbgt" + $asm.puts "bgt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "bigteq", "bpgteq", "bbgteq" + $asm.puts "bge #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "bilt", "bplt", "bblt" + $asm.puts "blt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "bilteq", "bplteq", "bblteq" + $asm.puts "ble #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "jmp" + if operands[0].label? + $asm.puts "j #{operands[0].asmLabel}" + else + $asm.puts "jr #{operands[0].mipsOperand}" + end + when "call" + if operands[0].label? + $asm.puts "jal #{operands[0].asmLabel}" + else + $asm.puts "jalr #{operands[0].mipsOperand}" + end + when "break" + $asm.puts "break" + when "ret" + $asm.puts "jr $ra" + when "cia", "cpa", "cba" + $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + when "ciaeq", "cpaeq", "cbaeq" + $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + $asm.puts "xori #{operands[2].mipsOperand}, 1" + when "cib", "cpb", "cbb" + $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + when "cibeq", "cpbeq", "cbbeq" + $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + $asm.puts "xori #{operands[2].mipsOperand}, 1" + when "cigt", "cpgt", "cbgt" + $asm.puts "slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + when "cigteq", "cpgteq", "cbgteq" + $asm.puts "slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + $asm.puts "xori #{operands[2].mipsOperand}, 1" + when "cilt", "cplt", "cblt" + $asm.puts "slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + when "cilteq", "cplteq", "cblteq" + $asm.puts "slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + $asm.puts "xori #{operands[2].mipsOperand}, 1" + when "peek" + $asm.puts "lw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)" + when "poke" + $asm.puts "sw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)" + when "fii2d" + $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[2].mipsSingleLo}" + $asm.puts "mtc1 #{operands[1].mipsOperand}, #{operands[2].mipsSingleHi}" + when "fd2ii" + $asm.puts "mfc1 #{operands[1].mipsOperand}, #{operands[0].mipsSingleLo}" + $asm.puts "mfc1 #{operands[2].mipsOperand}, #{operands[0].mipsSingleHi}" + when "bo" + $asm.puts "bgt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}" + when "bs" + $asm.puts "blt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}" + when "bz" + $asm.puts "beq #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}" + when "bnz" + $asm.puts "bne #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}" + when "leai", "leap" + operands[0].mipsEmitLea(operands[1]) + when "smulli" + raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands.length == 4 + $asm.puts "mult #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + $asm.puts "mflo #{operands[2].mipsOperand}" + $asm.puts "mfhi #{operands[3].mipsOperand}" + when "movz" + $asm.puts "movz #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}" + when "movn" + $asm.puts "movn #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}" + when "slt", "sltb" + $asm.puts "slt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}" + when "sltu", "sltub" + $asm.puts "sltu #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}" + when "pichdr" + $asm.putStr("OFFLINE_ASM_CPLOAD($25)") + $asm.puts "move $s4, $gp" + when "pichdrra" + $asm.putStr("OFFLINE_ASM_CPLOAD($31)") + $asm.puts "move $s4, $gp" + else + raise "Unhandled opcode #{opcode} at #{codeOriginString}" + end + end +end diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog index 098c8de6c..6560cb2f8 100644 --- a/Source/WTF/ChangeLog +++ b/Source/WTF/ChangeLog @@ -1,3 +1,14 @@ +2013-01-07 Balazs Kilvady <kilvadyb@homejinni.com> + + MIPS LLInt implementation. + https://bugs.webkit.org/show_bug.cgi?id=99706 + + Reviewed by Filip Pizlo. + + LLInt implementation for MIPS. + + * wtf/Platform.h: + 2013-01-05 Jonathan Liu <net147@gmail.com> Only enable MinGW-w64 pow() workaround if needed diff --git a/Source/WTF/wtf/Platform.h b/Source/WTF/wtf/Platform.h index 6912392e0..907fab664 100644 --- a/Source/WTF/wtf/Platform.h +++ b/Source/WTF/wtf/Platform.h @@ -921,7 +921,7 @@ && ENABLE(JIT) \ && (OS(DARWIN) || OS(LINUX)) \ && (PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(GTK) || PLATFORM(QT)) \ - && (CPU(X86) || CPU(X86_64) || CPU(ARM_THUMB2)) + && (CPU(X86) || CPU(X86_64) || CPU(ARM_THUMB2) || CPU(MIPS)) #define ENABLE_LLINT 1 #endif |