Clean up register naming
authormsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Sep 2015 22:16:23 +0000 (22:16 +0000)
committermsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Sep 2015 22:16:23 +0000 (22:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148658

Reviewed by Geoffrey Garen.

This changes register naming conventions in the llint and baseline JIT
in order to use as few (native) callee-save registers as possible on
64-bits platforms. It also introduces significant changes in the way
registers names are defined in the LLint and baseline JIT in order to
enable a simpler convention about which registers can be aliased. That
convention is valid across all architecture, and described in
llint/LowLevelInterpreter.asm.

Callee save registers are now called out regCS<n> (in the JIT) or
csr<n> (in the LLInt) with a common numbering across all tiers. Some
registers are unused in some tiers.

As a part of this change, rdi was removed from the list of temporary
registers for X86-64 Windows as it is a callee saves register. This
reduced the number of temporary registers for X86-64 Windows.

This is in preparation for properly handling callee save register
preservation and restoration.

* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::compileFunction):
* ftl/FTLLink.cpp:
(JSC::FTL::link):
* jit/FPRInfo.h:
(JSC::FPRInfo::toRegister):
(JSC::FPRInfo::toIndex):
* jit/GPRInfo.h:
(JSC::GPRInfo::toIndex):
(JSC::GPRInfo::toRegister):
(JSC::GPRInfo::debugName): Deleted.
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
* jit/JITArithmetic.cpp:
(JSC::JIT::emit_op_mod):
* jit/JITOpcodes.cpp:
(JSC::JIT::emitSlow_op_loop_hint):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_end):
(JSC::JIT::emit_op_new_object):
* jit/RegisterPreservationWrapperGenerator.cpp:
(JSC::generateRegisterPreservationWrapper):
(JSC::generateRegisterRestoration):
* jit/ThunkGenerators.cpp:
(JSC::arityFixupGenerator):
(JSC::nativeForGenerator): Deleted.
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* offlineasm/arm.rb:
* offlineasm/arm64.rb:
* offlineasm/cloop.rb:
* offlineasm/mips.rb:
* offlineasm/registers.rb:
* offlineasm/sh4.rb:
* offlineasm/x86.rb:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@189293 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
Source/JavaScriptCore/ftl/FTLLink.cpp
Source/JavaScriptCore/jit/FPRInfo.h
Source/JavaScriptCore/jit/GPRInfo.h
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JITArithmetic.cpp
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/jit/RegisterPreservationWrapperGenerator.cpp
Source/JavaScriptCore/jit/ThunkGenerators.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/offlineasm/arm.rb
Source/JavaScriptCore/offlineasm/arm64.rb
Source/JavaScriptCore/offlineasm/cloop.rb
Source/JavaScriptCore/offlineasm/mips.rb
Source/JavaScriptCore/offlineasm/registers.rb
Source/JavaScriptCore/offlineasm/sh4.rb
Source/JavaScriptCore/offlineasm/x86.rb

index de895f8..ddca280 100644 (file)
@@ -1,3 +1,66 @@
+2015-09-03  Basile Clement  <basile_clement@apple.com> and Michael Saboff  <msaboff@apple.com>
+
+        Clean up register naming
+        https://bugs.webkit.org/show_bug.cgi?id=148658
+
+        Reviewed by Geoffrey Garen.
+
+        This changes register naming conventions in the llint and baseline JIT
+        in order to use as few (native) callee-save registers as possible on
+        64-bits platforms. It also introduces significant changes in the way
+        registers names are defined in the LLint and baseline JIT in order to
+        enable a simpler convention about which registers can be aliased. That
+        convention is valid across all architecture, and described in
+        llint/LowLevelInterpreter.asm.
+
+        Callee save registers are now called out regCS<n> (in the JIT) or
+        csr<n> (in the LLInt) with a common numbering across all tiers. Some
+        registers are unused in some tiers.
+
+        As a part of this change, rdi was removed from the list of temporary
+        registers for X86-64 Windows as it is a callee saves register. This
+        reduced the number of temporary registers for X86-64 Windows.
+
+        This is in preparation for properly handling callee save register
+        preservation and restoration.
+
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::compileFunction):
+        * ftl/FTLLink.cpp:
+        (JSC::FTL::link):
+        * jit/FPRInfo.h:
+        (JSC::FPRInfo::toRegister):
+        (JSC::FPRInfo::toIndex):
+        * jit/GPRInfo.h:
+        (JSC::GPRInfo::toIndex):
+        (JSC::GPRInfo::toRegister):
+        (JSC::GPRInfo::debugName): Deleted.
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompile):
+        * jit/JITArithmetic.cpp:
+        (JSC::JIT::emit_op_mod):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emitSlow_op_loop_hint):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_end):
+        (JSC::JIT::emit_op_new_object):
+        * jit/RegisterPreservationWrapperGenerator.cpp:
+        (JSC::generateRegisterPreservationWrapper):
+        (JSC::generateRegisterRestoration):
+        * jit/ThunkGenerators.cpp:
+        (JSC::arityFixupGenerator):
+        (JSC::nativeForGenerator): Deleted.
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * offlineasm/arm.rb:
+        * offlineasm/arm64.rb:
+        * offlineasm/cloop.rb:
+        * offlineasm/mips.rb:
+        * offlineasm/registers.rb:
+        * offlineasm/sh4.rb:
+        * offlineasm/x86.rb:
+
 2015-09-03  Filip Pizlo  <fpizlo@apple.com>
 
         Get rid of RepatchBuffer and replace it with static functions
index b58d67e..1718df6 100644 (file)
@@ -395,18 +395,14 @@ void JITCompiler::compileFunction()
     m_speculative->callOperationWithCallFrameRollbackOnException(m_codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck, GPRInfo::regT0);
     if (maxFrameExtentForSlowPathCall)
         addPtr(TrustedImm32(maxFrameExtentForSlowPathCall), stackPointerRegister);
-    branchTest32(Zero, GPRInfo::regT0).linkTo(fromArityCheck, this);
+    branchTest32(Zero, GPRInfo::returnValueGPR).linkTo(fromArityCheck, this);
     emitStoreCodeOrigin(CodeOrigin(0));
-    GPRReg thunkReg;
-#if USE(JSVALUE64)
-    thunkReg = GPRInfo::regT7;
-#else
-    thunkReg = GPRInfo::regT5;
-#endif
+    GPRReg thunkReg = GPRInfo::argumentGPR1;
     CodeLocationLabel* arityThunkLabels =
         m_vm->arityCheckFailReturnThunks->returnPCsFor(*m_vm, m_codeBlock->numParameters());
     move(TrustedImmPtr(arityThunkLabels), thunkReg);
-    loadPtr(BaseIndex(thunkReg, GPRInfo::regT0, timesPtr()), thunkReg);
+    loadPtr(BaseIndex(thunkReg, GPRInfo::returnValueGPR, timesPtr()), thunkReg);
+    move(GPRInfo::returnValueGPR, GPRInfo::argumentGPR0);
     m_callArityFixup = call();
     jump(fromArityCheck);
     
index 77b6571..fa934c3 100644 (file)
@@ -165,14 +165,14 @@ void link(State& state)
         jit.load64(vm.addressOfException(), GPRInfo::regT1);
         jit.jitAssertIsNull(GPRInfo::regT1);
 #endif
-        jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0);
+        jit.move(GPRInfo::returnValueGPR, GPRInfo::argumentGPR0);
         jit.emitFunctionEpilogue();
-        mainPathJumps.append(jit.branchTest32(CCallHelpers::Zero, GPRInfo::regT0));
+        mainPathJumps.append(jit.branchTest32(CCallHelpers::Zero, GPRInfo::argumentGPR0));
         jit.emitFunctionPrologue();
         CodeLocationLabel* arityThunkLabels =
             vm.arityCheckFailReturnThunks->returnPCsFor(vm, codeBlock->numParameters());
-        jit.move(CCallHelpers::TrustedImmPtr(arityThunkLabels), GPRInfo::regT7);
-        jit.loadPtr(CCallHelpers::BaseIndex(GPRInfo::regT7, GPRInfo::regT0, CCallHelpers::timesPtr()), GPRInfo::regT7);
+        jit.move(CCallHelpers::TrustedImmPtr(arityThunkLabels), GPRInfo::argumentGPR1);
+        jit.loadPtr(CCallHelpers::BaseIndex(GPRInfo::argumentGPR1, GPRInfo::argumentGPR0, CCallHelpers::timesPtr()), GPRInfo::argumentGPR1);
         CCallHelpers::Call callArityFixup = jit.call();
         jit.emitFunctionEpilogue();
         mainPathJumps.append(jit.jump());
index f06b17c..0062b71 100644 (file)
@@ -268,15 +268,16 @@ public:
 class FPRInfo {
 public:
     typedef FPRReg RegisterType;
-    static const unsigned numberOfRegisters = 6;
+    static const unsigned numberOfRegisters = 7;
 
     // Temporary registers.
     static const FPRReg fpRegT0 = MIPSRegisters::f0;
-    static const FPRReg fpRegT1 = MIPSRegisters::f4;
-    static const FPRReg fpRegT2 = MIPSRegisters::f6;
-    static const FPRReg fpRegT3 = MIPSRegisters::f8;
-    static const FPRReg fpRegT4 = MIPSRegisters::f10;
-    static const FPRReg fpRegT5 = MIPSRegisters::f18;
+    static const FPRReg fpRegT1 = MIPSRegisters::f2;
+    static const FPRReg fpRegT2 = MIPSRegisters::f4;
+    static const FPRReg fpRegT3 = MIPSRegisters::f6;
+    static const FPRReg fpRegT4 = MIPSRegisters::f8;
+    static const FPRReg fpRegT5 = MIPSRegisters::f10;
+    static const FPRReg fpRegT6 = MIPSRegisters::f18;
 
     static const FPRReg returnValueFPR = MIPSRegisters::f0;
 
@@ -286,7 +287,7 @@ public:
     static FPRReg toRegister(unsigned index)
     {
         static const FPRReg registerForIndex[numberOfRegisters] = {
-            fpRegT0, fpRegT1, fpRegT2, fpRegT3, fpRegT4, fpRegT5 };
+            fpRegT0, fpRegT1, fpRegT2, fpRegT3, fpRegT4, fpRegT5, fpRegT6 };
 
         ASSERT(index < numberOfRegisters);
         return registerForIndex[index];
@@ -297,11 +298,11 @@ public:
         ASSERT(reg != InvalidFPRReg);
         ASSERT(reg < 20);
         static const unsigned indexForRegister[20] = {
-            0, InvalidIndex, InvalidIndex, InvalidIndex,
-            1, InvalidIndex, 2, InvalidIndex,
-            3, InvalidIndex, 4, InvalidIndex,
+            0, InvalidIndex, 1, InvalidIndex,
+            2, InvalidIndex, 3, InvalidIndex,
+            4, InvalidIndex, 5, InvalidIndex,
             InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex,
-            InvalidIndex, InvalidIndex, 5, InvalidIndex,
+            InvalidIndex, InvalidIndex, 6, InvalidIndex,
         };
         unsigned result = indexForRegister[reg];
         return result;
index a5e301b..ce425dd 100644 (file)
 
 namespace JSC {
 
+// We use the same conventions in the basline JIT as in the LLint. If you
+// change mappings in the GPRInfo, you should change them in the offlineasm
+// compiler adequately. The register naming conventions are described at the
+// top of the LowLevelInterpreter.asm file.
+
 typedef MacroAssembler::RegisterID GPRReg;
 #define InvalidGPRReg ((::JSC::GPRReg)-1)
 
@@ -294,8 +299,6 @@ private:
 };
 #endif // USE(JSVALUE32_64)
 
-// The baseline JIT requires that regT3 be callee-preserved.
-
 #if CPU(X86)
 #define NUMBER_OF_ARGUMENT_REGISTERS 0u
 
@@ -305,25 +308,21 @@ public:
     static const unsigned numberOfRegisters = 6;
     static const unsigned numberOfArgumentRegisters = NUMBER_OF_ARGUMENT_REGISTERS;
 
-    // Note: regT3 is required to be callee-preserved.
-
     // Temporary registers.
     static const GPRReg regT0 = X86Registers::eax;
     static const GPRReg regT1 = X86Registers::edx;
     static const GPRReg regT2 = X86Registers::ecx;
-    static const GPRReg regT3 = X86Registers::ebx;
-    static const GPRReg regT4 = X86Registers::edi;
-    static const GPRReg regT5 = X86Registers::esi;
-    // These registers match the baseline JIT.
-    static const GPRReg cachedResultRegister = regT0;
-    static const GPRReg cachedResultRegister2 = regT1;
+    static const GPRReg regT3 = X86Registers::ebx; // Callee-save
+    static const GPRReg regT4 = X86Registers::esi; // Callee-save
+    static const GPRReg regT5 = X86Registers::edi; // Callee-save
     static const GPRReg callFrameRegister = X86Registers::ebp;
     // These constants provide the names for the general purpose argument & return value registers.
     static const GPRReg argumentGPR0 = X86Registers::ecx; // regT2
     static const GPRReg argumentGPR1 = X86Registers::edx; // regT1
+    static const GPRReg argumentGPR2 = X86Registers::eax; // regT0
+    static const GPRReg argumentGPR3 = X86Registers::ebx; // regT3
     static const GPRReg nonArgGPR0 = X86Registers::esi; // regT4
-    static const GPRReg nonArgGPR1 = X86Registers::eax; // regT0
-    static const GPRReg nonArgGPR2 = X86Registers::ebx; // regT3
+    static const GPRReg nonArgGPR1 = X86Registers::edi; // regT5
     static const GPRReg returnValueGPR = X86Registers::eax; // regT0
     static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1
     static const GPRReg nonPreservedNonReturnGPR = X86Registers::ecx;
@@ -345,7 +344,7 @@ public:
     {
         ASSERT(reg != InvalidGPRReg);
         ASSERT(static_cast<int>(reg) < 8);
-        static const unsigned indexForRegister[8] = { 0, 2, 1, 3, InvalidIndex, InvalidIndex, 5, 4 };
+        static const unsigned indexForRegister[8] = { 0, 2, 1, 3, InvalidIndex, InvalidIndex, 4, 5 };
         unsigned result = indexForRegister[reg];
         return result;
     }
@@ -379,52 +378,74 @@ public:
     static const unsigned numberOfRegisters = 11;
     static const unsigned numberOfArgumentRegisters = NUMBER_OF_ARGUMENT_REGISTERS;
 
-    // Note: regT3 is required to be callee-preserved.
-
     // These registers match the baseline JIT.
-    static const GPRReg cachedResultRegister = X86Registers::eax;
     static const GPRReg callFrameRegister = X86Registers::ebp;
     static const GPRReg tagTypeNumberRegister = X86Registers::r14;
     static const GPRReg tagMaskRegister = X86Registers::r15;
     // Temporary registers.
     static const GPRReg regT0 = X86Registers::eax;
-    static const GPRReg regT1 = X86Registers::edx;
-    static const GPRReg regT2 = X86Registers::ecx;
-    static const GPRReg regT3 = X86Registers::ebx;
-    static const GPRReg regT4 = X86Registers::edi;
-    static const GPRReg regT5 = X86Registers::esi;
-    static const GPRReg regT6 = X86Registers::r8;
+#if !OS(WINDOWS)
+    static const GPRReg regT1 = X86Registers::esi;
+    static const GPRReg regT2 = X86Registers::edx;
+    static const GPRReg regT3 = X86Registers::ecx;
+    static const GPRReg regT4 = X86Registers::r8;
+    static const GPRReg regT5 = X86Registers::r10;
+    static const GPRReg regT6 = X86Registers::edi;
     static const GPRReg regT7 = X86Registers::r9;
-    static const GPRReg regT8 = X86Registers::r10;
-    static const GPRReg regT9 = X86Registers::r12;
-    static const GPRReg regT10 = X86Registers::r13;
+#else
+    static const GPRReg regT1 = X86Registers::edx;
+    static const GPRReg regT2 = X86Registers::r8;
+    static const GPRReg regT3 = X86Registers::r9;
+    static const GPRReg regT4 = X86Registers::r10;
+    static const GPRReg regT5 = X86Registers::ecx;
+#endif
+
+    static const GPRReg regCS0 = X86Registers::ebx;
+
+#if !OS(WINDOWS)
+    static const GPRReg regCS1 = X86Registers::r12;
+    static const GPRReg regCS2 = X86Registers::r13;
+    static const GPRReg regCS3 = X86Registers::r14;
+    static const GPRReg regCS4 = X86Registers::r15;
+#else
+    static const GPRReg regCS1 = X86Registers::esi;
+    static const GPRReg regCS2 = X86Registers::edi;
+    static const GPRReg regCS3 = X86Registers::r12;
+    static const GPRReg regCS4 = X86Registers::r13;
+    static const GPRReg regCS5 = X86Registers::r14;
+    static const GPRReg regCS6 = X86Registers::r15;
+#endif
+
     // These constants provide the names for the general purpose argument & return value registers.
 #if !OS(WINDOWS)
-    static const GPRReg argumentGPR0 = X86Registers::edi; // regT4
-    static const GPRReg argumentGPR1 = X86Registers::esi; // regT5
-    static const GPRReg argumentGPR2 = X86Registers::edx; // regT1
-    static const GPRReg argumentGPR3 = X86Registers::ecx; // regT2
-    static const GPRReg argumentGPR4 = X86Registers::r8;  // regT6
-    static const GPRReg argumentGPR5 = X86Registers::r9;  // regT7
+    static const GPRReg argumentGPR0 = X86Registers::edi; // regT6
+    static const GPRReg argumentGPR1 = X86Registers::esi; // regT1
+    static const GPRReg argumentGPR2 = X86Registers::edx; // regT2
+    static const GPRReg argumentGPR3 = X86Registers::ecx; // regT3
+    static const GPRReg argumentGPR4 = X86Registers::r8; // regT4
+    static const GPRReg argumentGPR5 = X86Registers::r9; // regT7
 #else
-    static const GPRReg argumentGPR0 = X86Registers::ecx;
-    static const GPRReg argumentGPR1 = X86Registers::edx;
-    static const GPRReg argumentGPR2 = X86Registers::r8; // regT6
-    static const GPRReg argumentGPR3 = X86Registers::r9; // regT7
+    static const GPRReg argumentGPR0 = X86Registers::ecx; // regT5
+    static const GPRReg argumentGPR1 = X86Registers::edx; // regT1
+    static const GPRReg argumentGPR2 = X86Registers::r8; // regT2
+    static const GPRReg argumentGPR3 = X86Registers::r9; // regT3
 #endif
-    static const GPRReg nonArgGPR0 = X86Registers::r10; // regT8
-    static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3
-    static const GPRReg nonArgGPR2 = X86Registers::r12; // regT9
+    static const GPRReg nonArgGPR0 = X86Registers::r10; // regT5 (regT4 on Windows)
+    static const GPRReg nonArgGPR1 = X86Registers::ebx; // Callee save
     static const GPRReg returnValueGPR = X86Registers::eax; // regT0
-    static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1
-    static const GPRReg nonPreservedNonReturnGPR = X86Registers::esi;
-    static const GPRReg nonPreservedNonArgumentGPR = X86Registers::r10;
+    static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1 or regT2
+    static const GPRReg nonPreservedNonReturnGPR = X86Registers::r10; // regT5 (regT4 on Windows)
+    static const GPRReg nonPreservedNonArgumentGPR = X86Registers::r10; // regT5 (regT4 on Windows)
     static const GPRReg patchpointScratchRegister = MacroAssembler::scratchRegister;
 
     static GPRReg toRegister(unsigned index)
     {
         ASSERT(index < numberOfRegisters);
-        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regT8, regT9, regT10 };
+#if !OS(WINDOWS)
+        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regCS0, regCS1, regCS2 };
+#else
+        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regCS0, regCS1, regCS2, regCS3, regCS4 };
+#endif
         return registerForIndex[index];
     }
     
