summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBalazs Kilvady <kilvadyb@homejinni.com>2013-01-07 19:40:10 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-05-23 13:38:48 +0200
commit9147a90a7bdf8a0791efa9d677a0f36ffdb75533 (patch)
treeb5b8f2bc485afc532ab8730c482bcf9d68fd58b3
parentd7fff220c897ab0eebcd6ca8087efd4b9477beb9 (diff)
downloadqtwebkit-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/ChangeLog24
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h3
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp69
-rw-r--r--Source/JavaScriptCore/jit/JITStubs.cpp29
-rw-r--r--Source/JavaScriptCore/jit/JITStubs.h2
-rw-r--r--Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h20
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter.asm12
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm24
-rw-r--r--Source/JavaScriptCore/offlineasm/backends.rb3
-rw-r--r--Source/JavaScriptCore/offlineasm/instructions.rb12
-rw-r--r--Source/JavaScriptCore/offlineasm/mips.rb867
-rw-r--r--Source/WTF/ChangeLog11
-rw-r--r--Source/WTF/wtf/Platform.h2
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