@@ -443,7 +464,11 @@ public:
     {
         ASSERT(reg != InvalidGPRReg);
         ASSERT(static_cast<int>(reg) < 16);
-        static const unsigned indexForRegister[16] = { 0, 2, 1, 3, InvalidIndex, InvalidIndex, 5, 4, 6, 7, 8, InvalidIndex, 9, 10, InvalidIndex, InvalidIndex };
+#if !OS(WINDOWS)
+        static const unsigned indexForRegister[16] = { 0, 3, 2, 8, InvalidIndex, InvalidIndex, 1, 6, 4, 7, 5, InvalidIndex, 9, 10, InvalidIndex, InvalidIndex };
+#else
+        static const unsigned indexForRegister[16] = { 0, 5, 1, 6, InvalidIndex, InvalidIndex, 7, 8, 2, 3, 4, InvalidIndex, 9, 10, InvalidIndex, InvalidIndex };
+#endif
         return indexForRegister[reg];
     }
 
@@ -474,13 +499,11 @@ public:
     static const unsigned numberOfRegisters = 9;
     static const unsigned numberOfArgumentRegisters = NUMBER_OF_ARGUMENT_REGISTERS;
 
-    // Note: regT3 is required to be callee-preserved.
-
     // Temporary registers.
     static const GPRReg regT0 = ARMRegisters::r0;
     static const GPRReg regT1 = ARMRegisters::r1;
     static const GPRReg regT2 = ARMRegisters::r2;
-    static const GPRReg regT3 = ARMRegisters::r4;
+    static const GPRReg regT3 = ARMRegisters::r3;
     static const GPRReg regT4 = ARMRegisters::r8;
     static const GPRReg regT5 = ARMRegisters::r9;
     static const GPRReg regT6 = ARMRegisters::r10;
@@ -489,22 +512,20 @@ public:
 #else 
     static const GPRReg regT7 = ARMRegisters::r7;
 #endif
-    static const GPRReg regT8 = ARMRegisters::r3;
+    static const GPRReg regT8 = ARMRegisters::r4;
     // These registers match the baseline JIT.
-    static const GPRReg cachedResultRegister = regT0;
-    static const GPRReg cachedResultRegister2 = regT1;
     static const GPRReg callFrameRegister = ARMRegisters::fp;
     // These constants provide the names for the general purpose argument & return value registers.
     static const GPRReg argumentGPR0 = ARMRegisters::r0; // regT0
     static const GPRReg argumentGPR1 = ARMRegisters::r1; // regT1
     static const GPRReg argumentGPR2 = ARMRegisters::r2; // regT2
-    static const GPRReg argumentGPR3 = ARMRegisters::r3; // regT8
-    static const GPRReg nonArgGPR0 = ARMRegisters::r4; // regT3
+    static const GPRReg argumentGPR3 = ARMRegisters::r3; // regT3
+    static const GPRReg nonArgGPR0 = ARMRegisters::r4; // regT8
     static const GPRReg nonArgGPR1 = ARMRegisters::r8; // regT4
     static const GPRReg nonArgGPR2 = ARMRegisters::r9; // regT5
     static const GPRReg returnValueGPR = ARMRegisters::r0; // regT0
     static const GPRReg returnValueGPR2 = ARMRegisters::r1; // regT1
-    static const GPRReg nonPreservedNonReturnGPR = ARMRegisters::r5; // regT7
+    static const GPRReg nonPreservedNonReturnGPR = ARMRegisters::r5;
 
     static GPRReg toRegister(unsigned index)
     {
@@ -526,9 +547,9 @@ public:
         ASSERT(static_cast<int>(reg) < 16);
         static const unsigned indexForRegister[16] =
 #if CPU(ARM_THUMB2)
-            { 0, 1, 2, 8, 3, 9, InvalidIndex, InvalidIndex, 4, 5, 6, 7, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
+            { 0, 1, 2, 3, 8, InvalidIndex, InvalidIndex, InvalidIndex, 4, 5, 6, 7, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
 #else
-            { 0, 1, 2, 8, 3, 9, InvalidIndex, 7, 4, 5, 6, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
+            { 0, 1, 2, 3, 8, InvalidIndex, InvalidIndex, 7, 4, 5, 6, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
 #endif
         unsigned result = indexForRegister[reg];
         return result;
@@ -561,11 +582,7 @@ public:
     static const unsigned numberOfRegisters = 16;
     static const unsigned numberOfArgumentRegisters = 8;
 
-    // Note: regT3 is required to be callee-preserved.
-
     // These registers match the baseline JIT.
-    static const GPRReg cachedResultRegister = ARM64Registers::x0;
-    static const GPRReg timeoutCheckRegister = ARM64Registers::x26;
     static const GPRReg callFrameRegister = ARM64Registers::fp;
     static const GPRReg tagTypeNumberRegister = ARM64Registers::x27;
     static const GPRReg tagMaskRegister = ARM64Registers::x28;
@@ -573,9 +590,9 @@ public:
     static const GPRReg regT0 = ARM64Registers::x0;
     static const GPRReg regT1 = ARM64Registers::x1;
     static const GPRReg regT2 = ARM64Registers::x2;
-    static const GPRReg regT3 = ARM64Registers::x23;
-    static const GPRReg regT4 = ARM64Registers::x5;
-    static const GPRReg regT5 = ARM64Registers::x24;
+    static const GPRReg regT3 = ARM64Registers::x3;
+    static const GPRReg regT4 = ARM64Registers::x4;
+    static const GPRReg regT5 = ARM64Registers::x5;
     static const GPRReg regT6 = ARM64Registers::x6;
     static const GPRReg regT7 = ARM64Registers::x7;
     static const GPRReg regT8 = ARM64Registers::x8;
@@ -586,18 +603,20 @@ public:
     static const GPRReg regT13 = ARM64Registers::x13;
     static const GPRReg regT14 = ARM64Registers::x14;
     static const GPRReg regT15 = ARM64Registers::x15;
+    static const GPRReg regCS0 = ARM64Registers::x26; // Used by LLInt only
+    static const GPRReg regCS1 = ARM64Registers::x27; // tagTypeNumber
+    static const GPRReg regCS2 = ARM64Registers::x28; // tagMask
     // These constants provide the names for the general purpose argument & return value registers.
     static const GPRReg argumentGPR0 = ARM64Registers::x0; // regT0
     static const GPRReg argumentGPR1 = ARM64Registers::x1; // regT1
     static const GPRReg argumentGPR2 = ARM64Registers::x2; // regT2
-    static const GPRReg argumentGPR3 = ARM64Registers::x3;
-    static const GPRReg argumentGPR4 = ARM64Registers::x4;
-    static const GPRReg argumentGPR5 = ARM64Registers::x5; // regT4
+    static const GPRReg argumentGPR3 = ARM64Registers::x3; // regT3
+    static const GPRReg argumentGPR4 = ARM64Registers::x4; // regT4
+    static const GPRReg argumentGPR5 = ARM64Registers::x5; // regT5
     static const GPRReg argumentGPR6 = ARM64Registers::x6; // regT6
     static const GPRReg argumentGPR7 = ARM64Registers::x7; // regT7
     static const GPRReg nonArgGPR0 = ARM64Registers::x8; // regT8
     static const GPRReg nonArgGPR1 = ARM64Registers::x9; // regT9
-    static const GPRReg nonArgGPR2 = ARM64Registers::x10; // regT10
     static const GPRReg returnValueGPR = ARM64Registers::x0; // regT0
     static const GPRReg returnValueGPR2 = ARM64Registers::x1; // regT1
     static const GPRReg nonPreservedNonReturnGPR = ARM64Registers::x2;
@@ -663,41 +682,38 @@ public:
 class GPRInfo {
 public:
     typedef GPRReg RegisterType;
-    static const unsigned numberOfRegisters = 7;
+    static const unsigned numberOfRegisters = 8;
     static const unsigned numberOfArgumentRegisters = NUMBER_OF_ARGUMENT_REGISTERS;
 
     // regT0 must be v0 for returning a 32-bit value.
     // regT1 must be v1 for returning a pair of 32-bit value.
-    // regT3 must be saved in the callee, so use an S register.
 
     // Temporary registers.
     static const GPRReg regT0 = MIPSRegisters::v0;
     static const GPRReg regT1 = MIPSRegisters::v1;
-    static const GPRReg regT2 = MIPSRegisters::t4;
-    static const GPRReg regT3 = MIPSRegisters::s2;
-    static const GPRReg regT4 = MIPSRegisters::t5;
-    static const GPRReg regT5 = MIPSRegisters::t6;
-    static const GPRReg regT6 = MIPSRegisters::s0;
+    static const GPRReg regT2 = MIPSRegisters::t2;
+    static const GPRReg regT3 = MIPSRegisters::t3;
+    static const GPRReg regT4 = MIPSRegisters::t4;
+    static const GPRReg regT5 = MIPSRegisters::t5;
+    static const GPRReg regT6 = MIPSRegisters::t0;
+    static const GPRReg regT7 = MIPSRegisters::t1;
     // These registers match the baseline JIT.
-    static const GPRReg cachedResultRegister = regT0;
-    static const GPRReg cachedResultRegister2 = regT1;
     static const GPRReg callFrameRegister = MIPSRegisters::fp;
     // These constants provide the names for the general purpose argument & return value registers.
     static const GPRReg argumentGPR0 = MIPSRegisters::a0;
     static const GPRReg argumentGPR1 = MIPSRegisters::a1;
     static const GPRReg argumentGPR2 = MIPSRegisters::a2;
     static const GPRReg argumentGPR3 = MIPSRegisters::a3;
-    static const GPRReg nonArgGPR0 = regT2;
-    static const GPRReg nonArgGPR1 = regT3;
-    static const GPRReg nonArgGPR2 = regT4;
+    static const GPRReg nonArgGPR0 = regT0;
+    static const GPRReg nonArgGPR1 = regT1;
     static const GPRReg returnValueGPR = regT0;
     static const GPRReg returnValueGPR2 = regT1;
-    static const GPRReg nonPreservedNonReturnGPR = regT5;
+    static const GPRReg nonPreservedNonReturnGPR = regT2;
 
     static GPRReg toRegister(unsigned index)
     {
         ASSERT(index < numberOfRegisters);
-        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6 };
+        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7 };
         return registerForIndex[index];
     }
 
@@ -707,8 +723,8 @@ public:
         ASSERT(reg < 24);
         static const unsigned indexForRegister[24] = {
             InvalidIndex, InvalidIndex, 0, 1, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex,
-            InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, 2, 4, 5, InvalidIndex,
-            6, InvalidIndex, 3, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex
+            6, 7, 2, 3, 4, 5, InvalidIndex, InvalidIndex,
+            InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex
         };
         unsigned result = indexForRegister[reg];
         return result;
@@ -745,12 +761,12 @@ public:
     // Temporary registers.
     static const GPRReg regT0 = SH4Registers::r0;
     static const GPRReg regT1 = SH4Registers::r1;
-    static const GPRReg regT2 = SH4Registers::r2;
-    static const GPRReg regT3 = SH4Registers::r10;
-    static const GPRReg regT4 = SH4Registers::r4;
-    static const GPRReg regT5 = SH4Registers::r5;
-    static const GPRReg regT6 = SH4Registers::r6;
-    static const GPRReg regT7 = SH4Registers::r7;
+    static const GPRReg regT2 = SH4Registers::r6;
+    static const GPRReg regT3 = SH4Registers::r7;
+    static const GPRReg regT4 = SH4Registers::r2;
+    static const GPRReg regT5 = SH4Registers::r3;
+    static const GPRReg regT6 = SH4Registers::r4;
+    static const GPRReg regT7 = SH4Registers::r5;
     static const GPRReg regT8 = SH4Registers::r8;
     static const GPRReg regT9 = SH4Registers::r9;
     // These registers match the baseline JIT.
@@ -758,13 +774,12 @@ public:
     static const GPRReg cachedResultRegister2 = regT1;
     static const GPRReg callFrameRegister = SH4Registers::fp;
     // These constants provide the names for the general purpose argument & return value registers.
-    static const GPRReg argumentGPR0 = regT4;
-    static const GPRReg argumentGPR1 = regT5;
-    static const GPRReg argumentGPR2 = regT6;
-    static const GPRReg argumentGPR3 = regT7;
-    static const GPRReg nonArgGPR0 = regT3;
-    static const GPRReg nonArgGPR1 = regT8;
-    static const GPRReg nonArgGPR2 = regT9;
+    static const GPRReg argumentGPR0 = SH4Registers::r4; // regT6
+    static const GPRReg argumentGPR1 = SH4Registers::r5; // regT7
+    static const GPRReg argumentGPR2 = SH4Registers::r6; // regT2
+    static const GPRReg argumentGPR3 = SH4Registers::r7; // regT3
+    static const GPRReg nonArgGPR0 = regT4;
+    static const GPRReg nonArgGPR1 = regT5;
     static const GPRReg returnValueGPR = regT0;
     static const GPRReg returnValueGPR2 = regT1;
     static const GPRReg nonPreservedNonReturnGPR = regT2;
@@ -780,7 +795,7 @@ public:
     {
         ASSERT(reg != InvalidGPRReg);
         ASSERT(reg < 14);
-        static const unsigned indexForRegister[14] = { 0, 1, 2, InvalidIndex, 4, 5, 6, 7, 8, 9, 3, InvalidIndex, InvalidIndex, InvalidIndex };
+        static const unsigned indexForRegister[14] = { 0, 1, 4, 5, 6, 7, 2, 3, 8, 9, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
         unsigned result = indexForRegister[reg];
         return result;
     }
index 066c35c..d23bf4b 100644 (file)
@@ -572,19 +572,13 @@ CompilationResult JIT::privateCompile(JITCompilationEffort effort)
         callOperationWithCallFrameRollbackOnException(m_codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck);
         if (maxFrameExtentForSlowPathCall)
             addPtr(TrustedImm32(maxFrameExtentForSlowPathCall), stackPointerRegister);
-        if (returnValueGPR != regT0)
-            move(returnValueGPR, regT0);
-        branchTest32(Zero, regT0).linkTo(beginLabel, this);
-        GPRReg thunkReg;
-#if USE(JSVALUE64)
-        thunkReg = GPRInfo::regT7;
-#else
-        thunkReg = GPRInfo::regT5;
-#endif
+        branchTest32(Zero, returnValueGPR).linkTo(beginLabel, this);
+        GPRReg thunkReg = GPRInfo::argumentGPR1;
         CodeLocationLabel* failThunkLabels =
             m_vm->arityCheckFailReturnThunks->returnPCsFor(*m_vm, m_codeBlock->numParameters());
         move(TrustedImmPtr(failThunkLabels), thunkReg);
-        loadPtr(BaseIndex(thunkReg, regT0, timesPtr()), thunkReg);
+        loadPtr(BaseIndex(thunkReg, returnValueGPR, timesPtr()), thunkReg);
+        move(returnValueGPR, GPRInfo::argumentGPR0);
         emitNakedCall(m_vm->getCTIStub(arityFixupGenerator).code());
 
 #if !ASSERT_DISABLED
index 167e413..50671e2 100644 (file)
@@ -611,25 +611,35 @@ void JIT::emit_op_mod(Instruction* currentInstruction)
     int op2 = currentInstruction[3].u.operand;
 
     // Make sure registers are correct for x86 IDIV instructions.
+#if CPU(X86)
+    auto edx = regT1;
+    auto ecx = regT2;
+#elif OS(WINDOWS)
+    auto edx = regT1;
+    auto ecx = regT5;
+#else
+    auto edx = regT2;
+    auto ecx = regT3;
+#endif
     ASSERT(regT0 == X86Registers::eax);
-    ASSERT(regT1 == X86Registers::edx);
-    ASSERT(regT2 == X86Registers::ecx);
+    ASSERT(edx == X86Registers::edx);
+    ASSERT(ecx == X86Registers::ecx);
 
-    emitGetVirtualRegisters(op1, regT3, op2, regT2);
-    emitJumpSlowCaseIfNotImmediateInteger(regT3);
-    emitJumpSlowCaseIfNotImmediateInteger(regT2);
+    emitGetVirtualRegisters(op1, regT4, op2, ecx);
+    emitJumpSlowCaseIfNotImmediateInteger(regT4);
+    emitJumpSlowCaseIfNotImmediateInteger(ecx);
 
-    move(regT3, regT0);
-    addSlowCase(branchTest32(Zero, regT2));
-    Jump denominatorNotNeg1 = branch32(NotEqual, regT2, TrustedImm32(-1));
+    move(regT4, regT0);
+    addSlowCase(branchTest32(Zero, ecx));
+    Jump denominatorNotNeg1 = branch32(NotEqual, ecx, TrustedImm32(-1));
     addSlowCase(branch32(Equal, regT0, TrustedImm32(-2147483647-1)));
     denominatorNotNeg1.link(this);
     m_assembler.cdq();
-    m_assembler.idivl_r(regT2);
-    Jump numeratorPositive = branch32(GreaterThanOrEqual, regT3, TrustedImm32(0));
-    addSlowCase(branchTest32(Zero, regT1));
+    m_assembler.idivl_r(ecx);
+    Jump numeratorPositive = branch32(GreaterThanOrEqual, regT4, TrustedImm32(0));
+    addSlowCase(branchTest32(Zero, edx));
     numeratorPositive.link(this);
-    emitFastArithReTagImmediate(regT1, regT0);
+    emitFastArithReTagImmediate(edx, regT0);
     emitPutVirtualRegister(result);
 }
 
index 426600c..29eb64a 100644 (file)
@@ -928,7 +928,7 @@ void JIT::emitSlow_op_loop_hint(Instruction*, Vector<SlowCaseEntry>::iterator& i
         callOperation(operationOptimize, m_bytecodeOffset);
         Jump noOptimizedEntry = branchTestPtr(Zero, returnValueGPR);
         if (!ASSERT_DISABLED) {
-            Jump ok = branchPtr(MacroAssembler::Above, regT0, TrustedImmPtr(bitwise_cast<void*>(static_cast<intptr_t>(1000))));
+            Jump ok = branchPtr(MacroAssembler::Above, returnValueGPR, TrustedImmPtr(bitwise_cast<void*>(static_cast<intptr_t>(1000))));
             abortWithReason(JITUnreasonableLoopHintJumpTarget);
             ok.link(this);
         }
index 9362152..b421a54 100644 (file)
@@ -147,7 +147,7 @@ void JIT::emit_op_mov(Instruction* currentInstruction)
 void JIT::emit_op_end(Instruction* currentInstruction)
 {
     ASSERT(returnValueGPR != callFrameRegister);
-    emitLoad(currentInstruction[1].u.operand, regT1, regT0);
+    emitLoad(currentInstruction[1].u.operand, regT1, returnValueGPR);
     emitFunctionEpilogue();
     ret();
 }
@@ -164,9 +164,9 @@ void JIT::emit_op_new_object(Instruction* currentInstruction)
     size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
     MarkedAllocator* allocator = &m_vm->heap.allocatorForObjectWithoutDestructor(allocationSize);
 
-    RegisterID resultReg = regT0;
+    RegisterID resultReg = returnValueGPR;
     RegisterID allocatorReg = regT1;
-    RegisterID scratchReg = regT2;
+    RegisterID scratchReg = regT3;
 
     move(TrustedImmPtr(allocator), allocatorReg);
     emitAllocateJSObject(allocatorReg, TrustedImmPtr(structure), resultReg, scratchReg);
index 070b5cb..1807251 100644 (file)
@@ -65,6 +65,10 @@ MacroAssemblerCodeRef generateRegisterPreservationWrapper(VM& vm, ExecutableBase
     // We shouldn't ever be generating wrappers for native functions.
     RegisterSet toSave = registersToPreserve();
     ptrdiff_t offset = registerPreservationOffset();
+
+    ASSERT(!toSave.get(GPRInfo::regT1));
+    ASSERT(!toSave.get(GPRInfo::regT2));
+    ASSERT(!toSave.get(GPRInfo::regT3));
     
     AssemblyHelpers jit(&vm, 0);
     
@@ -84,31 +88,30 @@ MacroAssemblerCodeRef generateRegisterPreservationWrapper(VM& vm, ExecutableBase
             JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize),
         GPRInfo::regT2);
 
-    ASSERT(!toSave.get(GPRInfo::regT4));
-    jit.move(AssemblyHelpers::stackPointerRegister, GPRInfo::regT4);
+    jit.move(AssemblyHelpers::stackPointerRegister, GPRInfo::regT3);
     
     AssemblyHelpers::Label loop = jit.label();
     jit.sub32(AssemblyHelpers::TrustedImm32(1), GPRInfo::regT2);
-    jit.load64(AssemblyHelpers::Address(GPRInfo::regT4, offset), GPRInfo::regT0);
-    jit.store64(GPRInfo::regT0, GPRInfo::regT4);
-    jit.addPtr(AssemblyHelpers::TrustedImm32(sizeof(Register)), GPRInfo::regT4);
+    jit.load64(AssemblyHelpers::Address(GPRInfo::regT3, offset), GPRInfo::regT0);
+    jit.store64(GPRInfo::regT0, GPRInfo::regT3);
+    jit.addPtr(AssemblyHelpers::TrustedImm32(sizeof(Register)), GPRInfo::regT3);
     jit.branchTest32(AssemblyHelpers::NonZero, GPRInfo::regT2).linkTo(loop, &jit);
 
-    // At this point regT4 + offset points to where we save things.
+    // At this point regT3 + offset points to where we save things.
     ptrdiff_t currentOffset = 0;
-    jit.storePtr(GPRInfo::regT1, AssemblyHelpers::Address(GPRInfo::regT4, currentOffset));
+    jit.storePtr(GPRInfo::regT1, AssemblyHelpers::Address(GPRInfo::regT3, currentOffset));
     
     for (GPRReg gpr = AssemblyHelpers::firstRegister(); gpr <= AssemblyHelpers::lastRegister(); gpr = static_cast<GPRReg>(gpr + 1)) {
         if (!toSave.get(gpr))
             continue;
         currentOffset += sizeof(Register);
-        jit.store64(gpr, AssemblyHelpers::Address(GPRInfo::regT4, currentOffset));
+        jit.store64(gpr, AssemblyHelpers::Address(GPRInfo::regT3, currentOffset));
     }
     for (FPRReg fpr = AssemblyHelpers::firstFPRegister(); fpr <= AssemblyHelpers::lastFPRegister(); fpr = static_cast<FPRReg>(fpr + 1)) {
         if (!toSave.get(fpr))
             continue;
         currentOffset += sizeof(Register);
-        jit.storeDouble(fpr, AssemblyHelpers::Address(GPRInfo::regT4, currentOffset));
+        jit.storeDouble(fpr, AssemblyHelpers::Address(GPRInfo::regT3, currentOffset));
     }
     
     // Assume that there aren't any saved FP registers.
@@ -151,7 +154,9 @@ static void generateRegisterRestoration(AssemblyHelpers& jit)
     RegisterSet toSave = registersToPreserve();
     ptrdiff_t offset = registerPreservationOffset();
     
-    ASSERT(!toSave.get(GPRInfo::regT4));
+    ASSERT(!toSave.get(GPRInfo::regT1));
+    ASSERT(!toSave.get(GPRInfo::regT2));
+    ASSERT(!toSave.get(GPRInfo::regT3));
 
     // We need to place the stack pointer back to where the caller thought they left it.
     // But also, in order to recover the registers, we need to figure out how big the
@@ -161,9 +166,9 @@ static void generateRegisterRestoration(AssemblyHelpers& jit)
         AssemblyHelpers::Address(
             AssemblyHelpers::stackPointerRegister,
             (JSStack::ArgumentCount - JSStack::CallerFrameAndPCSize) * sizeof(Register) + PayloadOffset),
-        GPRInfo::regT4);
+        GPRInfo::regT3);
     
-    jit.move(GPRInfo::regT4, GPRInfo::regT2);
+    jit.move(GPRInfo::regT3, GPRInfo::regT2);
     jit.lshift32(AssemblyHelpers::TrustedImm32(3), GPRInfo::regT2);
     
     jit.addPtr(AssemblyHelpers::TrustedImm32(offset), AssemblyHelpers::stackPointerRegister);
@@ -203,7 +208,7 @@ static void generateRegisterRestoration(AssemblyHelpers& jit)
     
     // Thunks like this rely on the ArgumentCount being intact. Pay it forward.
     jit.store32(
-        GPRInfo::regT4,
+        GPRInfo::regT3,
         AssemblyHelpers::Address(
             AssemblyHelpers::stackPointerRegister,
             (JSStack::ArgumentCount - JSStack::CallerFrameAndPCSize) * sizeof(Register) + PayloadOffset));
index 34c6504..2823ce1 100644 (file)
@@ -255,8 +255,6 @@ static MacroAssemblerCodeRef nativeForGenerator(VM* vm, CodeSpecializationKind k
 #endif
 
 #elif CPU(ARM64)
-    COMPILE_ASSERT(ARM64Registers::x3 != JSInterfaceJIT::regT1, prev_callframe_not_trampled_by_T1);
-    COMPILE_ASSERT(ARM64Registers::x3 != JSInterfaceJIT::regT3, prev_callframe_not_trampled_by_T3);
     COMPILE_ASSERT(ARM64Registers::x0 != JSInterfaceJIT::regT3, T3_not_trampled_by_arg_0);
     COMPILE_ASSERT(ARM64Registers::x1 != JSInterfaceJIT::regT3, T3_not_trampled_by_arg_1);
     COMPILE_ASSERT(ARM64Registers::x2 != JSInterfaceJIT::regT3, T3_not_trampled_by_arg_2);
@@ -355,46 +353,51 @@ MacroAssemblerCodeRef arityFixupGenerator(VM* vm)
 {
     JSInterfaceJIT jit(vm);
 
-    // We enter with fixup count, in aligned stack units, in regT0 and the return thunk in
-    // regT5 on 32-bit and regT7 on 64-bit.
+    // We enter with fixup count, in aligned stack units, in argumentGPR0 and the return thunk in argumentGPR1
+    // We have the guarantee that a0, a1, a2, t3, t4 and t5 (or t0 for Windows) are all distinct :-)
 #if USE(JSVALUE64)
+#if OS(WINDOWS)
+    const GPRReg extraTemp = JSInterfaceJIT::regT0;
+#else
+    const GPRReg extraTemp = JSInterfaceJIT::regT5;
+#endif
 #  if CPU(X86_64)
     jit.pop(JSInterfaceJIT::regT4);
 #  endif
-    jit.lshift32(JSInterfaceJIT::TrustedImm32(logStackAlignmentRegisters()), JSInterfaceJIT::regT0);
-    jit.neg64(JSInterfaceJIT::regT0);
-    jit.move(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::regT6);
-    jit.load32(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, JSStack::ArgumentCount * sizeof(Register)), JSInterfaceJIT::regT2);
-    jit.add32(JSInterfaceJIT::TrustedImm32(JSStack::CallFrameHeaderSize), JSInterfaceJIT::regT2);
+    jit.lshift32(JSInterfaceJIT::TrustedImm32(logStackAlignmentRegisters()), JSInterfaceJIT::argumentGPR0);
+    jit.neg64(JSInterfaceJIT::argumentGPR0);
+    jit.move(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::regT3);
+    jit.load32(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, JSStack::ArgumentCount * sizeof(Register)), JSInterfaceJIT::argumentGPR2);
+    jit.add32(JSInterfaceJIT::TrustedImm32(JSStack::CallFrameHeaderSize), JSInterfaceJIT::argumentGPR2);
 
-    // Move current frame down regT0 number of slots
+    // Move current frame down argumentGPR0 number of slots
     JSInterfaceJIT::Label copyLoop(jit.label());
-    jit.load64(JSInterfaceJIT::regT6, JSInterfaceJIT::regT1);
-    jit.store64(JSInterfaceJIT::regT1, MacroAssembler::BaseIndex(JSInterfaceJIT::regT6, JSInterfaceJIT::regT0, JSInterfaceJIT::TimesEight));
-    jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT6);
-    jit.branchSub32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::regT2).linkTo(copyLoop, &jit);
-
-    // Fill in regT0 - 1 missing arg slots with undefined
-    jit.move(JSInterfaceJIT::regT0, JSInterfaceJIT::regT2);
-    jit.move(JSInterfaceJIT::TrustedImm64(ValueUndefined), JSInterfaceJIT::regT1);
-    jit.add32(JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::regT2);
+    jit.load64(JSInterfaceJIT::regT3, extraTemp);
+    jit.store64(extraTemp, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight));
+    jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
+    jit.branchSub32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2).linkTo(copyLoop, &jit);
+
+    // Fill in argumentGPR0 - 1 missing arg slots with undefined
+    jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::argumentGPR2);
+    jit.move(JSInterfaceJIT::TrustedImm64(ValueUndefined), extraTemp);
+    jit.add32(JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2);
     JSInterfaceJIT::Label fillUndefinedLoop(jit.label());
-    jit.store64(JSInterfaceJIT::regT1, MacroAssembler::BaseIndex(JSInterfaceJIT::regT6, JSInterfaceJIT::regT0, JSInterfaceJIT::TimesEight));
-    jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT6);
-    jit.branchAdd32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::regT2).linkTo(fillUndefinedLoop, &jit);
+    jit.store64(extraTemp, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight));
+    jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
+    jit.branchAdd32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2).linkTo(fillUndefinedLoop, &jit);
     
     // Adjust call frame register and stack pointer to account for missing args
-    jit.move(JSInterfaceJIT::regT0, JSInterfaceJIT::regT1);
-    jit.lshift64(JSInterfaceJIT::TrustedImm32(3), JSInterfaceJIT::regT1);
-    jit.addPtr(JSInterfaceJIT::regT1, JSInterfaceJIT::callFrameRegister);
-    jit.addPtr(JSInterfaceJIT::regT1, JSInterfaceJIT::stackPointerRegister);
+    jit.move(JSInterfaceJIT::argumentGPR0, extraTemp);
+    jit.lshift64(JSInterfaceJIT::TrustedImm32(3), extraTemp);
+    jit.addPtr(extraTemp, JSInterfaceJIT::callFrameRegister);
+    jit.addPtr(extraTemp, JSInterfaceJIT::stackPointerRegister);
 
     // Save the original return PC.
-    jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, CallFrame::returnPCOffset()), GPRInfo::regT1);
-    jit.storePtr(GPRInfo::regT1, MacroAssembler::BaseIndex(JSInterfaceJIT::regT6, JSInterfaceJIT::regT0, JSInterfaceJIT::TimesEight));
-    
+    jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, CallFrame::returnPCOffset()), extraTemp);
+    jit.storePtr(extraTemp, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight));
+
     // Install the new return PC.
-    jit.storePtr(GPRInfo::regT7, JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, CallFrame::returnPCOffset()));
+    jit.storePtr(GPRInfo::argumentGPR1, JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, CallFrame::returnPCOffset()));
 
 #  if CPU(X86_64)
     jit.push(JSInterfaceJIT::regT4);
@@ -404,45 +407,45 @@ MacroAssemblerCodeRef arityFixupGenerator(VM* vm)
 #  if CPU(X86)
     jit.pop(JSInterfaceJIT::regT4);
 #  endif
-    jit.lshift32(JSInterfaceJIT::TrustedImm32(logStackAlignmentRegisters()), JSInterfaceJIT::regT0);
-    jit.neg32(JSInterfaceJIT::regT0);
+    jit.lshift32(JSInterfaceJIT::TrustedImm32(logStackAlignmentRegisters()), JSInterfaceJIT::argumentGPR0);
+    jit.neg32(JSInterfaceJIT::argumentGPR0);
     jit.move(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::regT3);
-    jit.load32(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, JSStack::ArgumentCount * sizeof(Register)), JSInterfaceJIT::regT2);
-    jit.add32(JSInterfaceJIT::TrustedImm32(JSStack::CallFrameHeaderSize), JSInterfaceJIT::regT2);
+    jit.load32(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, JSStack::ArgumentCount * sizeof(Register)), JSInterfaceJIT::argumentGPR2);
+    jit.add32(JSInterfaceJIT::TrustedImm32(JSStack::CallFrameHeaderSize), JSInterfaceJIT::argumentGPR2);
 
-    // Move current frame down regT0 number of slots
+    // Move current frame down argumentGPR0 number of slots
     JSInterfaceJIT::Label copyLoop(jit.label());
-    jit.load32(JSInterfaceJIT::regT3, JSInterfaceJIT::regT1);
-    jit.store32(JSInterfaceJIT::regT1, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::regT0, JSInterfaceJIT::TimesEight));
-    jit.load32(MacroAssembler::Address(JSInterfaceJIT::regT3, 4), JSInterfaceJIT::regT1);
-    jit.store32(JSInterfaceJIT::regT1, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::regT0, JSInterfaceJIT::TimesEight, 4));
+    jit.load32(JSInterfaceJIT::regT3, JSInterfaceJIT::regT5);
+    jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight));
+    jit.load32(MacroAssembler::Address(JSInterfaceJIT::regT3, 4), JSInterfaceJIT::regT5);
+    jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, 4));
     jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
-    jit.branchSub32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::regT2).linkTo(copyLoop, &jit);
+    jit.branchSub32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2).linkTo(copyLoop, &jit);
 
-    // Fill in regT0 - 1 missing arg slots with undefined
-    jit.move(JSInterfaceJIT::regT0, JSInterfaceJIT::regT2);
-    jit.add32(JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::regT2);
+    // Fill in argumentGPR0 - 1 missing arg slots with undefined
+    jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::argumentGPR2);
+    jit.add32(JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2);
     JSInterfaceJIT::Label fillUndefinedLoop(jit.label());
-    jit.move(JSInterfaceJIT::TrustedImm32(0), JSInterfaceJIT::regT1);
-    jit.store32(JSInterfaceJIT::regT1, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::regT0, JSInterfaceJIT::TimesEight));
-    jit.move(JSInterfaceJIT::TrustedImm32(JSValue::UndefinedTag), JSInterfaceJIT::regT1);
-    jit.store32(JSInterfaceJIT::regT1, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::regT0, JSInterfaceJIT::TimesEight, 4));
+    jit.move(JSInterfaceJIT::TrustedImm32(0), JSInterfaceJIT::regT5);
+    jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight));
+    jit.move(JSInterfaceJIT::TrustedImm32(JSValue::UndefinedTag), JSInterfaceJIT::regT5);
+    jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, 4));
 
     jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
-    jit.branchAdd32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::regT2).linkTo(fillUndefinedLoop, &jit);
+    jit.branchAdd32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2).linkTo(fillUndefinedLoop, &jit);
 
     // Adjust call frame register and stack pointer to account for missing args
-    jit.move(JSInterfaceJIT::regT0, JSInterfaceJIT::regT1);
-    jit.lshift32(JSInterfaceJIT::TrustedImm32(3), JSInterfaceJIT::regT1);
-    jit.addPtr(JSInterfaceJIT::regT1, JSInterfaceJIT::callFrameRegister);
-    jit.addPtr(JSInterfaceJIT::regT1, JSInterfaceJIT::stackPointerRegister);
+    jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::regT5);
+    jit.lshift32(JSInterfaceJIT::TrustedImm32(3), JSInterfaceJIT::regT5);
+    jit.addPtr(JSInterfaceJIT::regT5, JSInterfaceJIT::callFrameRegister);
+    jit.addPtr(JSInterfaceJIT::regT5, JSInterfaceJIT::stackPointerRegister);
 
     // Save the original return PC.
-    jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, CallFrame::returnPCOffset()), GPRInfo::regT1);
-    jit.storePtr(GPRInfo::regT1, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::regT0, JSInterfaceJIT::TimesEight));
+    jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, CallFrame::returnPCOffset()), GPRInfo::regT5);
+    jit.storePtr(GPRInfo::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight));
     
     // Install the new return PC.
-    jit.storePtr(GPRInfo::regT5, JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, CallFrame::returnPCOffset()));
+    jit.storePtr(GPRInfo::argumentGPR1, JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, CallFrame::returnPCOffset()));
     
 #  if CPU(X86)
     jit.push(JSInterfaceJIT::regT4);
index 455b607..9cfa821 100644 (file)
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+# Crash course on the language that this is written in (which I just call
+# "assembly" even though it's more than that):
+#
+# - Mostly gas-style operand ordering. The last operand tends to be the
+#   destination. So "a := b" is written as "mov b, a". But unlike gas,
+#   comparisons are in-order, so "if (a < b)" is written as
+#   "bilt a, b, ...".
+#
+# - "b" = byte, "h" = 16-bit word, "i" = 32-bit word, "p" = pointer.
+#   For 32-bit, "i" and "p" are interchangeable except when an op supports one
+#   but not the other.
+#
+# - In general, valid operands for macro invocations and instructions are
+#   registers (eg "t0"), addresses (eg "4[t0]"), base-index addresses
+#   (eg "7[t0, t1, 2]"), absolute addresses (eg "0xa0000000[]"), or labels
+#   (eg "_foo" or ".foo"). Macro invocations can also take anonymous
+#   macros as operands. Instructions cannot take anonymous macros.
+#
+# - Labels must have names that begin with either "_" or ".".  A "." label
+#   is local and gets renamed before code gen to minimize namespace
+#   pollution. A "_" label is an extern symbol (i.e. ".globl"). The "_"
+#   may or may not be removed during code gen depending on whether the asm
+#   conventions for C name mangling on the target platform mandate a "_"
+#   prefix.
+#
+# - A "macro" is a lambda expression, which may be either anonymous or
+#   named. But this has caveats. "macro" can take zero or more arguments,
+#   which may be macros or any valid operands, but it can only return
+#   code. But you can do Turing-complete things via continuation passing
+#   style: "macro foo (a, b) b(a, a) end foo(foo, foo)". Actually, don't do
+#   that, since you'll just crash the assembler.
+#
+# - An "if" is a conditional on settings. Any identifier supplied in the
+#   predicate of an "if" is assumed to be a #define that is available
+#   during code gen. So you can't use "if" for computation in a macro, but
+#   you can use it to select different pieces of code for different
+#   platforms.
+#
+# - Arguments to macros follow lexical scoping rather than dynamic scoping.
+#   Const's also follow lexical scoping and may override (hide) arguments
+#   or other consts. All variables (arguments and constants) can be bound
+#   to operands. Additionally, arguments (but not constants) can be bound
+#   to macros.
+
+# The following general-purpose registers are available:
+#
+#  - cfr and sp hold the call frame and (native) stack pointer respectively.
+#  They are callee-save registers, and guaranteed to be distinct from all other
+#  registers on all architectures.
+#
+#  - lr is defined on non-X86 architectures (ARM64, ARMv7, ARM,
+#  ARMv7_TRADITIONAL, MIPS, SH4 and CLOOP) and holds the return PC
+#
+#  - pc holds the (native) program counter on 32-bits ARM architectures (ARM,
+#  ARMv7, ARMv7_TRADITIONAL)
+#
+#  - t0, t1, t2, t3, t4 and optionally t5 are temporary registers that can get trashed on
+#  calls, and are pairwise distinct registers. t4 holds the JS program counter, so use
+#  with caution in opcodes (actually, don't use it in opcodes at all, except as PC).
+#
+#  - r0 and r1 are the platform's customary return registers, and thus are
+#  two distinct registers
+#
+#  - a0, a1, a2 and a3 are the platform's customary argument registers, and
+#  thus are pairwise distinct registers. Be mindful that:
+#    + On X86, there are no argument registers. a0 and a1 are edx and
+#    ecx following the fastcall convention, but you should still use the stack
+#    to pass your arguments. The cCall2 and cCall4 macros do this for you.
+#    + On X86_64_WIN, you should allocate space on the stack for the arguments,
+#    and the return convention is weird for > 8 bytes types. The only place we
+#    use > 8 bytes return values is on a cCall, and cCall2 and cCall4 handle
+#    this for you.
+#
+#  - The only registers guaranteed to be caller-saved are r0, r1, a0, a1 and a2, and
+#  you should be mindful of that in functions that are called directly from C.
+#  If you need more registers, you should push and pop them like a good
+#  assembly citizen, because any other register will be callee-saved on X86.
+#
+# You can additionally assume:
+#
+#  - a3, t2, t3, t4 and t5 are never return registers; t0, t1, a0, a1 and a2
+#  can be return registers.
+#
+#  - t4 and t5 are never argument registers, t3 can only be a3, t1 can only be
+#  a1; but t0 and t2 can be either a0 or a2.
+#
+#  - On 64 bits, csr0, csr1, csr2 and optionally csr3, csr4, csr5 and csr6
+#  are available as callee-save registers.
+#  csr0 is used to store the PC base, while the last two csr registers are used
+#  to store special tag values. Don't use them for anything else.
+#
+# Additional platform-specific details (you shouldn't rely on this remaining
+# true):
+#
+#  - For consistency with the baseline JIT, t0 is always r0 (and t1 is always
+#  r1 on 32 bits platforms). You should use the r version when you need return
+#  registers, and the t version otherwise: code using t0 (or t1) should still
+#  work if swapped with e.g. t3, while code using r0 (or r1) should not. There
+#  *may* be legacy code relying on this.
+#
+#  - On all platforms other than X86, t0 can only be a0 and t2 can only be a2.
+#
+#  - On all platforms other than X86 and X86_64, a2 is not a return register.
+#  a2 is r0 on X86 (because we have so few registers) and r1 on X86_64 (because
+#  the ABI enforces it).
+#
+# The following floating-point registers are available:
+#
+#  - ft0-ft5 are temporary floating-point registers that get trashed on calls,
+#  and are pairwise distinct.
+#
+#  - fa0 and fa1 are the platform's customary floating-point argument
+#  registers, and are both distinct. On 64-bits platforms, fa2 and fa3 are
+#  additional floating-point argument registers.
+#
+#  - fr is the platform's customary floating-point return register
+#
+# You can assume that ft1-ft5 or fa1-fa3 are never fr, and that ftX is never
+# faY if X != Y.
+
 # First come the common protocols that both interpreters use. Note that each
 # of these must have an ASSERT() in LLIntData.cpp
 
@@ -107,16 +227,25 @@ const IsInvalidated = 2
 if JSVALUE64
     # - Use a pair of registers to represent the PC: one register for the
     #   base of the bytecodes, and one register for the index.
-    # - The PC base (or PB for short) should be stored in the csr. It will
-    #   get clobbered on calls to other JS code, but will get saved on calls
-    #   to C functions.
+    # - The PC base (or PB for short) must be stored in a callee-save register.
     # - C calls are still given the Instruction* rather than the PC index.
     #   This requires an add before the call, and a sub after.
-    const PC = t5
-    const PB = t6
-    const tagTypeNumber = csr1
-    const tagMask = csr2
-    
+    const PC = t4
+    const PB = csr0
+    if ARM64
+        const tagTypeNumber = csr1
+        const tagMask = csr2
+    elsif X86_64
+        const tagTypeNumber = csr3
+        const tagMask = csr4
+    elsif X86_64_WIN
+        const tagTypeNumber = csr5
+        const tagMask = csr6
+    elsif C_LOOP
+        const tagTypeNumber = csr1
+        const tagMask = csr2
+    end
+
     macro loadisFromInstruction(offset, dest)
         loadis offset * 8[PB, PC, 8], dest
     end
@@ -130,7 +259,7 @@ if JSVALUE64
     end
 
 else
-    const PC = t5
+    const PC = t4
     macro loadisFromInstruction(offset, dest)
         loadis offset * 4[PC], dest
     end
@@ -140,6 +269,12 @@ else
     end
 end
 
+if X86_64_WIN
+    const extraTempReg = t0
+else
+    const extraTempReg = t5
+end
+
 # Constants for reasoning about value representation.
 if BIG_ENDIAN
     const TagOffset = 0
@@ -465,12 +600,12 @@ end
 
 macro restoreStackPointerAfterCall()
     loadp CodeBlock[cfr], t2
-    getFrameRegisterSizeForCodeBlock(t2, t4)
+    getFrameRegisterSizeForCodeBlock(t2, t2)
     if ARMv7
-        subp cfr, t4, t4
-        move t4, sp
+        subp cfr, t2, t2
+        move t2, sp
     else
-        subp cfr, t4, sp
+        subp cfr, t2, sp
     end
 end
 
@@ -494,13 +629,13 @@ end
 macro slowPathForCall(slowPath)
     callCallSlowPath(
         slowPath,
-        macro (callee)
-            btpz t1, .dontUpdateSP
+        macro (callee, calleeFrame)
+            btpz calleeFrame, .dontUpdateSP
             if ARMv7
-                addp CallerFrameAndPCSize, t1, t1
-                move t1, sp
+                addp CallerFrameAndPCSize, calleeFrame, calleeFrame
+                move calleeFrame, sp
             else
-                addp CallerFrameAndPCSize, t1, sp
+                addp CallerFrameAndPCSize, calleeFrame, sp
             end
         .dontUpdateSP:
             if C_LOOP
@@ -596,15 +731,19 @@ macro prologue(codeBlockGetter, codeBlockSetter, osrSlowPath, traceSlowPath)
     if not C_LOOP
         baddis 5, CodeBlock::m_llintExecuteCounter + BaselineExecutionCounter::m_counter[t1], .continue
         if JSVALUE64
-            cCall2(osrSlowPath, cfr, PC)
+            move cfr, a0
+            move PC, a1
+            cCall2(osrSlowPath)
         else
             # We are after the function prologue, but before we have set up sp from the CodeBlock.
             # Temporarily align stack pointer for this call.
             subp 8, sp
-            cCall2(osrSlowPath, cfr, PC)
+            move cfr, a0
+            move PC, a1
+            cCall2(osrSlowPath)
             addp 8, sp
         end
-        btpz t0, .recover
+        btpz r0, .recover
         move cfr, sp # restore the previous sp
         # pop the callerFrame since we will jump to a function that wants to save it
         if ARM64
@@ -615,7 +754,7 @@ macro prologue(codeBlockGetter, codeBlockSetter, osrSlowPath, traceSlowPath)
         else
             pop cfr
         end
-        jmp t0
+        jmp r0
     .recover:
         codeBlockGetter(t1)
     .continue:
@@ -640,8 +779,8 @@ macro prologue(codeBlockGetter, codeBlockSetter, osrSlowPath, traceSlowPath)
     # Stack height check failed - need to call a slow_path.
     subp maxFrameExtentForSlowPathCall, sp # Set up temporary stack pointer for call
     callSlowPath(_llint_stack_check)
-    bpeq t1, 0, .stackHeightOKGetCodeBlock
-    move t1, cfr
+    bpeq r1, 0, .stackHeightOKGetCodeBlock
+    move r1, cfr
     dispatch(0) # Go to exception handler in PC
 
 .stackHeightOKGetCodeBlock:
@@ -738,27 +877,14 @@ if not C_LOOP
     # void sanitizeStackForVMImpl(VM* vm)
     global _sanitizeStackForVMImpl
     _sanitizeStackForVMImpl:
-        if X86_64
-            const vm = t4
-            const address = t1
-            const zeroValue = t0
-        elsif X86_64_WIN
-            const vm = t2
-            const address = t1
-            const zeroValue = t0
-        elsif X86 or X86_WIN
-            const vm = t2
-            const address = t1
-            const zeroValue = t0
-        else
-            const vm = a0
-            const address = t1
-            const zeroValue = t2
-        end
-    
+        # We need three non-aliased caller-save registers. We are guaranteed
+        # this for a0, a1 and a2 on all architectures.
         if X86 or X86_WIN
-            loadp 4[sp], vm
+            loadp 4[sp], a0
         end
+        const vm = a0
+        const address = a1
+        const zeroValue = a2
     
         loadp VM::m_lastStackTop[vm], address
         bpbeq sp, address, .zeroFillDone
@@ -777,22 +903,11 @@ if not C_LOOP
     # VMEntryRecord* vmEntryRecord(const VMEntryFrame* entryFrame)
     global _vmEntryRecord
     _vmEntryRecord:
-        if X86_64
-            const entryFrame = t4
-            const result = t0
-        elsif X86 or X86_WIN or X86_64_WIN
-            const entryFrame = t2
-            const result = t0
-        else
-            const entryFrame = a0
-            const result = t0
-        end
-    
         if X86 or X86_WIN
-            loadp 4[sp], entryFrame
+            loadp 4[sp], a0
         end
-    
-        vmEntryRecord(entryFrame, result)
+
+        vmEntryRecord(a0, r0)
         ret
 end
 
@@ -800,17 +915,12 @@ if C_LOOP
     # Dummy entry point the C Loop uses to initialize.
     _llint_entry:
         crash()
-    else
+else
     macro initPCRelative(pcBase)
-        if X86_64 or X86_64_WIN
+        if X86_64 or X86_64_WIN or X86 or X86_WIN
             call _relativePCBase
         _relativePCBase:
             pop pcBase
-        elsif X86 or X86_WIN
-            call _relativePCBase
-        _relativePCBase:
-            pop pcBase
-            loadp 20[sp], t4
         elsif ARM64
         elsif ARMv7
         _relativePCBase:
@@ -831,41 +941,39 @@ if C_LOOP
         end
 end
 
+# The PC base is in t1, as this is what _llint_entry leaves behind through
+# initPCRelative(t1)
 macro setEntryAddress(index, label)
-    if X86_64
-        leap (label - _relativePCBase)[t1], t0
-        move index, t2
-        storep t0, [t4, t2, 8]
-    elsif X86_64_WIN
-        leap (label - _relativePCBase)[t1], t0
+    if X86_64 or X86_64_WIN
+        leap (label - _relativePCBase)[t1], t3
         move index, t4
-        storep t0, [t2, t4, 8]
+        storep t3, [a0, t4, 8]
     elsif X86 or X86_WIN
-        leap (label - _relativePCBase)[t1], t0
-        move index, t2
-        storep t0, [t4, t2, 4]
+        leap (label - _relativePCBase)[t1], t3
+        move index, t4
+        storep t3, [a0, t4, 4]
     elsif ARM64
         pcrtoaddr label, t1
-        move index, t2
-        storep t1, [a0, t2, 8]
+        move index, t4
+        storep t1, [a0, t4, 8]
     elsif ARM or ARMv7 or ARMv7_TRADITIONAL
-        mvlbl (label - _relativePCBase), t2
-        addp t2, t1, t2
+        mvlbl (label - _relativePCBase), t4
+        addp t4, t1, t4
         move index, t3
-        storep t2, [a0, t3, 4]
+        storep t4, [a0, t3, 4]
     elsif SH4
-        move (label - _relativePCBase), t2
-        addp t2, t1, t2
+        move (label - _relativePCBase), t4
+        addp t4, t1, t4
         move index, t3
-        storep t2, [a0, t3, 4]
+        storep t4, [a0, t3, 4]
         flushcp # Force constant pool flush to avoid "pcrel too far" link error.
     elsif MIPS
-        la label, t2
+        la label, t4
         la _relativePCBase, t3
-        subp t3, t2
-        addp t2, t1, t2
+        subp t3, t4
+        addp t4, t1, t4
         move index, t3
-        storep t2, [a0, t3, 4]
+        storep t4, [a0, t3, 4]
     end
 end
 
@@ -874,6 +982,9 @@ global _llint_entry
 _llint_entry:
     functionPrologue()
     pushCalleeSaves()
+    if X86 or X86_WIN
+        loadp 20[sp], a0
+    end
     initPCRelative(t1)
 
     # Include generated bytecode initialization file.
@@ -1213,16 +1324,16 @@ _llint_op_call_varargs:
     traceExecution()
     callSlowPath(_llint_slow_path_size_frame_for_varargs)
     branchIfException(_llint_throw_from_slow_path_trampoline)
-    # calleeFrame in t1
+    # calleeFrame in r1
     if JSVALUE64
-        move t1, sp
+        move r1, sp
     else
         # The calleeFrame is not stack aligned, move down by CallerFrameAndPCSize to align
         if ARMv7
-            subp t1, CallerFrameAndPCSize, t2
+            subp r1, CallerFrameAndPCSize, t2
             move t2, sp
         else
-            subp t1, CallerFrameAndPCSize, sp
+            subp r1, CallerFrameAndPCSize, sp
         end
     end
     slowPathForCall(_llint_slow_path_call_varargs)
@@ -1231,16 +1342,16 @@ _llint_op_construct_varargs:
     traceExecution()
     callSlowPath(_llint_slow_path_size_frame_for_varargs)
     branchIfException(_llint_throw_from_slow_path_trampoline)
-    # calleeFrame in t1
+    # calleeFrame in r1
     if JSVALUE64
-        move t1, sp
+        move r1, sp
     else
         # The calleeFrame is not stack aligned, move down by CallerFrameAndPCSize to align
         if ARMv7
-            subp t1, CallerFrameAndPCSize, t2
+            subp r1, CallerFrameAndPCSize, t2
             move t2, sp
         else
-            subp t1, CallerFrameAndPCSize, sp
+            subp r1, CallerFrameAndPCSize, sp
         end
     end
     slowPathForCall(_llint_slow_path_construct_varargs)
index 92e3ec8..eb697fb 100644 (file)
 # THE POSSIBILITY OF SUCH DAMAGE.
 
 
-# Crash course on the language that this is written in (which I just call
-# "assembly" even though it's more than that):
-#
-# - Mostly gas-style operand ordering. The last operand tends to be the
-#   destination. So "a := b" is written as "mov b, a". But unlike gas,
-#   comparisons are in-order, so "if (a < b)" is written as
-#   "bilt a, b, ...".
-#
-# - "b" = byte, "h" = 16-bit word, "i" = 32-bit word, "p" = pointer.
-#   Currently this is just 32-bit so "i" and "p" are interchangeable
-#   except when an op supports one but not the other.
-#
-# - In general, valid operands for macro invocations and instructions are
-#   registers (eg "t0"), addresses (eg "4[t0]"), base-index addresses
-#   (eg "7[t0, t1, 2]"), absolute addresses (eg "0xa0000000[]"), or labels
-#   (eg "_foo" or ".foo"). Macro invocations can also take anonymous
-#   macros as operands. Instructions cannot take anonymous macros.
-#
-# - Labels must have names that begin with either "_" or ".".  A "." label
-#   is local and gets renamed before code gen to minimize namespace
-#   pollution. A "_" label is an extern symbol (i.e. ".globl"). The "_"
-#   may or may not be removed during code gen depending on whether the asm
-#   conventions for C name mangling on the target platform mandate a "_"
-#   prefix.
-#
-# - A "macro" is a lambda expression, which may be either anonymous or
-#   named. But this has caveats. "macro" can take zero or more arguments,
-#   which may be macros or any valid operands, but it can only return
-#   code. But you can do Turing-complete things via continuation passing
-#   style: "macro foo (a, b) b(a) end foo(foo, foo)". Actually, don't do
-#   that, since you'll just crash the assembler.
-#
-# - An "if" is a conditional on settings. Any identifier supplied in the
-#   predicate of an "if" is assumed to be a #define that is available
-#   during code gen. So you can't use "if" for computation in a macro, but
-#   you can use it to select different pieces of code for different
-#   platforms.
-#
-# - Arguments to macros follow lexical scoping rather than dynamic scoping.
-#   Const's also follow lexical scoping and may override (hide) arguments
-#   or other consts. All variables (arguments and constants) can be bound
-#   to operands. Additionally, arguments (but not constants) can be bound
-#   to macros.
-
-
-# Below we have a bunch of constant declarations. Each constant must have
-# a corresponding ASSERT() in LLIntData.cpp.
-
 # Utilities
 macro dispatch(advance)
     addp advance * 4, PC
@@ -89,60 +41,47 @@ end
 
 macro dispatchAfterCall()
     loadi ArgumentCount + TagOffset[cfr], PC
-    loadi 4[PC], t2
-    storei t1, TagOffset[cfr, t2, 8]
-    storei t0, PayloadOffset[cfr, t2, 8]
-    valueProfile(t1, t0, 4 * (CallOpCodeSize - 1), t3)
+    loadi 4[PC], t3
+    storei r1, TagOffset[cfr, t3, 8]
+    storei r0, PayloadOffset[cfr, t3, 8]
+    valueProfile(r1, r0, 4 * (CallOpCodeSize - 1), t3)
     dispatch(CallOpCodeSize)
 end
 
-macro cCall2(function, arg1, arg2)
-    if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS
-        move arg1, a0
-        move arg2, a1
+macro cCall2(function)
+    if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS or SH4
         call function
     elsif X86 or X86_WIN
         subp 8, sp
-        push arg2
-        push arg1
+        push a1
+        push a0
         call function
         addp 16, sp
-    elsif SH4
-        setargs arg1, arg2
-        call function
     elsif C_LOOP
-        cloopCallSlowPath function, arg1, arg2
+        cloopCallSlowPath function, a0, a1
     else
         error
     end
 end
 
-macro cCall2Void(function, arg1, arg2)
+macro cCall2Void(function)
     if C_LOOP
-        cloopCallSlowPathVoid function, arg1, arg2
+        cloopCallSlowPathVoid function, a0, a1
     else
-        cCall2(function, arg1, arg2)
+        cCall2(function)
     end
 end
 
-# This barely works. arg3 and arg4 should probably be immediates.
-macro cCall4(function, arg1, arg2, arg3, arg4)
-    if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS
-        move arg1, a0
-        move arg2, a1
-        move arg3, a2
-        move arg4, a3
+macro cCall4(function)
+    if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS or SH4
         call function
     elsif X86 or X86_WIN
-        push arg4
-        push arg3
-        push arg2
-        push arg1
+        push a3
+        push a2
+        push a1
+        push a0
         call function
         addp 16, sp
-    elsif SH4
-        setargs arg1, arg2, arg3, arg4
-        call function
     elsif C_LOOP
         error
     else
@@ -151,133 +90,105 @@ macro cCall4(function, arg1, arg2, arg3, arg4)
 end
 
 macro callSlowPath(slowPath)
-    cCall2(slowPath, cfr, PC)
-    move t0, PC
+    move cfr, a0
+    move PC, a1
+    cCall2(slowPath)
+    move r0, PC
 end
 
 macro doVMEntry(makeCall)
-    if X86 or X86_WIN
-        const entry = t4
-        const vm = t3
-        const protoCallFrame = t5
-
-        const temp1 = t0
-        const temp2 = t1
-        const temp3 = t2
-        const temp4 = t3 # same as vm
-    elsif ARM or ARMv7 or ARMv7_TRADITIONAL or C_LOOP
-        const entry = a0
-        const vm = a1
-        const protoCallFrame = a2
-
-        const temp1 = t3
-        const temp2 = t4
-        const temp3 = t5
-        const temp4 = t4 # Same as temp2
-    elsif MIPS
-        const entry = a0
-        const vm = a1
-        const protoCallFrame = a2
-
-        const temp1 = t3
-        const temp2 = t5
-        const temp3 = t4
-        const temp4 = t6
-    elsif SH4
-        const entry = a0
-        const vm = a1
-        const protoCallFrame = a2
-
-        const temp1 = t3
-        const temp2 = a3
-        const temp3 = t8
-        const temp4 = t9
-    end
-
     functionPrologue()
     pushCalleeSaves()
 
+    # x86 needs to load arguments from the stack
     if X86 or X86_WIN
-        loadp 12[cfr], vm
-        loadp 8[cfr], entry
+        loadp 16[cfr], a2
+        loadp 12[cfr], a1
+        loadp 8[cfr], a0
     end
 
+    const entry = a0
+    const vm = a1
+    const protoCallFrame = a2
+
+    # We are using t3, t4 and t5 as temporaries through the function.
+    # Since we have the guarantee that tX != aY when X != Y, we are safe from
+    # aliasing problems with our arguments.
+
     if ARMv7
-        vmEntryRecord(cfr, temp1)
-        move temp1, sp
+        vmEntryRecord(cfr, t3)
+        move t3, sp
     else
         vmEntryRecord(cfr, sp)
     end
 
     storep vm, VMEntryRecord::m_vm[sp]
-    loadp VM::topCallFrame[vm], temp2
-    storep temp2, VMEntryRecord::m_prevTopCallFrame[sp]
-    loadp VM::topVMEntryFrame[vm], temp2
-    storep temp2, VMEntryRecord::m_prevTopVMEntryFrame[sp]
+    loadp VM::topCallFrame[vm], t4
+    storep t4, VMEntryRecord::m_prevTopCallFrame[sp]
+    loadp VM::topVMEntryFrame[vm], t4
+    storep t4, VMEntryRecord::m_prevTopVMEntryFrame[sp]
 
     # Align stack pointer
     if X86_WIN
-        addp CallFrameAlignSlots * SlotSize, sp, temp1
-        andp ~StackAlignmentMask, temp1
-        subp temp1, CallFrameAlignSlots * SlotSize, sp
+        addp CallFrameAlignSlots * SlotSize, sp, t3
+        andp ~StackAlignmentMask, t3
+        subp t3, CallFrameAlignSlots * SlotSize, sp
     elsif ARM or ARMv7 or ARMv7_TRADITIONAL
-        addp CallFrameAlignSlots * SlotSize, sp, temp1
-        clrbp temp1, StackAlignmentMask, temp1
+        addp CallFrameAlignSlots * SlotSize, sp, t3
+        clrbp t3, StackAlignmentMask, t3
         if ARMv7
-            subp temp1, CallFrameAlignSlots * SlotSize, temp1
-            move temp1, sp
+            subp t3, CallFrameAlignSlots * SlotSize, t3
+            move t3, sp
         else
-            subp temp1, CallFrameAlignSlots * SlotSize, sp
+            subp t3, CallFrameAlignSlots * SlotSize, sp
         end
     end
 
-    if X86 or X86_WIN
-        loadp 16[cfr], protoCallFrame
-    end
-
-    loadi ProtoCallFrame::paddedArgCount[protoCallFrame], temp2
-    addp CallFrameHeaderSlots, temp2, temp2
-    lshiftp 3, temp2
-    subp sp, temp2, temp1
+    loadi ProtoCallFrame::paddedArgCount[protoCallFrame], t4
+    addp CallFrameHeaderSlots, t4, t4
+    lshiftp 3, t4
+    subp sp, t4, t3
 
     # Ensure that we have enough additional stack capacity for the incoming args,
     # and the frame for the JS code we're executing. We need to do this check
     # before we start copying the args from the protoCallFrame below.
-    bpaeq temp1, VM::m_jsStackLimit[vm], .stackHeightOK
+    bpaeq t3, VM::m_jsStackLimit[vm], .stackHeightOK
 
     if C_LOOP
-        move entry, temp2
-        move vm, temp3
-        cloopCallSlowPath _llint_stack_check_at_vm_entry, vm, temp1
+        move entry, t4
+        move vm, t5
+        cloopCallSlowPath _llint_stack_check_at_vm_entry, vm, t3
         bpeq t0, 0, .stackCheckFailed
-        move temp2, entry
-        move temp3, vm
+        move t4, entry
+        move t5, vm
         jmp .stackHeightOK
 
 .stackCheckFailed:
-        move temp2, entry
-        move temp3, vm
+        move t4, entry
+        move t5, vm
     end
 
     subp 8, sp # Align stack for cCall2() to make a call.
-    cCall2(_llint_throw_stack_overflow_error, vm, protoCallFrame)
+    move vm, a0
+    move protoCallFrame, a1
+    cCall2(_llint_throw_stack_overflow_error)
 
     if ARMv7
-        vmEntryRecord(cfr, temp1)
-        move temp1, sp
+        vmEntryRecord(cfr, t3)
+        move t3, sp
     else
         vmEntryRecord(cfr, sp)
     end
 
-    loadp VMEntryRecord::m_vm[sp], temp3
-    loadp VMEntryRecord::m_prevTopCallFrame[sp], temp4
-    storep temp4, VM::topCallFrame[temp3]
-    loadp VMEntryRecord::m_prevTopVMEntryFrame[sp], temp4
-    storep temp4, VM::topVMEntryFrame[temp3]
+    loadp VMEntryRecord::m_vm[sp], t5
+    loadp VMEntryRecord::m_prevTopCallFrame[sp], t4
+    storep t4, VM::topCallFrame[t5]
+    loadp VMEntryRecord::m_prevTopVMEntryFrame[sp], t4
+    storep t4, VM::topVMEntryFrame[t5]
 
     if ARMv7
-        subp cfr, CalleeRegisterSaveSize, temp3
-        move temp3, sp
+        subp cfr, CalleeRegisterSaveSize, t5
+        move t5, sp
     else
         subp cfr, CalleeRegisterSaveSize, sp
     end
@@ -287,63 +198,63 @@ macro doVMEntry(makeCall)
     ret
 
 .stackHeightOK:
-    move temp1, sp
-    move 4, temp1
+    move t3, sp
+    move 4, t3
 
 .copyHeaderLoop:
-    subi 1, temp1
-    loadi TagOffset[protoCallFrame, temp1, 8], temp3
-    storei temp3, TagOffset + CodeBlock[sp, temp1, 8]
-    loadi PayloadOffset[protoCallFrame, temp1, 8], temp3
-    storei temp3, PayloadOffset + CodeBlock[sp, temp1, 8]
-    btinz temp1, .copyHeaderLoop
-
-    loadi PayloadOffset + ProtoCallFrame::argCountAndCodeOriginValue[protoCallFrame], temp2
-    subi 1, temp2
-    loadi ProtoCallFrame::paddedArgCount[protoCallFrame], temp3
-    subi 1, temp3
-
-    bieq temp2, temp3, .copyArgs
+    subi 1, t3
+    loadi TagOffset[protoCallFrame, t3, 8], t5
+    storei t5, TagOffset + CodeBlock[sp, t3, 8]
+    loadi PayloadOffset[protoCallFrame, t3, 8], t5
+    storei t5, PayloadOffset + CodeBlock[sp, t3, 8]
+    btinz t3, .copyHeaderLoop
+
+    loadi PayloadOffset + ProtoCallFrame::argCountAndCodeOriginValue[protoCallFrame], t4
+    subi 1, t4
+    loadi ProtoCallFrame::paddedArgCount[protoCallFrame], t5
+    subi 1, t5
+
+    bieq t4, t5, .copyArgs
 .fillExtraArgsLoop:
-    subi 1, temp3
-    storei UndefinedTag, ThisArgumentOffset + 8 + TagOffset[sp, temp3, 8]
-    storei 0, ThisArgumentOffset + 8 + PayloadOffset[sp, temp3, 8]
-    bineq temp2, temp3, .fillExtraArgsLoop
+    subi 1, t5
+    storei UndefinedTag, ThisArgumentOffset + 8 + TagOffset[sp, t5, 8]
+    storei 0, ThisArgumentOffset + 8 + PayloadOffset[sp, t5, 8]
+    bineq t4, t5, .fillExtraArgsLoop
 
 .copyArgs:
-    loadp ProtoCallFrame::args[protoCallFrame], temp1
+    loadp ProtoCallFrame::args[protoCallFrame], t3
 
 .copyArgsLoop:
-    btiz temp2, .copyArgsDone
-    subi 1, temp2
-    loadi TagOffset[temp1, temp2, 8], temp3
-    storei temp3, ThisArgumentOffset + 8 + TagOffset[sp, temp2, 8]
-    loadi PayloadOffset[temp1, temp2, 8], temp3
-    storei temp3, ThisArgumentOffset + 8 + PayloadOffset[sp, temp2, 8]
+    btiz t4, .copyArgsDone
+    subi 1, t4
+    loadi TagOffset[t3, t4, 8], t5
+    storei t5, ThisArgumentOffset + 8 + TagOffset[sp, t4, 8]
+    loadi PayloadOffset[t3, t4, 8], t5
+    storei t5, ThisArgumentOffset + 8 + PayloadOffset[sp, t4, 8]
     jmp .copyArgsLoop
 
 .copyArgsDone:
     storep sp, VM::topCallFrame[vm]
     storep cfr, VM::topVMEntryFrame[vm]
 
-    makeCall(entry, temp1, temp2)
+    makeCall(entry, t3, t4)
 
     if ARMv7
-        vmEntryRecord(cfr, temp1)
-        move temp1, sp
+        vmEntryRecord(cfr, t3)
+        move t3, sp
     else
         vmEntryRecord(cfr, sp)
     end
 
-    loadp VMEntryRecord::m_vm[sp], temp3
-    loadp VMEntryRecord::m_prevTopCallFrame[sp], temp4
-    storep temp4, VM::topCallFrame[temp3]
-    loadp VMEntryRecord::m_prevTopVMEntryFrame[sp], temp4
-    storep temp4, VM::topVMEntryFrame[temp3]
+    loadp VMEntryRecord::m_vm[sp], t5
+    loadp VMEntryRecord::m_prevTopCallFrame[sp], t4
+    storep t4, VM::topCallFrame[t5]
+    loadp VMEntryRecord::m_prevTopVMEntryFrame[sp], t4
+    storep t4, VM::topVMEntryFrame[t5]
 
     if ARMv7
-        subp cfr, CalleeRegisterSaveSize, temp3
-        move temp3, sp
+        subp cfr, CalleeRegisterSaveSize, t5
+        move t5, sp
     else
         subp cfr, CalleeRegisterSaveSize, sp
     end
@@ -355,13 +266,13 @@ end
 
 macro makeJavaScriptCall(entry, temp, unused)
     addp CallerFrameAndPCSize, sp
-    checkStackPointerAlignment(t2, 0xbad0dc02)
+    checkStackPointerAlignment(temp, 0xbad0dc02)
     if C_LOOP
         cloopCallJSFunction entry
     else
         call entry
     end
-    checkStackPointerAlignment(t2, 0xbad0dc03)
+    checkStackPointerAlignment(temp, 0xbad0dc03)
     subp CallerFrameAndPCSize, sp
 end
 
@@ -376,9 +287,9 @@ macro makeHostFunctionCall(entry, temp1, temp2)
         # Put callee frame pointer on stack as arg0, also put it in ecx for "fastcall" targets
         move 0, temp2
         move temp2, 4[sp] # put 0 in ReturnPC
-        move sp, t2 # t2 is ecx
+        move sp, a0 # a0 is ecx
         push temp2 # Push dummy arg1
-        push t2
+        push a0
         call temp1
         addp 8, sp
     else
@@ -429,31 +340,43 @@ end
 # debugging from. operand should likewise be an immediate, and should identify the operand
 # in the instruction stream you'd like to print out.
 macro traceOperand(fromWhere, operand)
-    cCall4(_llint_trace_operand, cfr, PC, fromWhere, operand)
-    move t0, PC
-    move t1, cfr
+    move fromWhere, a2
+    move operand, a3
+    move cfr, a0
+    move PC, a1
+    cCall4(_llint_trace_operand)
+    move r0, PC
+    move r1, cfr
 end
 
 # Debugging operation if you'd like to print the value of an operand in the instruction
 # stream. Same as traceOperand(), but assumes that the operand is a register, and prints its
 # value.
 macro traceValue(fromWhere, operand)
-    cCall4(_llint_trace_value, cfr, PC, fromWhere, operand)
-    move t0, PC
-    move t1, cfr
+    move fromWhere, a2
+    move operand, a3
+    move cfr, a0
+    move PC, a1
+    cCall4(_llint_trace_value)
+    move r0, PC
+    move r1, cfr
 end
 
 # Call a slowPath for call opcodes.
 macro callCallSlowPath(slowPath, action)
     storep PC, ArgumentCount + TagOffset[cfr]
-    cCall2(slowPath, cfr, PC)
-    action(t0)
+    move cfr, a0
+    move PC, a1
+    cCall2(slowPath)
+    action(r0, r1)
 end
 
 macro callWatchdogTimerHandler(throwHandler)
     storei PC, ArgumentCount + TagOffset[cfr]
-    cCall2(_llint_slow_path_handle_watchdog_timer, cfr, PC)
-    btpnz t0, throwHandler
+    move cfr, a0
+    move PC, a1
+    cCall2(_llint_slow_path_handle_watchdog_timer)
+    btpnz r0, throwHandler
     loadi ArgumentCount + TagOffset[cfr], PC
 end
 
@@ -462,10 +385,12 @@ macro checkSwitchToJITForLoop()
         1,
         macro ()
             storei PC, ArgumentCount + TagOffset[cfr]
-            cCall2(_llint_loop_osr, cfr, PC)
-            btpz t0, .recover
-            move t1, sp
-            jmp t0
+            move cfr, a0
+            move PC, a1
+            cCall2(_llint_loop_osr)
+            btpz r0, .recover
+            move r1, sp
+            jmp r0
         .recover:
             loadi ArgumentCount + TagOffset[cfr], PC
         end)
@@ -576,7 +501,9 @@ macro writeBarrierOnOperand(cellOperand)
                 push cfr, PC
                 # We make two extra slots because cCall2 will poke.
                 subp 8, sp
-                cCall2Void(_llint_write_barrier_slow, cfr, t2)
+                move t2, a1 # t2 can be a0 on x86
+                move cfr, a0
+                cCall2Void(_llint_write_barrier_slow)
                 addp 8, sp
                 pop PC, cfr
             end
@@ -610,7 +537,9 @@ macro writeBarrierOnGlobal(valueOperand, loadHelper)
                 push cfr, PC
                 # We make two extra slots because cCall2 will poke.
                 subp 8, sp
-                cCall2Void(_llint_write_barrier_slow, cfr, t3)
+                move cfr, a0
+                move t3, a1
+                cCall2Void(_llint_write_barrier_slow)
                 addp 8, sp
                 pop PC, cfr
             end
@@ -649,19 +578,21 @@ end
 macro functionArityCheck(doneLabel, slowPath)
     loadi PayloadOffset + ArgumentCount[cfr], t0
     biaeq t0, CodeBlock::m_numParameters[t1], doneLabel
-    cCall2(slowPath, cfr, PC)   # This slowPath has a simple protocol: t0 = 0 => no error, t0 != 0 => error
-    btiz t0, .noError
-    move t1, cfr   # t1 contains caller frame
+    move cfr, a0
+    move PC, a1
+    cCall2(slowPath)   # This slowPath has a simple protocol: t0 = 0 => no error, t0 != 0 => error
+    btiz r0, .noError
+    move r1, cfr   # r1 contains caller frame
     jmp _llint_throw_from_slow_path_trampoline
 
 .noError:
-    # t1 points to ArityCheckData.
-    loadp CommonSlowPaths::ArityCheckData::thunkToCall[t1], t2
-    btpz t2, .proceedInline
+    # r1 points to ArityCheckData.
+    loadp CommonSlowPaths::ArityCheckData::thunkToCall[r1], t3
+    btpz t3, .proceedInline
     
-    loadp CommonSlowPaths::ArityCheckData::returnPC[t1], t5
-    loadp CommonSlowPaths::ArityCheckData::paddedStackSpace[t1], t0
-    call t2
+    loadp CommonSlowPaths::ArityCheckData::paddedStackSpace[r1], a0
+    loadp CommonSlowPaths::ArityCheckData::returnPC[r1], a1
+    call t3
     if ASSERT_ENABLED
         loadp ReturnPC[cfr], t0
         loadp [t0], t0
@@ -669,7 +600,7 @@ macro functionArityCheck(doneLabel, slowPath)
     jmp .continue
 
 .proceedInline:
-    loadi CommonSlowPaths::ArityCheckData::paddedStackSpace[t1], t1
+    loadi CommonSlowPaths::ArityCheckData::paddedStackSpace[r1], t1
     btiz t1, .continue
 
     // Move frame up "t1 * 2" slots
@@ -751,14 +682,14 @@ _llint_op_create_this:
     traceExecution()
     loadi 8[PC], t0
     loadp PayloadOffset[cfr, t0, 8], t0
-    loadp JSFunction::m_rareData[t0], t4
-    btpz t4, .opCreateThisSlow
-    loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_allocator[t4], t1
-    loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_structure[t4], t2
+    loadp JSFunction::m_rareData[t0], t5
+    btpz t5, .opCreateThisSlow
+    loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_allocator[t5], t1
+    loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_structure[t5], t2
     btpz t1, .opCreateThisSlow
-    loadpFromInstruction(4, t4)
-    bpeq t4, 1, .hasSeenMultipleCallee
-    bpneq t4, t0, .opCreateThisSlow
+    loadpFromInstruction(4, t5)
+    bpeq t5, 1, .hasSeenMultipleCallee
+    bpneq t5, t0, .opCreateThisSlow
 .hasSeenMultipleCallee:
     allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow)
     loadi 4[PC], t1
@@ -2006,8 +1937,8 @@ macro nativeCallTrampoline(executableOffsetToFunction)
         andp MarkedBlockMask, t1
         loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t3
         storep cfr, VM::topCallFrame[t3]
-        move cfr, t2  # t2 = ecx
-        storep t2, [sp]
+        move cfr, a0  # a0 = ecx
+        storep a0, [sp]
         loadi Callee + PayloadOffset[cfr], t1
         loadp JSFunction::m_executable[t1], t1
         checkStackPointerAlignment(t3, 0xdead0001)
@@ -2022,11 +1953,7 @@ macro nativeCallTrampoline(executableOffsetToFunction)
         andp MarkedBlockMask, t1
         loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t1
         storep cfr, VM::topCallFrame[t1]
-        if MIPS or SH4
-            move cfr, a0
-        else
-            move cfr, t0
-        end
+        move cfr, a0
         loadi Callee + PayloadOffset[cfr], t1
         loadp JSFunction::m_executable[t1], t1
         checkStackPointerAlignment(t3, 0xdead0001)
@@ -2269,9 +2196,9 @@ end
 macro putLocalClosureVar()
     loadisFromInstruction(3, t1)
     loadConstantOrVariable(t1, t2, t3)
-    loadpFromInstruction(5, t4)
-    btpz t4, .noVariableWatchpointSet
-    notifyWrite(t4, .pDynamic)
+    loadpFromInstruction(5, t5)
+    btpz t5, .noVariableWatchpointSet
+    notifyWrite(t5, .pDynamic)
 .noVariableWatchpointSet:
     loadisFromInstruction(6, t1)
     storei t2, JSEnvironmentRecord_variables + TagOffset[t0, t1, 8]
@@ -2396,9 +2323,9 @@ _llint_op_profile_type:
     # t1 is holding the pointer to the typeProfilerLog.
     loadp VM::m_typeProfilerLog[t1], t1
 
-    # t0 is holding the payload, t4 is holding the tag.
+    # t0 is holding the payload, t5 is holding the tag.
     loadisFromInstruction(1, t2)
-    loadConstantOrVariable(t2, t4, t0)
+    loadConstantOrVariable(t2, t5, t0)
 
     bieq t4, EmptyValueTag, .opProfileTypeDone
 
@@ -2406,14 +2333,14 @@ _llint_op_profile_type:
     loadp TypeProfilerLog::m_currentLogEntryPtr[t1], t2
 
     # Store the JSValue onto the log entry.
-    storei t4, TypeProfilerLog::LogEntry::value + TagOffset[t2]
+    storei t5, TypeProfilerLog::LogEntry::value + TagOffset[t2]
     storei t0, TypeProfilerLog::LogEntry::value + PayloadOffset[t2]
 
     # Store the TypeLocation onto the log entry.
     loadpFromInstruction(2, t3)
     storep t3, TypeProfilerLog::LogEntry::location[t2]
 
-    bieq t4, CellTag, .opProfileTypeIsCell
+    bieq t5, CellTag, .opProfileTypeIsCell
     storei 0, TypeProfilerLog::LogEntry::structureID[t2]
     jmp .opProfileTypeSkipIsCell
 .opProfileTypeIsCell:
index 7f338da..1f321ca 100644 (file)
@@ -46,177 +46,127 @@ macro dispatchAfterCall()
     loadp CodeBlock[cfr], PB
     loadp CodeBlock::m_instructions[PB], PB
     loadisFromInstruction(1, t1)
-    storeq t0, [cfr, t1, 8]
-    valueProfile(t0, (CallOpCodeSize - 1), t2)
+    storeq r0, [cfr, t1, 8]
+    valueProfile(r0, (CallOpCodeSize - 1), t3)
     dispatch(CallOpCodeSize)
 end
 
-macro cCall2(function, arg1, arg2)
+macro cCall2(function)
     checkStackPointerAlignment(t4, 0xbad0c002)
-    if X86_64
-        move arg1, t4
-        move arg2, t5
+    if X86_64 or ARM64
         call function
     elsif X86_64_WIN
         # Note: this implementation is only correct if the return type size is > 8 bytes.
         # See macro cCall2Void for an implementation when the return type <= 8 bytes.
         # On Win64, when the return type is larger than 8 bytes, we need to allocate space on the stack for the return value.
-        # On entry rcx (t2), should contain a pointer to this stack space. The other parameters are shifted to the right,
-        # rdx (t1) should contain the first argument, and r8 (t6) should contain the second argument.
-        # On return, rax contains a pointer to this stack value, and we then need to copy the 16 byte return value into rax (t0) and rdx (t1)
+        # On entry rcx (a0), should contain a pointer to this stack space. The other parameters are shifted to the right,
+        # rdx (a1) should contain the first argument, and r8 (a2) should contain the second argument.
+        # On return, rax contains a pointer to this stack value, and we then need to copy the 16 byte return value into rax (r0) and rdx (r1)
         # since the return value is expected to be split between the two.
         # See http://msdn.microsoft.com/en-us/library/7572ztz4.aspx
-        move arg1, t1
-        move arg2, t6
+        move a1, a2
+        move a0, a1
         subp 48, sp
-        move sp, t2
-        addp 32, t2
+        move sp, a0
+        addp 32, a0
         call function
         addp 48, sp
-        move 8[t0], t1
-        move [t0], t0
-    elsif ARM64
-        move arg1, t0
-        move arg2, t1
-        call function
+        move 8[r0], r1
+        move [r0], r0
     elsif C_LOOP
-        cloopCallSlowPath function, arg1, arg2
+        cloopCallSlowPath function, a0, a1
     else
         error
     end
 end
 
-macro cCall2Void(function, arg1, arg2)
+macro cCall2Void(function)
     if C_LOOP
-        cloopCallSlowPathVoid function, arg1, arg2
+        cloopCallSlowPathVoid function, a0, a1
     elsif X86_64_WIN
         # Note: we cannot use the cCall2 macro for Win64 in this case,
         # as the Win64 cCall2 implemenation is only correct when the return type size is > 8 bytes.
         # On Win64, rcx and rdx are used for passing the first two parameters.
         # We also need to make room on the stack for all four parameter registers.
         # See http://msdn.microsoft.com/en-us/library/ms235286.aspx
-        move arg2, t1
-        move arg1, t2
         subp 32, sp 
         call function
         addp 32, sp 
     else
-        cCall2(function, arg1, arg2)
+        cCall2(function)
     end
 end
 
 # This barely works. arg3 and arg4 should probably be immediates.
-macro cCall4(function, arg1, arg2, arg3, arg4)
+macro cCall4(function)
     checkStackPointerAlignment(t4, 0xbad0c004)
-    if X86_64
-        move arg1, t4
-        move arg2, t5
-        move arg3, t1
-        move arg4, t2
+    if X86_64 or ARM64
         call function
     elsif X86_64_WIN
         # On Win64, rcx, rdx, r8, and r9 are used for passing the first four parameters.
         # We also need to make room on the stack for all four parameter registers.
         # See http://msdn.microsoft.com/en-us/library/ms235286.aspx
-        move arg1, t2
-        move arg2, t1
-        move arg3, t6
-        move arg4, t7
-        subp 32, sp 
+        subp 64, sp
         call function
-        addp 32, sp 
-    elsif ARM64
-        move arg1, t0
-        move arg2, t1
-        move arg3, t2
-        move arg4, t3
-        call function
-    elsif C_LOOP
-        error
+        addp 64, sp
     else
         error
     end
 end
 
 macro doVMEntry(makeCall)
-    if X86_64
-        const entry = t4
-        const vm = t5
-        const protoCallFrame = t1
-
-        const previousCFR = t0
-        const previousPC = t6
-        const temp1 = t0
-        const temp2 = t3
-        const temp3 = t6
-    elsif X86_64_WIN
-        const entry = t2
-        const vm = t1
-        const protoCallFrame = t6
-
-        const previousCFR = t0
-        const previousPC = t4
-        const temp1 = t0
-        const temp2 = t3
-        const temp3 = t7
-    elsif ARM64 or C_LOOP
-        const entry = a0
-        const vm = a1
-        const protoCallFrame = a2
-
-        const previousCFR = t5
-        const previousPC = lr
-        const temp1 = t3
-        const temp2 = t4
-        const temp3 = t6
-    end
-
     functionPrologue()
     pushCalleeSaves()
 
+    const entry = a0
+    const vm = a1
+    const protoCallFrame = a2
+
     vmEntryRecord(cfr, sp)
 
-    checkStackPointerAlignment(temp2, 0xbad0dc01)
+    checkStackPointerAlignment(t4, 0xbad0dc01)
 
     storep vm, VMEntryRecord::m_vm[sp]
-    loadp VM::topCallFrame[vm], temp2
-    storep temp2, VMEntryRecord::m_prevTopCallFrame[sp]
-    loadp VM::topVMEntryFrame[vm], temp2
-    storep temp2, VMEntryRecord::m_prevTopVMEntryFrame[sp]
+    loadp VM::topCallFrame[vm], t4
+    storep t4, VMEntryRecord::m_prevTopCallFrame[sp]
+    loadp VM::topVMEntryFrame[vm], t4
+    storep t4, VMEntryRecord::m_prevTopVMEntryFrame[sp]
 
-    loadi ProtoCallFrame::paddedArgCount[protoCallFrame], temp2
-    addp CallFrameHeaderSlots, temp2, temp2
-    lshiftp 3, temp2
-    subp sp, temp2, temp1
+    loadi ProtoCallFrame::paddedArgCount[protoCallFrame], t4
+    addp CallFrameHeaderSlots, t4, t4
+    lshiftp 3, t4
+    subp sp, t4, t3
 
     # Ensure that we have enough additional stack capacity for the incoming args,
     # and the frame for the JS code we're executing. We need to do this check
     # before we start copying the args from the protoCallFrame below.
-    bpaeq temp1, VM::m_jsStackLimit[vm], .stackHeightOK
+    bpaeq t3, VM::m_jsStackLimit[vm], .stackHeightOK
 
     if C_LOOP
-        move entry, temp2
-        move vm, temp3
-        cloopCallSlowPath _llint_stack_check_at_vm_entry, vm, temp1
+        move entry, t4
+        move vm, t5
+        cloopCallSlowPath _llint_stack_check_at_vm_entry, vm, t3
         bpeq t0, 0, .stackCheckFailed
-        move temp2, entry
-        move temp3, vm
+        move t4, entry
+        move t5, vm
         jmp .stackHeightOK
 
 .stackCheckFailed:
-        move temp2, entry
-        move temp3, vm
+        move t4, entry
+        move t5, vm
     end
 
-    cCall2(_llint_throw_stack_overflow_error, vm, protoCallFrame)
+    move vm, a0
+    move protoCallFrame, a1
+    cCall2(_llint_throw_stack_overflow_error)
 
-    vmEntryRecord(cfr, temp2)
+    vmEntryRecord(cfr, t4)
 
-    loadp VMEntryRecord::m_vm[temp2], vm
-    loadp VMEntryRecord::m_prevTopCallFrame[temp2], temp3
-    storep temp3, VM::topCallFrame[vm]
-    loadp VMEntryRecord::m_prevTopVMEntryFrame[temp2], temp3
-    storep temp3, VM::topVMEntryFrame[vm]
+    loadp VMEntryRecord::m_vm[t4], vm
+    loadp VMEntryRecord::m_prevTopCallFrame[t4], extraTempReg
+    storep extraTempReg, VM::topCallFrame[vm]
+    loadp VMEntryRecord::m_prevTopVMEntryFrame[t4], extraTempReg
+    storep extraTempReg, VM::topVMEntryFrame[vm]
 
     subp cfr, CalleeRegisterSaveSize, sp
 
@@ -225,62 +175,65 @@ macro doVMEntry(makeCall)
     ret
 
 .stackHeightOK:
-    move temp1, sp
-    move 4, temp1
+    move t3, sp
+    move 4, t3
 
 .copyHeaderLoop:
-    subi 1, temp1
-    loadq [protoCallFrame, temp1, 8], temp3
-    storeq temp3, CodeBlock[sp, temp1, 8]
-    btinz temp1, .copyHeaderLoop
-
-    loadi PayloadOffset + ProtoCallFrame::argCountAndCodeOriginValue[protoCallFrame], temp2
-    subi 1, temp2
-    loadi ProtoCallFrame::paddedArgCount[protoCallFrame], temp3
-    subi 1, temp3
-
-    bieq temp2, temp3, .copyArgs
-    move ValueUndefined, temp1
+    subi 1, t3
+    loadq [protoCallFrame, t3, 8], extraTempReg
+    storeq extraTempReg, CodeBlock[sp, t3, 8]
+    btinz t3, .copyHeaderLoop
+
+    loadi PayloadOffset + ProtoCallFrame::argCountAndCodeOriginValue[protoCallFrame], t4
+    subi 1, t4
+    loadi ProtoCallFrame::paddedArgCount[protoCallFrame], extraTempReg
+    subi 1, extraTempReg
+
+    bieq t4, extraTempReg, .copyArgs
+    move ValueUndefined, t3
 .fillExtraArgsLoop:
-    subi 1, temp3
-    storeq temp1, ThisArgumentOffset + 8[sp, temp3, 8]
-    bineq temp2, temp3, .fillExtraArgsLoop
+    subi 1, extraTempReg
+    storeq t3, ThisArgumentOffset + 8[sp, extraTempReg, 8]
+    bineq t4, extraTempReg, .fillExtraArgsLoop
 
 .copyArgs:
-    loadp ProtoCallFrame::args[protoCallFrame], temp1
+    loadp ProtoCallFrame::args[protoCallFrame], t3
 
 .copyArgsLoop:
-    btiz temp2, .copyArgsDone
-    subi 1, temp2
-    loadq [temp1, temp2, 8], temp3
-    storeq temp3, ThisArgumentOffset + 8[sp, temp2, 8]
+    btiz t4, .copyArgsDone
+    subi 1, t4
+    loadq [t3, t4, 8], extraTempReg
+    storeq extraTempReg, ThisArgumentOffset + 8[sp, t4, 8]
     jmp .copyArgsLoop
 
 .copyArgsDone:
     if ARM64
-        move sp, temp2
-        storep temp2, VM::topCallFrame[vm]
+        move sp, t4
+        storep t4, VM::topCallFrame[vm]
     else
         storep sp, VM::topCallFrame[vm]
     end
     storep cfr, VM::topVMEntryFrame[vm]
 
-    move 0xffff000000000000, csr1
-    addp 2, csr1, csr2
+    move TagTypeNumber, tagTypeNumber
+    addp TagBitTypeOther, tagTypeNumber, tagMask
 
-    checkStackPointerAlignment(temp3, 0xbad0dc02)
+    checkStackPointerAlignment(extraTempReg, 0xbad0dc02)
 
-    makeCall(entry, temp1)
+    makeCall(entry, t3)
 
-    checkStackPointerAlignment(temp3, 0xbad0dc03)
+    # We may have just made a call into a JS function, so we can't rely on sp
+    # for anything but the fact that our own locals (ie the VMEntryRecord) are
+    # not below it. It also still has to be aligned, though.
+    checkStackPointerAlignment(t2, 0xbad0dc03)
 
-    vmEntryRecord(cfr, temp2)
+    vmEntryRecord(cfr, t4)
 
-    loadp VMEntryRecord::m_vm[temp2], vm
-    loadp VMEntryRecord::m_prevTopCallFrame[temp2], temp3
-    storep temp3, VM::topCallFrame[vm]
-    loadp VMEntryRecord::m_prevTopVMEntryFrame[temp2], temp3
-    storep temp3, VM::topVMEntryFrame[vm]
+    loadp VMEntryRecord::m_vm[t4], vm
+    loadp VMEntryRecord::m_prevTopCallFrame[t4], t2
+    storep t2, VM::topCallFrame[vm]
+    loadp VMEntryRecord::m_prevTopVMEntryFrame[t4], t2
+    storep t2, VM::topVMEntryFrame[vm]
 
     subp cfr, CalleeRegisterSaveSize, sp
 
@@ -305,13 +258,7 @@ end
 macro makeHostFunctionCall(entry, temp)
     move entry, temp
     storep cfr, [sp]
-    if X86_64
-        move sp, t4
-    elsif X86_64_WIN
-        move sp, t2
-    elsif ARM64 or C_LOOP
-        move sp, a0
-    end
+    move sp, a0
     if C_LOOP
         storep lr, 8[sp]
         cloopCallNative temp
@@ -336,10 +283,10 @@ _handleUncaughtException:
     vmEntryRecord(cfr, t2)
 
     loadp VMEntryRecord::m_vm[t2], t3
-    loadp VMEntryRecord::m_prevTopCallFrame[t2], t5
-    storep t5, VM::topCallFrame[t3]
-    loadp VMEntryRecord::m_prevTopVMEntryFrame[t2], t5
-    storep t5, VM::topVMEntryFrame[t3]
+    loadp VMEntryRecord::m_prevTopCallFrame[t2], extraTempReg
+    storep extraTempReg, VM::topCallFrame[t3]
+    loadp VMEntryRecord::m_prevTopVMEntryFrame[t2], extraTempReg
+    storep extraTempReg, VM::topVMEntryFrame[t3]
 
     subp cfr, CalleeRegisterSaveSize, sp
 
@@ -350,31 +297,39 @@ _handleUncaughtException:
 
 macro prepareStateForCCall()
     leap [PB, PC, 8], PC
-    move PB, t3
 end
 
 macro restoreStateAfterCCall()
-    move t0, PC
-    move t3, PB
+    move r0, PC
     subp PB, PC
     rshiftp 3, PC
 end
 
 macro callSlowPath(slowPath)
     prepareStateForCCall()
-    cCall2(slowPath, cfr, PC)
+    move cfr, a0
+    move PC, a1
+    cCall2(slowPath)
     restoreStateAfterCCall()
 end
 
 macro traceOperand(fromWhere, operand)
     prepareStateForCCall()
-    cCall4(_llint_trace_operand, cfr, PC, fromWhere, operand)
+    move fromWhere, a2
+    move operand, a3
+    move cfr, a0
+    move PC, a1
+    cCall4(_llint_trace_operand)
     restoreStateAfterCCall()
 end
 
 macro traceValue(fromWhere, operand)
     prepareStateForCCall()
-    cCall4(_llint_trace_value, cfr, PC, fromWhere, operand)
+    move fromWhere, a2
+    move operand, a3
+    move cfr, a0
+    move PC, a1
+    cCall4(_llint_trace_value)
     restoreStateAfterCCall()
 end
 
@@ -382,16 +337,19 @@ end
 macro callCallSlowPath(slowPath, action)
     storei PC, ArgumentCount + TagOffset[cfr]
     prepareStateForCCall()
-    cCall2(slowPath, cfr, PC)
-    action(t0)
+    move cfr, a0
+    move PC, a1
+    cCall2(slowPath)
+    action(r0, r1)
 end
 
 macro callWatchdogTimerHandler(throwHandler)
     storei PC, ArgumentCount + TagOffset[cfr]
     prepareStateForCCall()
-    cCall2(_llint_slow_path_handle_watchdog_timer, cfr, PC)
-    btpnz t0, throwHandler
-    move t3, PB
+    move cfr, a0
+    move PC, a1
+    cCall2(_llint_slow_path_handle_watchdog_timer)
+    btpnz r0, throwHandler
     loadi ArgumentCount + TagOffset[cfr], PC
 end
 
@@ -401,12 +359,13 @@ macro checkSwitchToJITForLoop()
         macro()
             storei PC, ArgumentCount + TagOffset[cfr]
             prepareStateForCCall()
-            cCall2(_llint_loop_osr, cfr, PC)
-            btpz t0, .recover
-            move t1, sp
-            jmp t0
+            move cfr, a0
+            move PC, a1
+            cCall2(_llint_loop_osr)
+            btpz r0, .recover
+            move r1, sp
+            jmp r0
         .recover:
-            move t3, PB
             loadi ArgumentCount + TagOffset[cfr], PC
         end)
 end
@@ -447,7 +406,9 @@ macro writeBarrierOnOperand(cellOperand)
             macro(gcData)
                 btbnz gcData, .writeBarrierDone
                 push PB, PC
-                cCall2Void(_llint_write_barrier_slow, cfr, t2)
+                move t2, a1 # t2 can be a0 (not on 64 bits, but better safe than sorry)
+                move cfr, a0
+                cCall2Void(_llint_write_barrier_slow)
                 pop PC, PB
             end
         )
@@ -477,7 +438,9 @@ macro writeBarrierOnGlobal(valueOperand, loadHelper)
             macro(gcData)
                 btbnz gcData, .writeBarrierDone
                 push PB, PC
-                cCall2Void(_llint_write_barrier_slow, cfr, t3)
+                move cfr, a0
+                move t3, a1
+                cCall2Void(_llint_write_barrier_slow)
                 pop PC, PB
             end
         )
@@ -538,19 +501,21 @@ macro functionArityCheck(doneLabel, slowPath)
     loadi PayloadOffset + ArgumentCount[cfr], t0
     biaeq t0, CodeBlock::m_numParameters[t1], doneLabel
     prepareStateForCCall()
-    cCall2(slowPath, cfr, PC)   # This slowPath has the protocol: t0 = 0 => no error, t0 != 0 => error
-    btiz t0, .noError
-    move t1, cfr   # t1 contains caller frame
+    move cfr, a0
+    move PC, a1
+    cCall2(slowPath)   # This slowPath has the protocol: r0 = 0 => no error, r0 != 0 => error
+    btiz r0, .noError
+    move r1, cfr   # r1 contains caller frame
     jmp _llint_throw_from_slow_path_trampoline
 
 .noError:
-    # t1 points to ArityCheckData.
-    loadp CommonSlowPaths::ArityCheckData::thunkToCall[t1], t2
-    btpz t2, .proceedInline
+    # r1 points to ArityCheckData.
+    loadp CommonSlowPaths::ArityCheckData::thunkToCall[r1], t3
+    btpz t3, .proceedInline
     
-    loadp CommonSlowPaths::ArityCheckData::returnPC[t1], t7
-    loadp CommonSlowPaths::ArityCheckData::paddedStackSpace[t1], t0
-    call t2
+    loadp CommonSlowPaths::ArityCheckData::paddedStackSpace[r1], a0
+    loadp CommonSlowPaths::ArityCheckData::returnPC[r1], a1
+    call t3
     if ASSERT_ENABLED
         loadp ReturnPC[cfr], t0
         loadp [t0], t0
@@ -558,7 +523,7 @@ macro functionArityCheck(doneLabel, slowPath)
     jmp .continue
 
 .proceedInline:
-    loadi CommonSlowPaths::ArityCheckData::paddedStackSpace[t1], t1
+    loadi CommonSlowPaths::ArityCheckData::paddedStackSpace[r1], t1
     btiz t1, .continue
 
     // Move frame up "t1 * 2" slots
@@ -604,7 +569,6 @@ end
 
 
 # Instruction implementations
-
 _llint_op_enter:
     traceExecution()
     checkStackPointerAlignment(t2, 0xdead00e1)
@@ -636,14 +600,14 @@ _llint_op_create_this:
     traceExecution()
     loadisFromInstruction(2, t0)
     loadp [cfr, t0, 8], t0
-    loadp JSFunction::m_rareData[t0], t4
-    btpz t4, .opCreateThisSlow
-    loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_allocator[t4], t1
-    loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_structure[t4], t2
+    loadp JSFunction::m_rareData[t0], t3
+    btpz t3, .opCreateThisSlow
+    loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_allocator[t3], t1
+    loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_structure[t3], t2
     btpz t1, .opCreateThisSlow
-    loadpFromInstruction(4, t4)
-    bpeq t4, 1, .hasSeenMultipleCallee
-    bpneq t4, t0, .opCreateThisSlow
+    loadpFromInstruction(4, t3)
+    bpeq t3, 1, .hasSeenMultipleCallee
+    bpneq t3, t0, .opCreateThisSlow
 .hasSeenMultipleCallee:
     allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow)
     loadisFromInstruction(1, t1)
@@ -1776,7 +1740,7 @@ _llint_op_ret:
     traceExecution()
     checkSwitchToJITForEpilogue()
     loadisFromInstruction(1, t2)
-    loadConstantOrVariable(t2, t0)
+    loadConstantOrVariable(t2, r0)
     doReturn()
 
 
@@ -1839,7 +1803,7 @@ _llint_op_end:
     checkSwitchToJITForEpilogue()
     loadisFromInstruction(1, t0)
     assertNotConstant(t0)
-    loadq [cfr, t0, 8], t0
+    loadq [cfr, t0, 8], r0
     doReturn()
 
 
@@ -1864,56 +1828,31 @@ macro nativeCallTrampoline(executableOffsetToFunction)
 
     functionPrologue()
     storep 0, CodeBlock[cfr]
-    if X86_64 or X86_64_WIN
-        if X86_64
-            const arg1 = t4  # t4 = rdi
-            const arg2 = t5  # t5 = rsi
-            const temp = t1
-        elsif X86_64_WIN
-            const arg1 = t2  # t2 = rcx
-            const arg2 = t1  # t1 = rdx
-            const temp = t0
-        end
-        loadp Callee[cfr], t0
-        andp MarkedBlockMask, t0, t1
-        loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t1
-        storep cfr, VM::topCallFrame[t1]
-        move cfr, arg1
-        loadp Callee[cfr], arg2
-        loadp JSFunction::m_executable[arg2], temp
-        checkStackPointerAlignment(t3, 0xdead0001)
+    loadp Callee[cfr], t0
+    andp MarkedBlockMask, t0, t1
+    loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t1
+    storep cfr, VM::topCallFrame[t1]
+    if ARM64 or C_LOOP
+        storep lr, ReturnPC[cfr]
+    end
+    move cfr, a0
+    loadp Callee[cfr], t1
+    loadp JSFunction::m_executable[t1], t1
+    checkStackPointerAlignment(t3, 0xdead0001)
+    if C_LOOP
+        cloopCallNative executableOffsetToFunction[t1]
+    else
         if X86_64_WIN
             subp 32, sp
         end
-        call executableOffsetToFunction[temp]
+        call executableOffsetToFunction[t1]
         if X86_64_WIN
             addp 32, sp
         end
-        loadp Callee[cfr], t3
-        andp MarkedBlockMask, t3
-        loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
-    elsif ARM64 or C_LOOP
-        loadp Callee[cfr], t0
-        andp MarkedBlockMask, t0, t1
-        loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t1
-        storep cfr, VM::topCallFrame[t1]
-        preserveReturnAddressAfterCall(t3)
-        storep t3, ReturnPC[cfr]
-        move cfr, t0
-        loadp Callee[cfr], t1
-        loadp JSFunction::m_executable[t1], t1
-        if C_LOOP
-            cloopCallNative executableOffsetToFunction[t1]
-        else
-            call executableOffsetToFunction[t1]
-        end
-        restoreReturnAddressBeforeReturn(t3)
-        loadp Callee[cfr], t3
-        andp MarkedBlockMask, t3
-        loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
-    else
-        error
     end
+    loadp Callee[cfr], t3
+    andp MarkedBlockMask, t3
+    loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
 
     functionEpilogue()
 
index 44cfbe5..a0ab3dd 100644 (file)
@@ -27,6 +27,34 @@ require "ast"
 require "opt"
 require "risc"
 
+# GPR conventions, to match the baseline JIT
+#
+#  x0 => t0, a0, r0
+#  x1 => t1, a1, r1
+#  x2 => t2, a2, r2
+#  x3 => t3, a3, r3
+#  x6 =>            (callee-save scratch)
+#  x7 => cfr        (ARMv7 only)
+#  x8 => t4         (callee-save)
+#  x9 => t5         (callee-save)
+# x10 =>            (callee-save scratch)
+# x11 => cfr        (ARM and ARMv7 traditional)
+# x12 =>            (callee-save scratch)
+#  lr => lr
+#  sp => sp
+#  pc => pc
+#
+# FPR conventions, to match the baseline JIT
+#
+# d0 => ft0, fa0, fr
+# d1 => ft1, fa1
+# d2 => ft2
+# d3 => ft3
+# d4 => ft4
+# d5 => ft5
+# d6 =>              (scratch)
+# d7 =>              (scratch)
+
 def isARMv7
     case $activeBackend
     when "ARMv7"
@@ -119,9 +147,9 @@ end
 class FPRegisterID
     def armOperand
         case name
-        when "ft0", "fr"
+        when "ft0", "fr", "fa0"
             "d0"
-        when "ft1"
+        when "ft1", "fa1"
             "d1"
         when "ft2"
             "d2"
index 3a0d786..1110622 100644 (file)
@@ -37,32 +37,30 @@ require "risc"
 #
 # GPR conventions, to match the baseline JIT:
 #
-#  x0  => return value, cached result, first argument, t0, a0, r0
+#  x0  => t0, a0, r0
 #  x1  => t1, a1, r1
 #  x2  => t2, a2
-#  x3  => a3
-#  x5  => t4
-#  x6  => t6
-#  x9  => (nonArgGPR1 in baseline)
-# x13  => scratch (unused in baseline)
-# x16  => scratch
-# x17  => scratch
-# x23  => t3
-# x24  => t5
-# x27  => csr1 (tagTypeNumber)
-# x28  => csr2 (tagMask)
+#  x3  => t3, a3
+#  x4  => t4
+#  x5  => t5
+# x13  =>                  (scratch)
+# x16  =>                  (scratch)
+# x17  =>                  (scratch)
+# x26  =>             csr0 (PB)
+# x27  =>             csr1 (tagTypeNumber)
+# x28  =>             csr2 (tagMask)
 # x29  => cfr
 #  sp  => sp
 #  lr  => lr
 #
-# FPR conentions, to match the baseline JIT:
+# FPR conventions, to match the baseline JIT:
 #
-#  q0  => ft0
-#  q1  => ft1
-#  q2  => ft2
-#  q3  => ft3
-#  q4  => ft4 (unused in baseline)
-#  q5  => ft5 (unused in baseline)
+#  q0  => ft0, fa0, fr
+#  q1  => ft1, fa1
+#  q2  => ft2, fa2
+#  q3  => ft3, fa3
+#  q4  => ft4          (unused in baseline)
+#  q5  => ft5          (unused in baseline)
 # q31  => scratch
 
 def arm64GPRName(name, kind)
@@ -109,20 +107,16 @@ class RegisterID
             arm64GPRName('x1', kind)
         when 't2', 'a2'
             arm64GPRName('x2', kind)
-        when 'a3'
+        when 't3', 'a3'
             arm64GPRName('x3', kind)
-        when 't3'
-            arm64GPRName('x23', kind)
         when 't4'
-            arm64GPRName('x5', kind)
+            arm64GPRName('x4', kind)
         when 't5'
-            arm64GPRName('x24', kind)
-        when 't6'
-            arm64GPRName('x6', kind)
-        when 't7'
-            arm64GPRName('x7', kind)
+            arm64GPRName('x5', kind)
         when 'cfr'
             arm64GPRName('x29', kind)
+        when 'csr0'
+            arm64GPRName('x26', kind)
         when 'csr1'
             arm64GPRName('x27', kind)
         when 'csr2'
@@ -140,13 +134,13 @@ end
 class FPRegisterID
     def arm64Operand(kind)
         case @name
-        when 'ft0'
+        when 'ft0', 'fr', 'fa0'
             arm64FPRName('q0', kind)
-        when 'ft1'
+        when 'ft1', 'fa1'
             arm64FPRName('q1', kind)
-        when 'ft2'
+        when 'ft2', 'fa2'
             arm64FPRName('q2', kind)
-        when 'ft3'
+        when 'ft3', 'fa3'
             arm64FPRName('q3', kind)
         when 'ft4'
             arm64FPRName('q4', kind)
index 04a6998..7e93948 100644 (file)
@@ -70,9 +70,9 @@ class RegisterID
         case name
         # The cloop is modelled on the ARM implementation. Hence, the a0-a3
         # registers are aliases for r0-r3 i.e. t0-t3 in our case.
-        when "t0", "a0"
+        when "t0", "a0", "r0"
             "t0"
-        when "t1", "a1"
+        when "t1", "a1", "r1"
             "t1"
         when "t2", "a2"
             "t2"
@@ -82,10 +82,8 @@ class RegisterID
             "pc"
         when "t5"
             "t5"
-        when "t6"
+        when "csr0"
             "pcBase"
-        when "t7"
-            "t7"
         when "csr1"
             "tagTypeNumber"
         when "csr2"
index cc107ec..3052dca 100644 (file)
 
 require 'risc'
 
+# GPR conventions, to match the baseline JIT
+#
+# $a0 => a0
+# $a1 => a1
+# $a2 => a2
+# $a3 => a3
+# $v0 => t0, r0
+# $v1 => t1, r1
+# $t2 =>         t2
+# $t3 =>         t3
+# $t4 =>         t4
+# $t5 =>         t5
+# $t6 =>            (scratch)
+# $t7 =>            (scratch)
+# $t8 =>            (scratch)
+# $t9 =>            (stores the callee of a call opcode)
+# $gp =>            (globals)
+# $s4 =>            (callee-save used to preserve $gp across calls)
+# $ra => lr
+# $sp => sp
+# $fp => cfr
+#
+# FPR conventions, to match the baseline JIT
+# We don't have fa2 or fa3!
+#  $f0 => ft0, fr
+#  $f2 => ft1
+#  $f4 => ft2
+#  $f6 => ft3
+#  $f8 => ft4
+# $f10 => ft5
+# $f12 =>        fa0
+# $f14 =>        fa1
+# $f16 =>            (scratch)
+# $f18 =>            (scratch)
+
 class Assembler
     def putStr(str)
         @outp.puts str
@@ -57,8 +92,7 @@ class SpecialRegister < NoChildren
     end
 end
 
-MIPS_TEMP_GPRS = [SpecialRegister.new("$t5"), SpecialRegister.new("$t6"), SpecialRegister.new("$t7"),
-                    SpecialRegister.new("$t8")]
+MIPS_TEMP_GPRS = [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")
@@ -85,24 +119,18 @@ class RegisterID
             "$a2"
         when "a3"
             "$a3"
-        when "r0", "t0"
+        when "t0", "r0"
             "$v0"
-        when "r1", "t1"
+        when "t1", "r1"
             "$v1"
         when "t2"
             "$t2"
         when "t3"
-            "$s3"
-        when "t4"   # PC reg in llint
-            "$s2"
+            "$t3"
+        when "t4"
+            "$t4"
         when "t5"
             "$t5"
-        when "t6"
-            "$t6"
-        when "t7"
-            "$t7"
-        when "t8"
-            "$t8"
         when "cfr"
             "$fp"
         when "lr"
index 168667e..a4a075c 100644 (file)
@@ -31,10 +31,6 @@ GPRS =
      "t3",
      "t4",
      "t5",
-     "t6",
-     "t7",
-     "t8",
-     "t9",
      "cfr",
      "a0",
      "a1",
@@ -46,8 +42,13 @@ GPRS =
      "lr",
      "pc",
      # 64-bit only registers:
-     "csr1",  # tag type number register
-     "csr2"   # tag mask register
+     "csr0",
+     "csr1",
+     "csr2",
+     "csr3",
+     "csr4",
+     "csr5",
+     "csr6"
     ]
 
 FPRS =
index 0241f38..c847d56 100644 (file)
 
 require 'risc'
 
+# GPR conventions, to match the baseline JIT
+#
+#  r0 => t0, r0
+#  r1 => t1, r1
+#  r2 => t4
+#  r3 => t5
+#  r4 =>         a0
+#  r5 =>         a1
+#  r6 => t2,     a2
+#  r7 => t3,     a3
+# r10 =>            (scratch)
+# r11 =>            (scratch)
+# r13 =>            (scratch)
+# r14 => cfr
+# r15 => sp
+#  pr => lr
+
+# FPR conventions, to match the baseline JIT
+# We don't have fa2 or fa3!
+#  dr0 => ft0, fr
+#  dr2 => ft1
+#  dr4 => ft2,   fa0
+#  dr6 => ft3,   fa1
+#  dr8 => ft4
+# dr10 => ft5
+# dr12 =>             (scratch)
+
 class Node
     def sh4SingleHi
         doubleOperand = sh4Operand
@@ -51,32 +78,28 @@ class SpecialRegister < NoChildren
     end
 end
 
-SH4_TMP_GPRS = [ SpecialRegister.new("r3"), SpecialRegister.new("r11"), SpecialRegister.new("r13") ]
-SH4_TMP_FPRS = [ SpecialRegister.new("dr10") ]
+SH4_TMP_GPRS = [ SpecialRegister.new("r10"), SpecialRegister.new("r11"), SpecialRegister.new("r13") ]
+SH4_TMP_FPRS = [ SpecialRegister.new("dr12") ]
 
 class RegisterID
     def sh4Operand
         case name
-        when "t0"
-            "r0"
-        when "t1"
-            "r1"
-        when "t2"
-            "r2"
-        when "t3"
-            "r10"
-        when "t4", "a0"
+        when "a0"
             "r4"
-        when "t5", "a1"
+        when "a1"
             "r5"
-        when "t6", "a2"
+        when "r0", "t0"
+            "r0"
+        when "r1", "t1"
+            "r1"
+        when "a2", "t2"
             "r6"
-        when "t7", "a3"
+        when "a3", "t3"
             "r7"
-        when "t8"
-            "r8"
-        when "t9"
-            "r9"
+        when "t4"
+            "r2"
+        when "t5"
+            "r3"
         when "cfr"
             "r14"
         when "sp"
@@ -96,14 +119,14 @@ class FPRegisterID
             "dr0"
         when "ft1"
             "dr2"
-        when "ft2"
+        when "ft2", "fa0"
             "dr4"
-        when "ft3"
+        when "ft3", "fa1"
             "dr6"
         when "ft4"
             "dr8"
-        when "fa0"
-            "dr12"
+        when "ft5"
+            "dr10"
         else
             raise "Bad register #{name} for SH4 at #{codeOriginString}"
         end
index 8830e3d..f2ee96c 100644 (file)
 
 require "config"
 
+# GPR conventions, to match the baseline JIT:
+#
+#
+# On x86-32 bits (windows and non-windows)
+# a0, a1, a2, a3 are only there for ease-of-use of offlineasm; they are not
+# actually considered as such by the ABI and we need to push/pop our arguments
+# on the stack. a0 and a1 are ecx and edx to follow fastcall.
+#
+# eax => t0, a2, r0
+# edx => t1, a1, r1
+# ecx => t2, a0
+# ebx => t3, a3     (callee-save)
+# esi => t4         (callee-save)
+# edi => t5         (callee-save)
+# ebp => cfr
+# esp => sp
+#
+# On x86-64 non-windows
+#
+# rax => t0,     r0
+# rdi =>     a0
+# rsi => t1, a1
+# rdx => t2, a2, r1
+# rcx => t3, a3
+#  r8 => t4
+# r10 => t5
+# rbx =>             csr0 (callee-save, PB, unused in baseline)
+# r12 =>             csr1 (callee-save)
+# r13 =>             csr2 (callee-save)
+# r14 =>             csr3 (callee-save, tagTypeNumber)
+# r15 =>             csr4 (callee-save, tagMask)
+# rsp => sp
+# rbp => cfr
+# r11 =>                  (scratch)
+#
+# On x86-64 windows
+# Arguments need to be push/pop'd on the stack in addition to being stored in
+# the registers. Also, >8 return types are returned in a weird way.
+#
+# rax => t0,     r0
+# rcx =>     a0
+# rdx => t1, a1, r1
+#  r8 => t2, a2
+#  r9 => t3, a3
+# r10 => t4
+# rbx =>             csr0 (callee-save, PB, unused in baseline)
+# rsi =>             csr1 (callee-save)
+# rdi =>             csr2 (callee-save)
+# r12 =>             csr3 (callee-save)
+# r13 =>             csr4 (callee-save)
+# r14 =>             csr5 (callee-save, tagTypeNumber)
+# r15 =>             csr6 (callee-save, tagMask)
+# rsp => sp
+# rbp => cfr
+# r11 =>                  (scratch)
+
 def isX64
     case $activeBackend
     when "X86"
@@ -39,6 +95,21 @@ def isX64
     end
 end
 
+def isWin
+    case $activeBackend
+    when "X86"
+        false
+    when "X86_WIN"
+        true
+    when "X86_64"
+        false
+    when "X86_64_WIN"
+        true
+    else
+        raise "bad value for $activeBackend: #{$activeBackend}"
+    end
+end
+
 def useX87
     case $activeBackend
     when "X86"
@@ -54,20 +125,20 @@ def useX87
     end
 end
 
-def isWindows
+def isCompilingOnWindows
     ENV['OS'] == 'Windows_NT'
 end
 
 def isGCC
-    !isWindows
+    !isCompilingOnWindows
 end
 
 def isMSVC
-    isWindows
+    isCompilingOnWindows
 end
 
 def isIntelSyntax
-    isWindows
+    isCompilingOnWindows
 end
 
 def register(name)
@@ -141,205 +212,133 @@ end
 
 X64_SCRATCH_REGISTER = SpecialRegister.new("r11")
 
+def x86GPRName(name, kind)
+    case name
+    when "eax", "ebx", "ecx", "edx"
+        name8 = name[1] + 'l'
+        name16 = name[1..2]
+    when "esi", "edi", "ebp", "esp"
+        name16 = name[1..2]
+        name8 = name16 + 'l'
+    when "rax", "rbx", "rcx", "rdx"
+        raise "bad GPR name #{name} in 32-bit X86" unless isX64
+        name8 = name[1] + 'l'
+        name16 = name[1..2]
+    when "r8", "r9", "r10", "r12", "r13", "r14", "r15"
+        raise "bad GPR name #{name} in 32-bit X86" unless isX64
+        case kind
+        when :half
+            return register(name + "w")
+        when :int
+            return register(name + "d")
+        when :ptr
+            return register(name)
+        when :quad
+            return register(name)
+        end
+    else
+        raise "bad GPR name #{name}"
+    end
+    case kind
+    when :byte
+        register(name8)
+    when :half
+        register(name16)
+    when :int
+        register("e" + name16)
+    when :ptr
+        register((isX64 ? "r" : "e") + name16)
+    when :quad
+        isX64 ? register("r" + name16) : raise
+    else
+        raise "invalid kind #{kind} for GPR #{name} in X86"
+    end
+end
+
 class RegisterID
     def supports8BitOnX86
-        case name
-        when "t0", "a0", "r0", "t1", "a1", "r1", "t2", "t3", "t4", "t5"
+        case x86GPR
+        when "eax", "ebx", "ecx", "edx", "edi", "esi", "ebp", "esp"
             true
-        when "cfr", "ttnr", "tmr"
+        when "r8", "r9", "r10", "r12", "r13", "r14", "r15"
             false
-        when "t6"
-            isX64
         else
             raise
         end
     end
-    
-    def x86Operand(kind)
-        case name
-        when "t0", "a0", "r0"
-            case kind
-            when :byte
-                register("al")
-            when :half
-                register("ax")
-            when :int
-                register("eax")
-            when :ptr
-                isX64 ? register("rax") : register("eax")
-            when :quad
-                isX64 ? register("rax") : raise
-            else
-                raise "Invalid kind #{kind} for name #{name}"
-            end
-        when "t1", "a1", "r1"
-            case kind
-            when :byte
-                register("dl")
-            when :half
-                register("dx")
-            when :int
-                register("edx")
-            when :ptr
-                isX64 ? register("rdx") : register("edx")
-            when :quad
-                isX64 ? register("rdx") : raise
-            else
-                raise
-            end
-        when "t2"
-            case kind
-            when :byte
-                register("cl")
-            when :half
-                register("cx")
-            when :int
-                register("ecx")
-            when :ptr
-                isX64 ? register("rcx") : register("ecx")
-            when :quad
-                isX64 ? register("rcx") : raise
-            else
-                raise
-            end
-        when "t3"
-            case kind
-            when :byte
-                register("bl")
-            when :half
-                register("bx")
-            when :int
-                register("ebx")
-            when :ptr
-                isX64 ? register("rbx") : register("ebx")
-            when :quad
-                isX64 ? register("rbx") : raise
-            else
-                raise
-            end
-        when "t4"
-            case kind
-            when :byte
-                register("dil")
-            when :half
-                register("di")
-            when :int
-                register("edi")
-            when :ptr
-                isX64 ? register("rdi") : register("edi")
-            when :quad
-                isX64 ? register("rdi") : raise
-            else
-                raise
-            end
-        when "cfr"
-            if isX64
-                case kind
-                when :half
-                    register("bp")
-                when :int
-                    register("ebp")
-                when :ptr
-                    register("rbp")
-                when :quad
-                    register("rbp")
-                else
-                    raise
-                end
-            else
-                case kind
-                when :half
-                    register("bp")
-                when :int
-                    register("ebp")
-                when :ptr
-                    register("ebp")
-                else
-                    raise
-                end
-            end
-        when "sp"
-            case kind
-            when :byte
-                register("spl")
-            when :half
-                register("sp")
-            when :int
-                register("esp")
-            when :ptr
-                isX64 ? register("rsp") : register("esp")
-            when :quad
-                isX64 ? register("rsp") : raise
+
+    def x86GPR
+        if isX64
+            case name
+            when "t0", "r0"
+                "eax"
+            when "r1"
+                "edx" # t1 = a1 when isWin, t2 = a2 otherwise
+            when "a0"
+                isWin ? "ecx" : "edi"
+            when "t1", "a1"
+                isWin ? "edx" : "esi"
+            when "t2", "a2"
+                isWin ? "r8" : "edx"
+            when "t3", "a3"
+                isWin ? "r9" : "ecx"
+            when "t4"
+                isWin ? "r10" : "r8"
+            when "t5"
+                raise "cannot use register #{name} on X86-64 Windows" unless not isWin
+                "r10"
+            when "csr0"
+                "ebx"
+            when "csr1"
+                "r12"
+            when "csr2"
+                "r13"
+            when "csr3"
+                isWin ? "esi" : "r14"
+            when "csr4"
+                isWin ? "edi" : "r15"
+                "r15"
+            when "csr5"
+                raise "cannot use register #{name} on X86-64" unless isWin
+                "r14"
+            when "csr6"
+                raise "cannot use register #{name} on X86-64" unless isWin
+                "r15"
+            when "cfr"
+                "ebp"
+            when "sp"
+                "esp"
             else
-                raise
-            end
-        when "t5"
-            case kind
-            when :byte
-                register("sil")
-            when :half
-                register("si")
-            when :int
-                register("esi")
-            when :ptr
-                isX64 ? register("rsi") : register("esi")
-            when :quad
-                isX64 ? register("rsi") : raise
-            end
-        when "t6"
-            raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
-            case kind
-            when :half
-                register("r8w")
-            when :int
-                register("r8d")
-            when :ptr
-                register("r8")
-            when :quad
-                register("r8")
-            end
-        when "t7"
-            raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
-            case kind
-            when :half
-                register("r9w")
-            when :int
-                register("r9d")
-            when :ptr
-                register("r9")
-            when :quad
-                register("r9")
-            end
-        when "csr1"
-            raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
-            case kind
-            when :half
-                register("r14w")
-            when :int
-                register("r14d")
-            when :ptr
-                register("r14")
-            when :quad
-                register("r14")
-            end
-        when "csr2"
-            raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
-            case kind
-            when :half
-                register("r15w")
-            when :int
-                register("r15d")
-            when :ptr
-                register("r15")
-            when :quad
-                register("r15")
+                raise "cannot use register #{name} on X86"
             end
         else
-            raise "Bad register #{name} for X86 at #{codeOriginString}"
+            case name
+            when "t0", "r0", "a2"
+                "eax"
+            when "t1", "r1", "a1"
+                "edx"
+            when "t2", "a0"
+                "ecx"
+            when "t3", "a3"
+                "ebx"
+            when "t4"
+                "esi"
+            when "t5"
+                "edi"
+            when "cfr"
+                "ebp"
+            when "sp"
+                "esp"
+            end
         end
     end
+
+    def x86Operand(kind)
+        x86GPRName(x86GPR, kind)
+    end
+
     def x86CallOperand(kind)
-        isX64 ? "#{callPrefix}#{x86Operand(:quad)}" : "#{callPrefix}#{x86Operand(:ptr)}"
+        "#{callPrefix}#{x86Operand(:ptr)}"
     end
 end
 
@@ -597,13 +596,12 @@ class Instruction
     end
     
     def handleX86Shift(opcode, kind)
-        if operands[0].is_a? Immediate or operands[0] == RegisterID.forName(nil, "t2")
+        if operands[0].is_a? Immediate or operands[0].x86GPR == "ecx"
             $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(kind))}"
         else
-            cx = RegisterID.forName(nil, "t2")
-            $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{cx.x86Operand(:ptr)}"
+            $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}"
             $asm.puts "#{opcode} #{orderOperands(register("cl"), operands[1].x86Operand(kind))}"
-            $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{cx.x86Operand(:ptr)}"
+            $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}"
         end
     end
     
@@ -647,10 +645,14 @@ class Instruction
                 $asm.puts "movzx #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
             end
         else
-            ax = RegisterID.new(nil, "t0")
+            ax = RegisterID.new(nil, "r0")
             $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
-            $asm.puts "#{setOpcode} %al"
-            $asm.puts "movzbl %al, %eax"
+            $asm.puts "#{setOpcode} #{ax.x86Operand(:byte)}"
+            if !isIntelSyntax
+               $asm.puts "movzbl #{ax.x86Operand(:byte)}, #{ax.x86Operand(:int)}"
+            else
+                $asm.puts "movzx #{ax.x86Operand(:int)}, #{ax.x86Operand(:byte)}"
+            end
             $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
         end
     end