From 1d574b1c281490f3fc37c6de7a8ad1acc58b7c6b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 26 Jun 2014 17:31:45 -0700 Subject: [PATCH] Bug 1028064 - Remove lots of dead code in js/src/assembler/. r=jandem. --HG-- extra : rebase_source : e5696eb5818871e8214ad5e5e4b54805260e6c35 --- config/check_spidermonkey_style.py | 4 +- js/src/assembler/TestMain.cpp | 933 ------ js/src/assembler/assembler/ARMAssembler.cpp | 669 ---- js/src/assembler/assembler/ARMAssembler.h | 1713 ---------- js/src/assembler/assembler/ARMv7Assembler.h | 1931 ------------ .../assembler/AbstractMacroAssembler.h | 659 ---- .../AssemblerBufferWithConstantPool.h | 386 --- js/src/assembler/assembler/CodeLocation.h | 189 -- js/src/assembler/assembler/LinkBuffer.h | 221 -- js/src/assembler/assembler/MIPSAssembler.h | 1081 ------- js/src/assembler/assembler/MacroAssembler.h | 341 +- .../assembler/assembler/MacroAssemblerARM.cpp | 29 +- .../assembler/assembler/MacroAssemblerARM.h | 1498 +-------- .../assembler/assembler/MacroAssemblerARMv7.h | 1175 +------ .../assembler/MacroAssemblerCodeRef.h | 229 -- .../assembler/assembler/MacroAssemblerMIPS.h | 2752 +---------------- .../assembler/assembler/MacroAssemblerSparc.h | 1444 +-------- .../assembler/assembler/MacroAssemblerX86.h | 209 -- .../assembler/MacroAssemblerX86Common.h | 1228 +------- .../assembler/MacroAssemblerX86_64.h | 554 ---- js/src/assembler/assembler/RepatchBuffer.h | 163 - js/src/assembler/assembler/SparcAssembler.h | 1217 -------- js/src/assembler/moco/MocoStubs.h | 38 - js/src/assembler/wtf/SegmentedVector.h | 264 -- js/src/jit/arm/Assembler-arm.h | 1 - js/src/jit/shared/Assembler-x86-shared.h | 3 - .../IonAssemblerBufferWithConstantPools.h | 1 - js/src/jit/x86/Assembler-x86.h | 1 - js/src/moz.build | 1 - 29 files changed, 19 insertions(+), 18915 deletions(-) delete mode 100644 js/src/assembler/TestMain.cpp delete mode 100644 js/src/assembler/assembler/ARMAssembler.cpp delete mode 100644 js/src/assembler/assembler/ARMAssembler.h delete mode 100644 js/src/assembler/assembler/ARMv7Assembler.h delete mode 100644 js/src/assembler/assembler/AbstractMacroAssembler.h delete mode 100644 js/src/assembler/assembler/AssemblerBufferWithConstantPool.h delete mode 100644 js/src/assembler/assembler/CodeLocation.h delete mode 100644 js/src/assembler/assembler/LinkBuffer.h delete mode 100644 js/src/assembler/assembler/MIPSAssembler.h delete mode 100644 js/src/assembler/assembler/MacroAssemblerCodeRef.h delete mode 100644 js/src/assembler/assembler/RepatchBuffer.h delete mode 100644 js/src/assembler/assembler/SparcAssembler.h delete mode 100644 js/src/assembler/moco/MocoStubs.h delete mode 100644 js/src/assembler/wtf/SegmentedVector.h diff --git a/config/check_spidermonkey_style.py b/config/check_spidermonkey_style.py index a31d84e7853..d5956280a37 100644 --- a/config/check_spidermonkey_style.py +++ b/config/check_spidermonkey_style.py @@ -482,9 +482,9 @@ def do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclname error(filename, str(include1.linenum) + ':' + str(include2.linenum), include1.quote() + ' should be included after ' + include2.quote()) - # The #include statements in the files in assembler/ and yarr/ have all manner of implicit + # The #include statements in the files in assembler/ have all manner of implicit # ordering requirements. Boo. Ignore them. - skip_order_checking = inclname.startswith(('assembler/', 'yarr/')) + skip_order_checking = inclname.startswith('assembler/') # Check the extracted #include statements, both individually, and the ordering of # adjacent pairs that live in the same block. diff --git a/js/src/assembler/TestMain.cpp b/js/src/assembler/TestMain.cpp deleted file mode 100644 index 49cd4c70f70..00000000000 --- a/js/src/assembler/TestMain.cpp +++ /dev/null @@ -1,933 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - - -// A short test program with which to experiment with the assembler. - -//satisfies CPU(X86_64) -//#define WTF_CPU_X86_64 - -// satisfies ENABLE(ASSEMBLER) -#define ENABLE_ASSEMBLER 1 - -// satisfies ENABLE(JIT) -#define ENABLE_JIT 1 - -#define USE_SYSTEM_MALLOC 1 -// leads to FORCE_SYSTEM_MALLOC in wtf/FastMalloc.cpp - -#include "assembler/jit/ExecutableAllocator.h" -#include "assembler/assembler/LinkBuffer.h" -#include "assembler/assembler/CodeLocation.h" -#include "assembler/assembler/RepatchBuffer.h" - -#include "assembler/assembler/MacroAssembler.h" - -#include - -///////////////////////////////////////////////////////////////// -// Temporary scaffolding for selecting the arch -#undef ARCH_x86 -#undef ARCH_amd64 -#undef ARCH_arm - -#if defined(__APPLE__) && defined(__i386__) -# define ARCH_x86 1 -#elif defined(__APPLE__) && defined(__x86_64__) -# define ARCH_amd64 1 -#elif defined(__linux__) && defined(__i386__) -# define ARCH_x86 1 -#elif defined(__linux__) && defined(__x86_64__) -# define ARCH_amd64 1 -#elif defined(__linux__) && defined(__arm__) -# define ARCH_arm 1 -#elif defined(_MSC_VER) && defined(_M_IX86) -# define ARCH_x86 1 -#endif -///////////////////////////////////////////////////////////////// - -// just somewhere convenient to put a breakpoint, before -// running gdb -#if WTF_COMPILER_GCC -__attribute__((noinline)) -#endif -void pre_run ( void ) { } - -///////////////////////////////////////////////////////////////// -//// test1 (simple straight line code) -#if WTF_COMPILER_GCC - -void test1 ( void ) -{ - printf("\n------------ Test 1 (straight line code) ------------\n\n" ); - - // Create new assembler - JSC::MacroAssembler* am = new JSC::MacroAssembler(); - -#if defined(ARCH_amd64) - JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; - // dump some instructions into it - // xor %r15,%r15 - // add $0x7b,%r15 - // add $0x141,%r15 - // retq - am->xorPtr(areg,areg); - am->addPtr(JSC::MacroAssembler::Imm32(123), areg); - am->addPtr(JSC::MacroAssembler::Imm32(321), areg); - am->ret(); -#endif - -#if defined(ARCH_x86) - JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; - // dump some instructions into it - // xor %edi,%edi - // add $0x7b,%edi - // add $0x141,%edi - // ret - am->xorPtr(areg,areg); - am->addPtr(JSC::MacroAssembler::Imm32(123), areg); - am->addPtr(JSC::MacroAssembler::Imm32(321), areg); - am->ret(); -#endif - -#if defined(ARCH_arm) - JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; - // eors r8, r8, r8 - // adds r8, r8, #123 ; 0x7b - // mov r3, #256 ; 0x100 - // orr r3, r3, #65 ; 0x41 - // adds r8, r8, r3 - // mov pc, lr - am->xorPtr(areg,areg); - am->addPtr(JSC::MacroAssembler::Imm32(123), areg); - am->addPtr(JSC::MacroAssembler::Imm32(321), areg); - am->ret(); -#endif - - // prepare a link buffer, into which we can copy the completed insns - JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); - - // intermediate step .. get the pool suited for the size of code in 'am' - //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); - JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); - - // constructor for LinkBuffer asks ep to allocate r-x memory, - // then copies it there. - JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); - - // finalize - JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); - - // cr now holds a pointer to the final runnable code. - void* entry = cr.m_code.executableAddress(); - - printf("disas %p %p\n", - entry, (char*)entry + cr.m_size); - pre_run(); - - unsigned long result = 0x55555555; - -#if defined(ARCH_amd64) - // call the generated piece of code. It puts its result in r15. - __asm__ __volatile__( - "callq *%1" "\n\t" - "movq %%r15, %0" "\n" - :/*out*/ "=r"(result) - :/*in*/ "r"(entry) - :/*trash*/ "r15","cc" - ); -#endif -#if defined(ARCH_x86) - // call the generated piece of code. It puts its result in edi. - __asm__ __volatile__( - "calll *%1" "\n\t" - "movl %%edi, %0" "\n" - :/*out*/ "=r"(result) - :/*in*/ "r"(entry) - :/*trash*/ "edi","cc" - ); -#endif -#if defined(ARCH_arm) - // call the generated piece of code. It puts its result in r8. - __asm__ __volatile__( - "blx %1" "\n\t" - "mov %0, %%r8" "\n" - :/*out*/ "=r"(result) - :/*in*/ "r"(entry) - :/*trash*/ "r8","cc" - ); -#endif - - printf("\n"); - printf("value computed is %lu (expected 444)\n", result); - printf("\n"); - - delete eal; - delete am; -} - -#endif /* WTF_COMPILER_GCC */ - -///////////////////////////////////////////////////////////////// -//// test2 (a simple counting-down loop) -#if WTF_COMPILER_GCC - -void test2 ( void ) -{ - printf("\n------------ Test 2 (mini loop) ------------\n\n" ); - - // Create new assembler - JSC::MacroAssembler* am = new JSC::MacroAssembler(); - -#if defined(ARCH_amd64) - JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; - // xor %r15,%r15 - // add $0x7b,%r15 - // add $0x141,%r15 - // sub $0x1,%r15 - // mov $0x0,%r11 - // cmp %r11,%r15 - // jne 0x7ff6d3e6a00e - // retq - // so r15 always winds up being zero - am->xorPtr(areg,areg); - am->addPtr(JSC::MacroAssembler::Imm32(123), areg); - am->addPtr(JSC::MacroAssembler::Imm32(321), areg); - - JSC::MacroAssembler::Label loopHeadLabel(am); - am->subPtr(JSC::MacroAssembler::Imm32(1), areg); - - JSC::MacroAssembler::Jump j - = am->branchPtr(JSC::MacroAssembler::NotEqual, - areg, JSC::MacroAssembler::ImmPtr(0)); - j.linkTo(loopHeadLabel, am); - - am->ret(); -#endif - -#if defined(ARCH_x86) - JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; - // xor %edi,%edi - // add $0x7b,%edi - // add $0x141,%edi - // sub $0x1,%edi - // test %edi,%edi - // jne 0xf7f9700b - // ret - // so edi always winds up being zero - am->xorPtr(areg,areg); - am->addPtr(JSC::MacroAssembler::Imm32(123), areg); - am->addPtr(JSC::MacroAssembler::Imm32(321), areg); - - JSC::MacroAssembler::Label loopHeadLabel(am); - am->subPtr(JSC::MacroAssembler::Imm32(1), areg); - - JSC::MacroAssembler::Jump j - = am->branchPtr(JSC::MacroAssembler::NotEqual, - areg, JSC::MacroAssembler::ImmPtr(0)); - j.linkTo(loopHeadLabel, am); - - am->ret(); -#endif - -#if defined(ARCH_arm) - JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; - // eors r8, r8, r8 - // adds r8, r8, #123 ; 0x7b - // mov r3, #256 ; 0x100 - // orr r3, r3, #65 ; 0x41 - // adds r8, r8, r3 - // subs r8, r8, #1 ; 0x1 - // ldr r3, [pc, #8] ; 0x40026028 - // cmp r8, r3 - // bne 0x40026014 - // mov pc, lr - // andeq r0, r0, r0 // DATA (0) - // andeq r0, r0, r4, lsl r0 // DATA (?? what's this for?) - // so r8 always winds up being zero - am->xorPtr(areg,areg); - am->addPtr(JSC::MacroAssembler::Imm32(123), areg); - am->addPtr(JSC::MacroAssembler::Imm32(321), areg); - - JSC::MacroAssembler::Label loopHeadLabel(am); - am->subPtr(JSC::MacroAssembler::Imm32(1), areg); - - JSC::MacroAssembler::Jump j - = am->branchPtr(JSC::MacroAssembler::NotEqual, - areg, JSC::MacroAssembler::ImmPtr(0)); - j.linkTo(loopHeadLabel, am); - - am->ret(); -#endif - - // prepare a link buffer, into which we can copy the completed insns - JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); - - // intermediate step .. get the pool suited for the size of code in 'am' - //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); - JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); - - // constructor for LinkBuffer asks ep to allocate r-x memory, - // then copies it there. - JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); - - // finalize - JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); - - // cr now holds a pointer to the final runnable code. - void* entry = cr.m_code.executableAddress(); - - printf("disas %p %p\n", - entry, (char*)entry + cr.m_size); - pre_run(); - - unsigned long result = 0x55555555; - -#if defined(ARCH_amd64) - // call the generated piece of code. It puts its result in r15. - __asm__ __volatile__( - "callq *%1" "\n\t" - "movq %%r15, %0" "\n" - :/*out*/ "=r"(result) - :/*in*/ "r"(entry) - :/*trash*/ "r15","cc" - ); -#endif -#if defined(ARCH_x86) - // call the generated piece of code. It puts its result in edi. - __asm__ __volatile__( - "calll *%1" "\n\t" - "movl %%edi, %0" "\n" - :/*out*/ "=r"(result) - :/*in*/ "r"(entry) - :/*trash*/ "edi","cc" - ); -#endif -#if defined(ARCH_arm) - // call the generated piece of code. It puts its result in r8. - __asm__ __volatile__( - "blx %1" "\n\t" - "mov %0, %%r8" "\n" - :/*out*/ "=r"(result) - :/*in*/ "r"(entry) - :/*trash*/ "r8","cc" - ); -#endif - - printf("\n"); - printf("value computed is %lu (expected 0)\n", result); - printf("\n"); - - delete eal; - delete am; -} - -#endif /* WTF_COMPILER_GCC */ - -///////////////////////////////////////////////////////////////// -//// test3 (if-then-else) -#if WTF_COMPILER_GCC - -void test3 ( void ) -{ - printf("\n------------ Test 3 (if-then-else) ------------\n\n" ); - - // Create new assembler - JSC::MacroAssembler* am = new JSC::MacroAssembler(); - -#if defined(ARCH_amd64) - JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; - // mov $0x64,%r15d - // mov $0x0,%r11 - // cmp %r11,%r15 - // jne 0x7ff6d3e6a024 - // mov $0x40,%r15d - // jmpq 0x7ff6d3e6a02a - // mov $0x4,%r15d - // retq - // so r15 ends up being 4 - - // put a value in reg - am->move(JSC::MacroAssembler::Imm32(100), areg); - - // test, and conditionally jump to 'else' branch - JSC::MacroAssembler::Jump jToElse - = am->branchPtr(JSC::MacroAssembler::NotEqual, - areg, JSC::MacroAssembler::ImmPtr(0)); - - // 'then' branch - am->move(JSC::MacroAssembler::Imm32(64), areg); - JSC::MacroAssembler::Jump jToAfter - = am->jump(); - - // 'else' branch - JSC::MacroAssembler::Label elseLbl(am); - am->move(JSC::MacroAssembler::Imm32(4), areg); - - // after - JSC::MacroAssembler::Label afterLbl(am); - - am->ret(); -#endif - -#if defined(ARCH_x86) - JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; - // mov $0x64,%edi - // test %edi,%edi - // jne 0xf7f22017 - // mov $0x40,%edi - // jmp 0xf7f2201c - // mov $0x4,%edi - // ret - // so edi ends up being 4 - - // put a value in reg - am->move(JSC::MacroAssembler::Imm32(100), areg); - - // test, and conditionally jump to 'else' branch - JSC::MacroAssembler::Jump jToElse - = am->branchPtr(JSC::MacroAssembler::NotEqual, - areg, JSC::MacroAssembler::ImmPtr(0)); - - // 'then' branch - am->move(JSC::MacroAssembler::Imm32(64), areg); - JSC::MacroAssembler::Jump jToAfter - = am->jump(); - - // 'else' branch - JSC::MacroAssembler::Label elseLbl(am); - am->move(JSC::MacroAssembler::Imm32(4), areg); - - // after - JSC::MacroAssembler::Label afterLbl(am); - - am->ret(); -#endif - -#if defined(ARCH_arm) - JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; - // mov r8, #100 ; 0x64 - // ldr r3, [pc, #20] ; 0x40026020 - // cmp r8, r3 - // bne 0x40026018 - // mov r8, #64 ; 0x40 - // b 0x4002601c - // mov r8, #4 ; 0x4 - // mov pc, lr - // andeq r0, r0, r0 // DATA - // andeq r0, r0, r8, lsl r0 // DATA - // andeq r0, r0, r12, lsl r0 // DATA - // ldr r3, [r3, -r3] // DATA - // so r8 ends up being 4 - - // put a value in reg - am->move(JSC::MacroAssembler::Imm32(100), areg); - - // test, and conditionally jump to 'else' branch - JSC::MacroAssembler::Jump jToElse - = am->branchPtr(JSC::MacroAssembler::NotEqual, - areg, JSC::MacroAssembler::ImmPtr(0)); - - // 'then' branch - am->move(JSC::MacroAssembler::Imm32(64), areg); - JSC::MacroAssembler::Jump jToAfter - = am->jump(); - - // 'else' branch - JSC::MacroAssembler::Label elseLbl(am); - am->move(JSC::MacroAssembler::Imm32(4), areg); - - // after - JSC::MacroAssembler::Label afterLbl(am); - - am->ret(); -#endif - - // set branch targets appropriately - jToElse.linkTo(elseLbl, am); - jToAfter.linkTo(afterLbl, am); - - // prepare a link buffer, into which we can copy the completed insns - JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); - - // intermediate step .. get the pool suited for the size of code in 'am' - //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); - JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); - - // constructor for LinkBuffer asks ep to allocate r-x memory, - // then copies it there. - JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); - - // finalize - JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); - - // cr now holds a pointer to the final runnable code. - void* entry = cr.m_code.executableAddress(); - - printf("disas %p %p\n", - entry, (char*)entry + cr.m_size); - pre_run(); - - unsigned long result = 0x55555555; - -#if defined(ARCH_amd64) - // call the generated piece of code. It puts its result in r15. - __asm__ __volatile__( - "callq *%1" "\n\t" - "movq %%r15, %0" "\n" - :/*out*/ "=r"(result) - :/*in*/ "r"(entry) - :/*trash*/ "r15","cc" - ); -#endif -#if defined(ARCH_x86) - // call the generated piece of code. It puts its result in edi. - __asm__ __volatile__( - "calll *%1" "\n\t" - "movl %%edi, %0" "\n" - :/*out*/ "=r"(result) - :/*in*/ "r"(entry) - :/*trash*/ "edi","cc" - ); -#endif -#if defined(ARCH_arm) - // call the generated piece of code. It puts its result in r8. - __asm__ __volatile__( - "blx %1" "\n\t" - "mov %0, %%r8" "\n" - :/*out*/ "=r"(result) - :/*in*/ "r"(entry) - :/*trash*/ "r8","cc" - ); -#endif - - printf("\n"); - printf("value computed is %lu (expected 4)\n", result); - printf("\n"); - - delete eal; - delete am; -} - -#endif /* WTF_COMPILER_GCC */ - -///////////////////////////////////////////////////////////////// -//// test4 (callable function) - -void test4 ( void ) -{ - printf("\n------------ Test 4 (callable fn) ------------\n\n" ); - - // Create new assembler - JSC::MacroAssembler* am = new JSC::MacroAssembler(); - -#if defined(ARCH_amd64) - // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function - // push %rbp - // mov %rsp,%rbp - // push %rbx - // push %r12 - // push %r13 - // push %r14 - // push %r15 - // xor %rax,%rax - // add $0x7b,%rax - // add $0x141,%rax - // pop %r15 - // pop %r14 - // pop %r13 - // pop %r12 - // pop %rbx - // mov %rbp,%rsp - // pop %rbp - // retq - // callable as a normal function, returns 444 - - JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax; - am->push(JSC::X86Registers::ebp); - am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); - am->push(JSC::X86Registers::ebx); - am->push(JSC::X86Registers::r12); - am->push(JSC::X86Registers::r13); - am->push(JSC::X86Registers::r14); - am->push(JSC::X86Registers::r15); - - am->xorPtr(rreg,rreg); - am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); - am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); - - am->pop(JSC::X86Registers::r15); - am->pop(JSC::X86Registers::r14); - am->pop(JSC::X86Registers::r13); - am->pop(JSC::X86Registers::r12); - am->pop(JSC::X86Registers::ebx); - am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); - am->pop(JSC::X86Registers::ebp); - am->ret(); -#endif - -#if defined(ARCH_x86) - // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function - // push %ebp - // mov %esp,%ebp - // push %ebx - // push %esi - // push %edi - // xor %eax,%eax - // add $0x7b,%eax - // add $0x141,%eax - // pop %edi - // pop %esi - // pop %ebx - // mov %ebp,%esp - // pop %ebp - // ret - // callable as a normal function, returns 444 - - JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax; - - am->push(JSC::X86Registers::ebp); - am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); - am->push(JSC::X86Registers::ebx); - am->push(JSC::X86Registers::esi); - am->push(JSC::X86Registers::edi); - - am->xorPtr(rreg,rreg); - am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); - am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); - - am->pop(JSC::X86Registers::edi); - am->pop(JSC::X86Registers::esi); - am->pop(JSC::X86Registers::ebx); - am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); - am->pop(JSC::X86Registers::ebp); - am->ret(); -#endif - -#if defined(ARCH_arm) - // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function - // push {r4} ; (str r4, [sp, #-4]!) - // push {r5} ; (str r5, [sp, #-4]!) - // push {r6} ; (str r6, [sp, #-4]!) - // push {r7} ; (str r7, [sp, #-4]!) - // push {r8} ; (str r8, [sp, #-4]!) - // push {r9} ; (str r9, [sp, #-4]!) - // push {r10} ; (str r10, [sp, #-4]!) - // push {r11} ; (str r11, [sp, #-4]!) - // eors r0, r0, r0 - // adds r0, r0, #123 ; 0x7b - // mov r3, #256 ; 0x100 - // orr r3, r3, #65 ; 0x41 - // adds r0, r0, r3 - // pop {r11} ; (ldr r11, [sp], #4) - // pop {r10} ; (ldr r10, [sp], #4) - // pop {r9} ; (ldr r9, [sp], #4) - // pop {r8} ; (ldr r8, [sp], #4) - // pop {r7} ; (ldr r7, [sp], #4) - // pop {r6} ; (ldr r6, [sp], #4) - // pop {r5} ; (ldr r5, [sp], #4) - // pop {r4} ; (ldr r4, [sp], #4) - // mov pc, lr - // callable as a normal function, returns 444 - - JSC::ARMRegisters::RegisterID rreg = JSC::ARMRegisters::r0; - - am->push(JSC::ARMRegisters::r4); - am->push(JSC::ARMRegisters::r5); - am->push(JSC::ARMRegisters::r6); - am->push(JSC::ARMRegisters::r7); - am->push(JSC::ARMRegisters::r8); - am->push(JSC::ARMRegisters::r9); - am->push(JSC::ARMRegisters::r10); - am->push(JSC::ARMRegisters::r11); - - am->xorPtr(rreg,rreg); - am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); - am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); - - am->pop(JSC::ARMRegisters::r11); - am->pop(JSC::ARMRegisters::r10); - am->pop(JSC::ARMRegisters::r9); - am->pop(JSC::ARMRegisters::r8); - am->pop(JSC::ARMRegisters::r7); - am->pop(JSC::ARMRegisters::r6); - am->pop(JSC::ARMRegisters::r5); - am->pop(JSC::ARMRegisters::r4); - - am->ret(); -#endif - - // prepare a link buffer, into which we can copy the completed insns - JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); - - // intermediate step .. get the pool suited for the size of code in 'am' - //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); - JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); - - // constructor for LinkBuffer asks ep to allocate r-x memory, - // then copies it there. - JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); - - // now fix up any branches/calls - //JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube ); - - // finalize - JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); - - // cr now holds a pointer to the final runnable code. - void* entry = cr.m_code.executableAddress(); - - printf("disas %p %p\n", - entry, (char*)entry + cr.m_size); - pre_run(); - - // call the function - unsigned long (*fn)(void) = (unsigned long (*)())entry; - unsigned long result = fn(); - - printf("\n"); - printf("value computed is %lu (expected 444)\n", result); - printf("\n"); - - delete eal; - delete am; -} - - -///////////////////////////////////////////////////////////////// -//// test5 (call in, out, repatch) - -// a function which we will call from the JIT generated code -unsigned long cube ( unsigned long x ) { return x * x * x; } -unsigned long square ( unsigned long x ) { return x * x; } - -void test5 ( void ) -{ - printf("\n--------- Test 5 (call in, out, repatch) ---------\n\n" ); - - // Create new assembler - JSC::MacroAssembler* am = new JSC::MacroAssembler(); - JSC::MacroAssembler::Call cl; - ptrdiff_t offset_of_call_insn; - -#if defined(ARCH_amd64) - // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function - // and then call a non-JIT-generated helper from within - // this code - // push %rbp - // mov %rsp,%rbp - // push %rbx - // push %r12 - // push %r13 - // push %r14 - // push %r15 - // mov $0x9,%edi - // mov $0x40187e,%r11 - // callq *%r11 - // pop %r15 - // pop %r14 - // pop %r13 - // pop %r12 - // pop %rbx - // mov %rbp,%rsp - // pop %rbp - // retq - JSC::MacroAssembler::Label startOfFnLbl(am); - am->push(JSC::X86Registers::ebp); - am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); - am->push(JSC::X86Registers::ebx); - am->push(JSC::X86Registers::r12); - am->push(JSC::X86Registers::r13); - am->push(JSC::X86Registers::r14); - am->push(JSC::X86Registers::r15); - - // let's compute cube(9). Move $9 to the first arg reg. - am->move(JSC::MacroAssembler::Imm32(9), JSC::X86Registers::edi); - cl = am->JSC::MacroAssembler::call(); - - // result is now in %rax. Leave it ther and just return. - - am->pop(JSC::X86Registers::r15); - am->pop(JSC::X86Registers::r14); - am->pop(JSC::X86Registers::r13); - am->pop(JSC::X86Registers::r12); - am->pop(JSC::X86Registers::ebx); - am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); - am->pop(JSC::X86Registers::ebp); - am->ret(); - - offset_of_call_insn - = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); - if (0) printf("XXXXXXXX offset = %lu\n", offset_of_call_insn); -#endif - -#if defined(ARCH_x86) - // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function - // and then call a non-JIT-generated helper from within - // this code - // push %ebp - // mov %esp,%ebp - // push %ebx - // push %esi - // push %edi - // push $0x9 - // call 0x80490e9 <_Z4cubem> - // add $0x4,%esp - // pop %edi - // pop %esi - // pop %ebx - // mov %ebp,%esp - // pop %ebp - // ret - JSC::MacroAssembler::Label startOfFnLbl(am); - am->push(JSC::X86Registers::ebp); - am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); - am->push(JSC::X86Registers::ebx); - am->push(JSC::X86Registers::esi); - am->push(JSC::X86Registers::edi); - - // let's compute cube(9). Push $9 on the stack. - am->push(JSC::MacroAssembler::Imm32(9)); - cl = am->JSC::MacroAssembler::call(); - am->addPtr(JSC::MacroAssembler::Imm32(4), JSC::X86Registers::esp); - // result is now in %eax. Leave it there and just return. - - am->pop(JSC::X86Registers::edi); - am->pop(JSC::X86Registers::esi); - am->pop(JSC::X86Registers::ebx); - am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); - am->pop(JSC::X86Registers::ebp); - am->ret(); - - offset_of_call_insn - = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); - if (0) printf("XXXXXXXX offset = %lu\n", - (unsigned long)offset_of_call_insn); -#endif - -#if defined(ARCH_arm) - // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function - // push {r4} ; (str r4, [sp, #-4]!) - // push {r5} ; (str r5, [sp, #-4]!) - // push {r6} ; (str r6, [sp, #-4]!) - // push {r7} ; (str r7, [sp, #-4]!) - // push {r8} ; (str r8, [sp, #-4]!) - // push {r9} ; (str r9, [sp, #-4]!) - // push {r10} ; (str r10, [sp, #-4]!) - // push {r11} ; (str r11, [sp, #-4]!) - // eors r0, r0, r0 - // adds r0, r0, #123 ; 0x7b - // mov r3, #256 ; 0x100 - // orr r3, r3, #65 ; 0x41 - // adds r0, r0, r3 - // pop {r11} ; (ldr r11, [sp], #4) - // pop {r10} ; (ldr r10, [sp], #4) - // pop {r9} ; (ldr r9, [sp], #4) - // pop {r8} ; (ldr r8, [sp], #4) - // pop {r7} ; (ldr r7, [sp], #4) - // pop {r6} ; (ldr r6, [sp], #4) - // pop {r5} ; (ldr r5, [sp], #4) - // pop {r4} ; (ldr r4, [sp], #4) - // mov pc, lr - // callable as a normal function, returns 444 - JSC::MacroAssembler::Label startOfFnLbl(am); - am->push(JSC::ARMRegisters::r4); - am->push(JSC::ARMRegisters::r5); - am->push(JSC::ARMRegisters::r6); - am->push(JSC::ARMRegisters::r7); - am->push(JSC::ARMRegisters::r8); - am->push(JSC::ARMRegisters::r9); - am->push(JSC::ARMRegisters::r10); - am->push(JSC::ARMRegisters::r11); - am->push(JSC::ARMRegisters::lr); - - // let's compute cube(9). Get $9 into r0. - am->move(JSC::MacroAssembler::Imm32(9), JSC::ARMRegisters::r0); - cl = am->JSC::MacroAssembler::call(); - // result is now in r0. Leave it there and just return. - - am->pop(JSC::ARMRegisters::lr); - am->pop(JSC::ARMRegisters::r11); - am->pop(JSC::ARMRegisters::r10); - am->pop(JSC::ARMRegisters::r9); - am->pop(JSC::ARMRegisters::r8); - am->pop(JSC::ARMRegisters::r7); - am->pop(JSC::ARMRegisters::r6); - am->pop(JSC::ARMRegisters::r5); - am->pop(JSC::ARMRegisters::r4); - am->ret(); - - offset_of_call_insn - = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); - if (0) printf("XXXXXXXX offset = %lu\n", - (unsigned long)offset_of_call_insn); -#endif - - // prepare a link buffer, into which we can copy the completed insns - JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); - - // intermediate step .. get the pool suited for the size of code in 'am' - //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); - JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); - - // constructor for LinkBuffer asks ep to allocate r-x memory, - // then copies it there. - JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); - - // now fix up any branches/calls - JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube ); - patchBuffer.link(cl, target); - - JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); - - // cr now holds a pointer to the final runnable code. - void* entry = cr.m_code.executableAddress(); - - printf("disas %p %p\n", - entry, (char*)entry + cr.m_size); - - - pre_run(); - - printf("\n"); - - unsigned long (*fn)() = (unsigned long(*)())entry; - unsigned long result = fn(); - - printf("value computed is %lu (expected 729)\n", result); - printf("\n"); - - // now repatch the call in the JITted code to go elsewhere - JSC::JITCode jc = JSC::JITCode::JITCode(entry, cr.m_size); - JSC::CodeBlock cb = JSC::CodeBlock::CodeBlock(jc); - - // the address of the call insn, that we want to prod - JSC::MacroAssemblerCodePtr cp - = JSC::MacroAssemblerCodePtr( ((char*)entry) + offset_of_call_insn ); - - JSC::RepatchBuffer repatchBuffer(&cb); - repatchBuffer.relink( JSC::CodeLocationCall(cp), - JSC::FunctionPtr::FunctionPtr( &square )); - - result = fn(); - printf("value computed is %lu (expected 81)\n", result); - printf("\n\n"); - - delete eal; - delete am; -} - -///////////////////////////////////////////////////////////////// - -int main ( void ) -{ -#if WTF_COMPILER_GCC - test1(); - test2(); - test3(); -#endif - test4(); - test5(); - return 0; -} diff --git a/js/src/assembler/assembler/ARMAssembler.cpp b/js/src/assembler/assembler/ARMAssembler.cpp deleted file mode 100644 index 95f458fbfd9..00000000000 --- a/js/src/assembler/assembler/ARMAssembler.cpp +++ /dev/null @@ -1,669 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2009 University of Szeged - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#include "assembler/wtf/Platform.h" - -#if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL - -#include "assembler/assembler/ARMAssembler.h" - -namespace JSC { - -// Patching helpers - -void ARMAssembler::patchConstantPoolLoad(void* loadAddr, void* constPoolAddr) -{ - ARMWord *ldr = reinterpret_cast(loadAddr); - ARMWord diff = reinterpret_cast(constPoolAddr) - ldr; - ARMWord index = (*ldr & 0xfff) >> 1; - - ASSERT(diff >= 1); - if (diff >= 2 || index > 0) { - diff = (diff + index - 2) * sizeof(ARMWord); - ASSERT(diff <= 0xfff); - *ldr = (*ldr & ~0xfff) | diff; - } else - *ldr = (*ldr & ~(0xfff | ARMAssembler::DT_UP)) | sizeof(ARMWord); -} - -// Handle immediates - -ARMWord ARMAssembler::getOp2(ARMWord imm) -{ - int rol; - - if (imm <= 0xff) - return OP2_IMM | imm; - - if ((imm & 0xff000000) == 0) { - imm <<= 8; - rol = 8; - } - else { - imm = (imm << 24) | (imm >> 8); - rol = 0; - } - - if ((imm & 0xff000000) == 0) { - imm <<= 8; - rol += 4; - } - - if ((imm & 0xf0000000) == 0) { - imm <<= 4; - rol += 2; - } - - if ((imm & 0xc0000000) == 0) { - imm <<= 2; - rol += 1; - } - - if ((imm & 0x00ffffff) == 0) - return OP2_IMM | (imm >> 24) | (rol << 8); - - return INVALID_IMM; -} - -ARMWord ARMAssembler::getOp2RegScale(RegisterID reg, ARMWord scale) -{ - // The field that this method constructs looks like this: - // [11:7] Shift immediate. - // [ 6:5] Shift type. Only LSL ("00") is used here. - // [ 4:4] 0. - // [ 3:0] The register to shift. - - ARMWord shift; // Shift field. This is log2(scale). - ARMWord lz; // Leading zeroes. - - // Calculate shift=log2(scale). -#if WTF_ARM_ARCH_AT_LEAST_5 - asm ( - " clz %[lz], %[scale]\n" - : [lz] "=r" (lz) - : [scale] "r" (scale) - : // No clobbers. - ); -#else - lz = 0; // Accumulate leading zeroes. - for (ARMWord s = 16; s > 0; s /= 2) { - ARMWord mask = 0xffffffff << (32-lz-s); - if ((scale & mask) == 0) { - lz += s; - } - } -#endif - if (lz >= 32) { - return INVALID_IMM; - } - shift = 31-lz; - // Check that scale was a power of 2. - if ((1u<> (32 - rol)); - rol = 4 + (rol >> 1); - break; - } - rol += 2; - mask >>= 2; - if (mask & 0x3) { - // rol 8 - imm = (imm << 8) | (imm >> 24); - mask = 0xff00; - rol = 24; - while (1) { - if ((imm & mask) == 0) { - imm = (imm << rol) | (imm >> (32 - rol)); - rol = (rol >> 1) - 8; - break; - } - rol += 2; - mask >>= 2; - if (mask & 0x3) - return 0; - } - break; - } - } - - ASSERT((imm & 0xff) == 0); - - if ((imm & 0xff000000) == 0) { - imm1 = OP2_IMM | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8); - imm2 = OP2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8); - } else if (imm & 0xc0000000) { - imm1 = OP2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8); - imm <<= 8; - rol += 4; - - if ((imm & 0xff000000) == 0) { - imm <<= 8; - rol += 4; - } - - if ((imm & 0xf0000000) == 0) { - imm <<= 4; - rol += 2; - } - - if ((imm & 0xc0000000) == 0) { - imm <<= 2; - rol += 1; - } - - if ((imm & 0x00ffffff) == 0) - imm2 = OP2_IMM | (imm >> 24) | ((rol & 0xf) << 8); - else - return 0; - } else { - if ((imm & 0xf0000000) == 0) { - imm <<= 4; - rol += 2; - } - - if ((imm & 0xc0000000) == 0) { - imm <<= 2; - rol += 1; - } - - imm1 = OP2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8); - imm <<= 8; - rol += 4; - - if ((imm & 0xf0000000) == 0) { - imm <<= 4; - rol += 2; - } - - if ((imm & 0xc0000000) == 0) { - imm <<= 2; - rol += 1; - } - - if ((imm & 0x00ffffff) == 0) - imm2 = OP2_IMM | (imm >> 24) | ((rol & 0xf) << 8); - else - return 0; - } - - if (positive) { - mov_r(reg, imm1); - orr_r(reg, reg, imm2); - } else { - mvn_r(reg, imm1); - bic_r(reg, reg, imm2); - } - - return 1; -} - -#ifdef __GNUC__ -// If the result of this function isn't used, the caller should probably be -// using movImm. -__attribute__((warn_unused_result)) -#endif -ARMWord ARMAssembler::getImm(ARMWord imm, int tmpReg, bool invert) -{ - ARMWord tmp; - - // Do it by 1 instruction - tmp = getOp2(imm); - if (tmp != INVALID_IMM) - return tmp; - - tmp = getOp2(~imm); - if (tmp != INVALID_IMM) { - if (invert) - return tmp | OP2_INV_IMM; - mvn_r(tmpReg, tmp); - return tmpReg; - } - - return encodeComplexImm(imm, tmpReg); -} - -void ARMAssembler::moveImm(ARMWord imm, int dest) -{ - ARMWord tmp; - - // Do it by 1 instruction - tmp = getOp2(imm); - if (tmp != INVALID_IMM) { - mov_r(dest, tmp); - return; - } - - tmp = getOp2(~imm); - if (tmp != INVALID_IMM) { - mvn_r(dest, tmp); - return; - } - - encodeComplexImm(imm, dest); -} - -ARMWord ARMAssembler::encodeComplexImm(ARMWord imm, int dest) -{ -#if WTF_ARM_ARCH_VERSION >= 7 - ARMWord tmp = getImm16Op2(imm); - if (tmp != INVALID_IMM) { - movw_r(dest, tmp); - return dest; - } - movw_r(dest, getImm16Op2(imm & 0xffff)); - movt_r(dest, getImm16Op2(imm >> 16)); - return dest; -#else - // Do it by 2 instruction - if (genInt(dest, imm, true)) - return dest; - if (genInt(dest, ~imm, false)) - return dest; - - ldr_imm(dest, imm); - return dest; -#endif -} - -// Memory load/store helpers -// TODO: this does not take advantage of all of ARMv7's instruction encodings, it should. -void ARMAssembler::dataTransferN(bool isLoad, bool isSigned, int size, RegisterID rt, RegisterID base, int32_t offset) -{ - bool posOffset = true; - - // There may be more elegant ways of handling this, but this one works. - if (offset == int32_t(0x80000000)) { - // For even bigger offsets, load the entire offset into a register, then do an - // indexed load using the base register and the index register. - moveImm(offset, ARMRegisters::S0); - mem_reg_off(isLoad, isSigned, size, posOffset, rt, base, ARMRegisters::S0); - return; - } - if (offset < 0) { - offset = - offset; - posOffset = false; - } - - // max_ldr is also a mask. - int max_ldr = 0xfff; - int ldr_bits = 12; - if (size == 16 || (size == 8 && isSigned)) { - max_ldr = 0xff; - ldr_bits = 8; - } - - if (offset <= max_ldr) { - // LDR rd, [rb, #+offset] - mem_imm_off(isLoad, isSigned, size, posOffset, rt, base, offset); - } else if (offset <= ((max_ldr << 8) | 0xff)) { - // Add upper bits of offset to the base, and store the result into the temp register. - if (posOffset) { - add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> ldr_bits) | getOp2RotLSL(ldr_bits)); - } else { - sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> ldr_bits) | getOp2RotLSL(ldr_bits)); - } - // Load using the lower bits of the offset, using max_ldr as a mask. - mem_imm_off(isLoad, isSigned, size, posOffset, rt, - ARMRegisters::S0, (offset & max_ldr)); - } else { - // For even bigger offsets, load the entire offset into a register, then do an - // indexed load using the base register and the index register. - moveImm(offset, ARMRegisters::S0); - mem_reg_off(isLoad, isSigned, size, posOffset, rt, base, ARMRegisters::S0); - } -} - -void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset) -{ - if (offset >= 0) { - if (offset <= 0xfff) { - // LDR rd, [rb, +offset] - dtr_u(isLoad, srcDst, base, offset); - } else if (offset <= 0xfffff) { - // Add upper bits of offset to the base, and store the result into the temp register. - add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | getOp2RotLSL(12)); - // Load using the lower bits of the register. - dtr_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff)); - } else { - // For even bigger offsets, load the entire offset into a register, then do an - // indexed load using the base register and the index register. - moveImm(offset, ARMRegisters::S0); - dtr_ur(isLoad, srcDst, base, ARMRegisters::S0); - } - } else { - // Negative offsets. - if (offset >= -0xfff) { - dtr_d(isLoad, srcDst, base, -offset); - } else if (offset >= -0xfffff) { - sub_r(ARMRegisters::S0, base, OP2_IMM | (-offset >> 12) | getOp2RotLSL(12)); - dtr_d(isLoad, srcDst, ARMRegisters::S0, (-offset & 0xfff)); - } else { - moveImm(offset, ARMRegisters::S0); - dtr_ur(isLoad, srcDst, base, ARMRegisters::S0); - } - } -} -/* this is large, ugly and obsolete. dataTransferN is superior.*/ -void ARMAssembler::dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool isSigned) -{ - if (offset >= 0) { - if (offset <= 0xfff) { - if (isSigned) - mem_imm_off(isLoad, true, 8, true, srcDst, base, offset); - else - dtrb_u(isLoad, srcDst, base, offset); - } else if (offset <= 0xfffff) { - add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | getOp2RotLSL(12)); - if (isSigned) - mem_imm_off(isLoad, true, 8, true, srcDst, ARMRegisters::S0, (offset & 0xfff)); - else - dtrb_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff)); - } else { - moveImm(offset, ARMRegisters::S0); - if (isSigned) - mem_reg_off(isLoad, true, 8, true, srcDst, base, ARMRegisters::S0); - else - dtrb_ur(isLoad, srcDst, base, ARMRegisters::S0); - } - } else { - if (offset >= -0xfff) { - if (isSigned) - mem_imm_off(isLoad, true, 8, false, srcDst, base, -offset); - else - dtrb_d(isLoad, srcDst, base, -offset); - } else if (offset >= -0xfffff) { - sub_r(ARMRegisters::S0, base, OP2_IMM | (-offset >> 12) | getOp2RotLSL(12)); - if (isSigned) - mem_imm_off(isLoad, true, 8, false, srcDst, ARMRegisters::S0, (-offset & 0xfff)); - else - dtrb_d(isLoad, srcDst, ARMRegisters::S0, (-offset & 0xfff)); - - } else { - moveImm(offset, ARMRegisters::S0); - if (isSigned) - mem_reg_off(isLoad, true, 8, true, srcDst, base, ARMRegisters::S0); - else - dtrb_ur(isLoad, srcDst, base, ARMRegisters::S0); - - } - } -} - -// rather X86-like, implements dest <- [base, index * shift + offset] -void ARMAssembler::baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset) -{ - ARMWord op2; - - ASSERT(scale >= 0 && scale <= 3); - op2 = lsl(index, scale); - - if (offset >= 0 && offset <= 0xfff) { - add_r(ARMRegisters::S0, base, op2); - dtr_u(isLoad, srcDst, ARMRegisters::S0, offset); - return; - } - if (offset <= 0 && offset >= -0xfff) { - add_r(ARMRegisters::S0, base, op2); - dtr_d(isLoad, srcDst, ARMRegisters::S0, -offset); - return; - } - - ldr_un_imm(ARMRegisters::S0, offset); - add_r(ARMRegisters::S0, ARMRegisters::S0, op2); - dtr_ur(isLoad, srcDst, base, ARMRegisters::S0); -} - -void ARMAssembler::baseIndexTransferN(bool isLoad, bool isSigned, int size, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset) -{ - ARMWord op2; - - ASSERT(scale >= 0 && scale <= 3); - op2 = lsl(index, scale); - - if (offset >= -0xfff && offset <= 0xfff) { - add_r(ARMRegisters::S0, base, op2); - bool posOffset = true; - if (offset < 0) { - posOffset = false; - offset = -offset; - } - mem_imm_off(isLoad, isSigned, size, posOffset, srcDst, ARMRegisters::S0, offset); - return; - } - ldr_un_imm(ARMRegisters::S0, offset); - add_r(ARMRegisters::S0, ARMRegisters::S0, op2); - mem_reg_off(isLoad, isSigned, size, true, srcDst, base, ARMRegisters::S0); -} - -void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset) -{ - // VFP cannot directly access memory that is not four-byte-aligned, so - // special-case support will be required for such cases. However, we don't - // currently use any unaligned floating-point memory accesses and probably - // never will, so for now just assert that the offset is aligned. - // - // Note that we cannot assert that the base register is aligned, but in - // that case, an alignment fault will be raised at run-time. - ASSERT((offset & 0x3) == 0); - - // Try to use a single load/store instruction, or at least a simple address - // calculation. - if (offset >= 0) { - if (offset <= 0x3ff) { - fmem_imm_off(isLoad, true, true, srcDst, base, offset >> 2); - return; - } - if (offset <= 0x3ffff) { - add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | getOp2RotLSL(10)); - fmem_imm_off(isLoad, true, true, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); - return; - } - } else { - if (offset >= -0x3ff) { - fmem_imm_off(isLoad, true, false, srcDst, base, -offset >> 2); - return; - } - if (offset >= -0x3ffff) { - sub_r(ARMRegisters::S0, base, OP2_IMM | (-offset >> 10) | getOp2RotLSL(10)); - fmem_imm_off(isLoad, true, false, srcDst, ARMRegisters::S0, (-offset >> 2) & 0xff); - return; - } - } - - // Slow case for long-range accesses. - ldr_un_imm(ARMRegisters::S0, offset); - add_r(ARMRegisters::S0, ARMRegisters::S0, base); - fmem_imm_off(isLoad, true, true, srcDst, ARMRegisters::S0, 0); -} - -void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset, RegisterID index, int32_t scale) -{ - // This variant accesses memory at base+offset+(index*scale). VLDR and VSTR - // don't have such an addressing mode, so this access will require some - // arithmetic instructions. - - // This method does not support accesses that are not four-byte-aligned. - ASSERT((offset & 0x3) == 0); - - // Catch the trivial case, where scale is 0. - if (scale == 0) { - doubleTransfer(isLoad, srcDst, base, offset); - return; - } - - // Calculate the address, excluding the non-scaled offset. This is - // efficient for scale factors that are powers of two. - ARMWord op2_index = getOp2RegScale(index, scale); - if (op2_index == INVALID_IMM) { - // Use MUL to calculate scale factors that are not powers of two. - moveImm(scale, ARMRegisters::S0); - mul_r(ARMRegisters::S0, index, ARMRegisters::S0); - op2_index = ARMRegisters::S0; - } - - add_r(ARMRegisters::S0, base, op2_index); - doubleTransfer(isLoad, srcDst, ARMRegisters::S0, offset); -} - -void ARMAssembler::floatTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset) -{ - // Assert that the access is aligned, as in doubleTransfer. - ASSERT((offset & 0x3) == 0); - - // Try to use a single load/store instruction, or at least a simple address - // calculation. - if (offset >= 0) { - if (offset <= 0x3ff) { - fmem_imm_off(isLoad, false, true, srcDst, base, offset >> 2); - return; - } - if (offset <= 0x3ffff) { - add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | getOp2RotLSL(10)); - fmem_imm_off(isLoad, false, true, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); - return; - } - } else { - if (offset >= -0x3ff) { - fmem_imm_off(isLoad, false, false, srcDst, base, -offset >> 2); - return; - } - if (offset >= -0x3ffff) { - sub_r(ARMRegisters::S0, base, OP2_IMM | (-offset >> 10) | getOp2RotLSL(10)); - fmem_imm_off(isLoad, false, false, srcDst, ARMRegisters::S0, (-offset >> 2) & 0xff); - return; - } - } - - // Slow case for long-range accesses. - ldr_un_imm(ARMRegisters::S0, offset); - add_r(ARMRegisters::S0, ARMRegisters::S0, base); - fmem_imm_off(isLoad, false, true, srcDst, ARMRegisters::S0, 0); -} - -void ARMAssembler::baseIndexFloatTransfer(bool isLoad, bool isDouble, FPRegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset) -{ - ARMWord op2; - - ASSERT(scale >= 0 && scale <= 3); - op2 = lsl(index, scale); - // vldr/vstr have a more restricted range than your standard ldr. - // they get 8 bits that are implicitly shifted left by 2. - if (offset >= -(0xff<<2) && offset <= (0xff<<2)) { - add_r(ARMRegisters::S0, base, op2); - bool posOffset = true; - if (offset < 0) { - posOffset = false; - offset = -offset; - } - fmem_imm_off(isLoad, isDouble, posOffset, srcDst, ARMRegisters::S0, offset >> 2); - return; - } - - ldr_un_imm(ARMRegisters::S0, offset); - // vldr/vstr do not allow register-indexed operations, so we get to do this *manually*. - add_r(ARMRegisters::S0, ARMRegisters::S0, op2); - add_r(ARMRegisters::S0, ARMRegisters::S0, base); - - fmem_imm_off(isLoad, isDouble, true, srcDst, ARMRegisters::S0, 0); -} - -// Fix up the offsets and literal-pool loads in buffer. The buffer should -// already contain the code from m_buffer. -inline void ARMAssembler::fixUpOffsets(void * buffer) -{ - char * data = reinterpret_cast(buffer); - for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) { - // The last bit is set if the constant must be placed on constant pool. - int pos = (*iter) & (~0x1); - ARMWord* ldrAddr = reinterpret_cast(data + pos); - ARMWord* addr = getLdrImmAddress(ldrAddr); - if (*addr != InvalidBranchTarget) { -// The following is disabled for JM because we patch some branches after -// calling fixUpOffset, and the branch patcher doesn't know how to handle 'B' -// instructions. -#if 0 - if (!(*iter & 1)) { - int diff = reinterpret_cast(data + *addr) - (ldrAddr + DefaultPrefetching); - - if ((diff <= BOFFSET_MAX && diff >= BOFFSET_MIN)) { - *ldrAddr = B | getConditionalField(*ldrAddr) | (diff & BRANCH_MASK); - continue; - } - } -#endif - *addr = reinterpret_cast(data + *addr); - } - } -} - -void* ARMAssembler::executableAllocAndCopy(ExecutableAllocator* allocator, ExecutablePool **poolp, CodeKind kind) -{ - // 64-bit alignment is required for next constant pool and JIT code as well - m_buffer.flushWithoutBarrier(true); - if (m_buffer.uncheckedSize() & 0x7) - bkpt(0); - - void * data = m_buffer.executableAllocAndCopy(allocator, poolp, kind); - if (data) - fixUpOffsets(data); - return data; -} - -// This just dumps the code into the specified buffer, fixing up absolute -// offsets and literal pool loads as it goes. The buffer is assumed to be large -// enough to hold the code, and any pre-existing literal pool is assumed to -// have been flushed. -void ARMAssembler::executableCopy(void * buffer) -{ - ASSERT(m_buffer.sizeOfConstantPool() == 0); - memcpy(buffer, m_buffer.data(), m_buffer.size()); - fixUpOffsets(buffer); -} - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) diff --git a/js/src/assembler/assembler/ARMAssembler.h b/js/src/assembler/assembler/ARMAssembler.h deleted file mode 100644 index ffc99ca6d65..00000000000 --- a/js/src/assembler/assembler/ARMAssembler.h +++ /dev/null @@ -1,1713 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2009, 2010 University of Szeged - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef assembler_assembler_ARMAssembler_h -#define assembler_assembler_ARMAssembler_h - -#include "assembler/wtf/Platform.h" - -// Some debug code uses s(n)printf for instruction logging. -#include - -#if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL - -#include "assembler/assembler/AssemblerBufferWithConstantPool.h" -#include "assembler/wtf/Assertions.h" - -// TODO: We don't print the condition code in our spew lines. Doing this -// is awkward whilst maintaining a consistent field width. -namespace js { - namespace jit { - class Assembler; - } -} - -namespace JSC { - - typedef uint32_t ARMWord; - - namespace ARMRegisters { - typedef enum { - r0 = 0, - r1, - r2, - r3, - S0 = r3, - r4, - r5, - r6, - r7, - r8, - S1 = r8, - r9, - r10, - r11, - r12, - ip = r12, - r13, - sp = r13, - r14, - lr = r14, - r15, - pc = r15, - invalid_reg - } RegisterID; - - typedef enum { - d0, - d1, - d2, - d3, - SD0 = d3, - d4, - d5, - d6, - d7, - d8, - d9, - d10, - d11, - d12, - d13, - d14, - d15, - d16, - d17, - d18, - d19, - d20, - d21, - d22, - d23, - d24, - d25, - d26, - d27, - d28, - d29, - d30, - d31, - invalid_freg - } FPRegisterID; - - inline FPRegisterID floatShadow(FPRegisterID s) - { - return (FPRegisterID)(s*2); - } - inline FPRegisterID doubleShadow(FPRegisterID d) - { - return (FPRegisterID)(d / 2); - } - } // namespace ARMRegisters - class ARMAssembler : public GenericAssembler { - public: - - typedef ARMRegisters::RegisterID RegisterID; - typedef ARMRegisters::FPRegisterID FPRegisterID; - typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer; - typedef SegmentedVector Jumps; - - unsigned char *buffer() const { return m_buffer.buffer(); } - bool oom() const { return m_buffer.oom(); } - - // ARM conditional constants - typedef enum { - EQ = 0x00000000, // Zero - NE = 0x10000000, // Non-zero - CS = 0x20000000, - CC = 0x30000000, - MI = 0x40000000, - PL = 0x50000000, - VS = 0x60000000, - VC = 0x70000000, - HI = 0x80000000, - LS = 0x90000000, - GE = 0xa0000000, - LT = 0xb0000000, - GT = 0xc0000000, - LE = 0xd0000000, - AL = 0xe0000000 - } Condition; - - // ARM instruction constants - enum { - AND = (0x0 << 21), - EOR = (0x1 << 21), - SUB = (0x2 << 21), - RSB = (0x3 << 21), - ADD = (0x4 << 21), - ADC = (0x5 << 21), - SBC = (0x6 << 21), - RSC = (0x7 << 21), - TST = (0x8 << 21), - TEQ = (0x9 << 21), - CMP = (0xa << 21), - CMN = (0xb << 21), - ORR = (0xc << 21), - MOV = (0xd << 21), - BIC = (0xe << 21), - MVN = (0xf << 21), - MUL = 0x00000090, - MULL = 0x00c00090, - FCPYD = 0x0eb00b40, - FADDD = 0x0e300b00, - FNEGD = 0x0eb10b40, - FABSD = 0x0eb00bc0, - FDIVD = 0x0e800b00, - FSUBD = 0x0e300b40, - FMULD = 0x0e200b00, - FCMPD = 0x0eb40b40, - FSQRTD = 0x0eb10bc0, - DTR = 0x05000000, - LDRH = 0x00100090, - STRH = 0x00000090, - DTRH = 0x00000090, - STMDB = 0x09200000, - LDMIA = 0x08b00000, - B = 0x0a000000, - BL = 0x0b000000 -#if WTF_ARM_ARCH_VERSION >= 5 || defined(__ARM_ARCH_4T__) - ,BX = 0x012fff10 -#endif -#if WTF_ARM_ARCH_VERSION >= 5 - ,CLZ = 0x016f0f10, - BKPT = 0xe1200070, - BLX = 0x012fff30 -#endif -#if WTF_ARM_ARCH_VERSION >= 7 - ,MOVW = 0x03000000, - MOVT = 0x03400000 -#endif - }; - - enum { - OP2_IMM = (1 << 25), - OP2_IMMh = (1 << 22), - OP2_INV_IMM = (1 << 26), - SET_CC = (1 << 20), - OP2_OFSREG = (1 << 25), - DT_UP = (1 << 23), - DT_BYTE = (1 << 22), - DT_WB = (1 << 21), - // This flag is inlcuded in LDR and STR - DT_PRE = (1 << 24), - // This flag makes switches the instruction between {ld,st}r{,s}h and {ld,st}rsb - HDT_UH = (1 << 5), - // if this bit is on, we do a register offset, if it is off, we do an immediate offest. - HDT_IMM = (1 << 22), - // Differentiates half word load/store between signed and unsigned (also enables signed byte loads.) - HDT_S = (1 << 6), - DT_LOAD = (1 << 20) - }; - - // Masks of ARM instructions - enum { - BRANCH_MASK = 0x00ffffff, - NONARM = 0xf0000000, - SDT_MASK = 0x0c000000, - SDT_OFFSET_MASK = 0xfff - }; - - enum { - BOFFSET_MIN = -0x00800000, - BOFFSET_MAX = 0x007fffff, - SDT = 0x04000000 - }; - - enum { - padForAlign8 = (int)0x00, - padForAlign16 = (int)0x0000, - padForAlign32 = (int)0xe12fff7f // 'bkpt 0xffff' - }; - - typedef enum { - LSL = 0, - LSR = 1, - ASR = 2, - ROR = 3 - } Shift; - - static const ARMWord INVALID_IMM = 0xf0000000; - static const ARMWord InvalidBranchTarget = 0xffffffff; - static const int DefaultPrefetching = 2; - - class JmpSrc { - friend class ARMAssembler; - friend class js::jit::Assembler; - public: - JmpSrc() - : m_offset(-1) - { - } - int offset() {return m_offset;} - - bool isSet() const { - return m_offset != -1; - } - - private: - JmpSrc(int offset) - : m_offset(offset) - { - } - - int m_offset; - }; - - class JmpDst { - friend class ARMAssembler; - friend class js::jit::Assembler; - public: - JmpDst() - : m_offset(-1) - , m_used(false) - { - } - - bool isUsed() const { return m_used; } - void used() { m_used = true; } - bool isValid() const { return m_offset != -1; } - private: - JmpDst(int offset) - : m_offset(offset) - , m_used(false) - { - ASSERT(m_offset == offset); - } - - int m_offset : 31; - bool m_used : 1; - }; - - // Instruction formating - - void emitInst(ARMWord op, int rd, int rn, ARMWord op2) - { - ASSERT ( ((op2 & ~OP2_IMM) <= 0xfff) || (((op2 & ~OP2_IMMh) <= 0xfff)) ); - m_buffer.putInt(op | RN(rn) | RD(rd) | op2); - } - - // Work out the pre-shifted constant necessary to encode the specified - // logical shift left for op2 immediates. Only even shifts can be - // applied. - // - // Input validity is asserted in debug builds. - ARMWord getOp2RotLSL(int lsl) - { - ASSERT((lsl >= 0) && (lsl <= 24)); - ASSERT(!(lsl % 2)); - - return (-(lsl/2) & 0xf) << 8; - } - - void and_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("and", cc, rd, rn, op2); - emitInst(static_cast(cc) | AND, rd, rn, op2); - } - - void ands_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("ands", cc, rd, rn, op2); - emitInst(static_cast(cc) | AND | SET_CC, rd, rn, op2); - } - - void eor_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("eor", cc, rd, rn, op2); - emitInst(static_cast(cc) | EOR, rd, rn, op2); - } - - void eors_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("eors", cc, rd, rn, op2); - emitInst(static_cast(cc) | EOR | SET_CC, rd, rn, op2); - } - - void sub_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("sub", cc, rd, rn, op2); - emitInst(static_cast(cc) | SUB, rd, rn, op2); - } - - void subs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("subs", cc, rd, rn, op2); - emitInst(static_cast(cc) | SUB | SET_CC, rd, rn, op2); - } - - void rsb_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("rsb", cc, rd, rn, op2); - emitInst(static_cast(cc) | RSB, rd, rn, op2); - } - - void rsbs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("rsbs", cc, rd, rn, op2); - emitInst(static_cast(cc) | RSB | SET_CC, rd, rn, op2); - } - - void add_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("add", cc, rd, rn, op2); - emitInst(static_cast(cc) | ADD, rd, rn, op2); - } - - void adds_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("adds", cc, rd, rn, op2); - emitInst(static_cast(cc) | ADD | SET_CC, rd, rn, op2); - } - - void adc_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("adc", cc, rd, rn, op2); - emitInst(static_cast(cc) | ADC, rd, rn, op2); - } - - void adcs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("adcs", cc, rd, rn, op2); - emitInst(static_cast(cc) | ADC | SET_CC, rd, rn, op2); - } - - void sbc_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("sbc", cc, rd, rn, op2); - emitInst(static_cast(cc) | SBC, rd, rn, op2); - } - - void sbcs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("sbcs", cc, rd, rn, op2); - emitInst(static_cast(cc) | SBC | SET_CC, rd, rn, op2); - } - - void rsc_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("rsc", cc, rd, rn, op2); - emitInst(static_cast(cc) | RSC, rd, rn, op2); - } - - void rscs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("rscs", cc, rd, rn, op2); - emitInst(static_cast(cc) | RSC | SET_CC, rd, rn, op2); - } - - void tst_r(int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("tst", cc, rn, op2); - emitInst(static_cast(cc) | TST | SET_CC, 0, rn, op2); - } - - void teq_r(int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("teq", cc, rn, op2); - emitInst(static_cast(cc) | TEQ | SET_CC, 0, rn, op2); - } - - void cmp_r(int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("cmp", cc, rn, op2); - emitInst(static_cast(cc) | CMP | SET_CC, 0, rn, op2); - } - - void cmn_r(int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("cmn", cc, rn, op2); - emitInst(static_cast(cc) | CMN | SET_CC, 0, rn, op2); - } - - void orr_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("orr", cc, rd, rn, op2); - emitInst(static_cast(cc) | ORR, rd, rn, op2); - } - - void orrs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("orrs", cc, rd, rn, op2); - emitInst(static_cast(cc) | ORR | SET_CC, rd, rn, op2); - } - - void mov_r(int rd, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("mov", cc, rd, op2); - emitInst(static_cast(cc) | MOV, rd, ARMRegisters::r0, op2); - } - -#if WTF_ARM_ARCH_VERSION >= 7 - void movw_r(int rd, ARMWord op2, Condition cc = AL) - { - ASSERT((op2 | 0xf0fff) == 0xf0fff); - spew("%-15s %s, 0x%04x", "movw", nameGpReg(rd), (op2 & 0xfff) | ((op2 >> 4) & 0xf000)); - m_buffer.putInt(static_cast(cc) | MOVW | RD(rd) | op2); - } - - void movt_r(int rd, ARMWord op2, Condition cc = AL) - { - ASSERT((op2 | 0xf0fff) == 0xf0fff); - spew("%-15s %s, 0x%04x", "movt", nameGpReg(rd), (op2 & 0xfff) | ((op2 >> 4) & 0xf000)); - m_buffer.putInt(static_cast(cc) | MOVT | RD(rd) | op2); - } -#endif - - void movs_r(int rd, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("movs", cc, rd, op2); - emitInst(static_cast(cc) | MOV | SET_CC, rd, ARMRegisters::r0, op2); - } - - void bic_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("bic", cc, rd, rn, op2); - emitInst(static_cast(cc) | BIC, rd, rn, op2); - } - - void bics_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("bics", cc, rd, rn, op2); - emitInst(static_cast(cc) | BIC | SET_CC, rd, rn, op2); - } - - void mvn_r(int rd, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("mvn", cc, rd, op2); - emitInst(static_cast(cc) | MVN, rd, ARMRegisters::r0, op2); - } - - void mvns_r(int rd, ARMWord op2, Condition cc = AL) - { - spewInsWithOp2("mvns", cc, rd, op2); - emitInst(static_cast(cc) | MVN | SET_CC, rd, ARMRegisters::r0, op2); - } - - void mul_r(int rd, int rn, int rm, Condition cc = AL) - { - spewInsWithOp2("mul", cc, rd, rn, static_cast(rm)); - m_buffer.putInt(static_cast(cc) | MUL | RN(rd) | RS(rn) | RM(rm)); - } - - void muls_r(int rd, int rn, int rm, Condition cc = AL) - { - spewInsWithOp2("muls", cc, rd, rn, static_cast(rm)); - m_buffer.putInt(static_cast(cc) | MUL | SET_CC | RN(rd) | RS(rn) | RM(rm)); - } - - void mull_r(int rdhi, int rdlo, int rn, int rm, Condition cc = AL) - { - spew("%-15s %s, %s, %s, %s", "mull", nameGpReg(rdlo), nameGpReg(rdhi), nameGpReg(rn), nameGpReg(rm)); - m_buffer.putInt(static_cast(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm)); - } - - // pc relative loads (useful for loading from pools). - void ldr_imm(int rd, ARMWord imm, Condition cc = AL) - { -#if defined(JS_METHODJIT_SPEW) - char mnemonic[16]; - snprintf(mnemonic, 16, "ldr%s", nameCC(cc)); - spew("%-15s %s, =0x%x @ (%d) (reusable pool entry)", mnemonic, nameGpReg(rd), imm, static_cast(imm)); -#endif - m_buffer.putIntWithConstantInt(static_cast(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true); - } - - void ldr_un_imm(int rd, ARMWord imm, Condition cc = AL) - { -#if defined(JS_METHODJIT_SPEW) - char mnemonic[16]; - snprintf(mnemonic, 16, "ldr%s", nameCC(cc)); - spew("%-15s %s, =0x%x @ (%d)", mnemonic, nameGpReg(rd), imm, static_cast(imm)); -#endif - m_buffer.putIntWithConstantInt(static_cast(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm); - } - - void mem_imm_off(bool isLoad, bool isSigned, int size, bool posOffset, - int rd, int rb, ARMWord offset, Condition cc = AL) - { - ASSERT(size == 8 || size == 16 || size == 32); - char const * mnemonic_act = (isLoad) ? ("ld") : ("st"); - char const * mnemonic_sign = (isSigned) ? ("s") : (""); - - char const * mnemonic_size = NULL; - switch (size / 8) { - case 1: - mnemonic_size = "b"; - break; - case 2: - mnemonic_size = "h"; - break; - case 4: - mnemonic_size = ""; - break; - } - char const * off_sign = (posOffset) ? ("+") : ("-"); - spew("%sr%s%s %s, [%s, #%s%u]", - mnemonic_act, mnemonic_sign, mnemonic_size, - nameGpReg(rd), nameGpReg(rb), off_sign, offset); - if (size == 32 || (size == 8 && !isSigned)) { - /* All (the one) 32 bit ops and the unsigned 8 bit ops use the original encoding.*/ - emitInst(static_cast(cc) | DTR | - (isLoad ? DT_LOAD : 0) | - (size == 8 ? DT_BYTE : 0) | - (posOffset ? DT_UP : 0), rd, rb, offset); - } else { - /* All 16 bit ops and 8 bit unsigned use the newer encoding.*/ - emitInst(static_cast(cc) | DTRH | HDT_IMM | DT_PRE | - (isLoad ? DT_LOAD : 0) | - (size == 16 ? HDT_UH : 0) | - (isSigned ? HDT_S : 0) | - (posOffset ? DT_UP : 0), rd, rb, offset); - } - } - - void mem_reg_off(bool isLoad, bool isSigned, int size, bool posOffset, int rd, int rb, int rm, Condition cc = AL) - { - char const * mnemonic_act = (isLoad) ? ("ld") : ("st"); - char const * mnemonic_sign = (isSigned) ? ("s") : (""); - - char const * mnemonic_size = NULL; - switch (size / 8) { - case 1: - mnemonic_size = "b"; - break; - case 2: - mnemonic_size = "h"; - break; - case 4: - mnemonic_size = ""; - break; - } - char const * off_sign = (posOffset) ? ("+") : ("-"); - spew("%sr%s%s %s, [%s, #%s%s]", mnemonic_act, mnemonic_sign, mnemonic_size, - nameGpReg(rd), nameGpReg(rb), off_sign, nameGpReg(rm)); - if (size == 32 || (size == 8 && !isSigned)) { - /* All (the one) 32 bit ops and the signed 8 bit ops use the original encoding.*/ - emitInst(static_cast(cc) | DTR | - (isLoad ? DT_LOAD : 0) | - (size == 8 ? DT_BYTE : 0) | - (posOffset ? DT_UP : 0) | - OP2_OFSREG, rd, rb, rm); - } else { - /* All 16 bit ops and 8 bit unsigned use the newer encoding.*/ - emitInst(static_cast(cc) | DTRH | DT_PRE | - (isLoad ? DT_LOAD : 0) | - (size == 16 ? HDT_UH : 0) | - (isSigned ? HDT_S : 0) | - (posOffset ? DT_UP : 0), rd, rb, rm); - } - } - - // Data transfers like this: - // LDR rd, [rb, +offset] - // STR rd, [rb, +offset] - void dtr_u(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL) - { - char const * mnemonic = (isLoad) ? ("ldr") : ("str"); - spew("%-15s %s, [%s, #+%u]", - mnemonic, nameGpReg(rd), nameGpReg(rb), offset); - emitInst(static_cast(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, offset); - } - - // Data transfers like this: - // LDR rd, [rb, +rm] - // STR rd, [rb, +rm] - void dtr_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL) - { - char const * mnemonic = (isLoad) ? ("ldr") : ("str"); - spew("%-15s %s, [%s, +%s]", - mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); - emitInst(static_cast(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm); - } - - // Data transfers like this: - // LDR rd, [rb, -offset] - // STR rd, [rb, -offset] - void dtr_d(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL) - { - char const * mnemonic = (isLoad) ? ("ldr") : ("str"); - spew("%-15s %s, [%s, #-%u]", - mnemonic, nameGpReg(rd), nameGpReg(rb), offset); - emitInst(static_cast(cc) | DTR | (isLoad ? DT_LOAD : 0), rd, rb, offset); - } - - // Data transfers like this: - // LDR rd, [rb, -rm] - // STR rd, [rb, -rm] - void dtr_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL) - { - char const * mnemonic = (isLoad) ? ("ldr") : ("str"); - spew("%-15s %s, [%s, -%s]", - mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); - emitInst(static_cast(cc) | DTR | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm); - } - - // Data transfers like this: - // LDRB rd, [rb, +offset] - // STRB rd, [rb, +offset] - void dtrb_u(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL) - { - char const * mnemonic = (isLoad) ? ("ldrb") : ("strb"); - spew("%-15s %s, [%s, #+%u]", - mnemonic, nameGpReg(rd), nameGpReg(rb), offset); - emitInst(static_cast(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, offset); - } - - // Data transfers like this: - // LDRSB rd, [rb, +offset] - // STRSB rd, [rb, +offset] - void dtrsb_u(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL) - { - char const * mnemonic = (isLoad) ? ("ldrsb") : ("strb"); - spew("%-15s %s, [%s, #+%u]", - mnemonic, nameGpReg(rd), nameGpReg(rb), offset); - emitInst(static_cast(cc) | DTRH | HDT_S | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, offset); - } - - // Data transfers like this: - // LDRB rd, [rb, +rm] - // STRB rd, [rb, +rm] - void dtrb_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL) - { - char const * mnemonic = (isLoad) ? ("ldrb") : ("strb"); - spew("%-15s %s, [%s, +%s]", - mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); - emitInst(static_cast(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm); - } - - // Data transfers like this: - // LDRB rd, [rb, #-offset] - // STRB rd, [rb, #-offset] - void dtrb_d(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL) - { - char const * mnemonic = (isLoad) ? ("ldrb") : ("strb"); - spew("%-15s %s, [%s, #-%u]", - mnemonic, nameGpReg(rd), nameGpReg(rb), offset); - emitInst(static_cast(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0), rd, rb, offset); - } - - // Data transfers like this: - // LDRSB rd, [rb, #-offset] - // STRSB rd, [rb, #-offset] - void dtrsb_d(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL) - { - ASSERT(isLoad); /*can only do signed byte loads, not stores*/ - char const * mnemonic = (isLoad) ? ("ldrsb") : ("strb"); - spew("%-15s %s, [%s, #-%u]", - mnemonic, nameGpReg(rd), nameGpReg(rb), offset); - emitInst(static_cast(cc) | DTRH | HDT_S | (isLoad ? DT_LOAD : 0), rd, rb, offset); - } - - // Data transfers like this: - // LDRB rd, [rb, -rm] - // STRB rd, [rb, -rm] - void dtrb_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL) - { - char const * mnemonic = (isLoad) ? ("ldrb") : ("strb"); - spew("%-15s %s, [%s, -%s]", - mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); - emitInst(static_cast(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm); - } - - void ldrh_r(int rd, int rb, int rm, Condition cc = AL) - { - spew("%-15s %s, [%s, +%s]", - "ldrh", nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); - emitInst(static_cast(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, rm); - } - - void ldrh_d(int rd, int rb, ARMWord offset, Condition cc = AL) - { - spew("%-15s %s, [%s, #-%u]", - "ldrh", nameGpReg(rd), nameGpReg(rb), offset); - emitInst(static_cast(cc) | LDRH | HDT_UH | DT_PRE, rd, rb, offset); - } - - void ldrh_u(int rd, int rb, ARMWord offset, Condition cc = AL) - { - spew("%-15s %s, [%s, #+%u]", - "ldrh", nameGpReg(rd), nameGpReg(rb), offset); - emitInst(static_cast(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, offset); - } - - void ldrsh_d(int rd, int rb, ARMWord offset, Condition cc = AL) - { - spew("%-15s %s, [%s, #-%u]", - "ldrsh", nameGpReg(rd), nameGpReg(rb), offset); - emitInst(static_cast(cc) | LDRH | HDT_UH | HDT_S | DT_PRE, rd, rb, offset); - } - - void ldrsh_u(int rd, int rb, ARMWord offset, Condition cc = AL) - { - spew("%-15s %s, [%s, #+%u]", - "ldrsh", nameGpReg(rd), nameGpReg(rb), offset); - emitInst(static_cast(cc) | LDRH | HDT_UH | HDT_S | DT_UP | DT_PRE, rd, rb, offset); - } - - void strh_r(int rb, int rm, int rd, Condition cc = AL) - { - spew("%-15s %s, [%s, +%s]", - "strh", nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); - emitInst(static_cast(cc) | STRH | HDT_UH | DT_UP | DT_PRE, rd, rb, rm); - } - - void push_r(int reg, Condition cc = AL) - { - spew("%-15s {%s}", - "push", nameGpReg(reg)); - ASSERT(ARMWord(reg) <= 0xf); - m_buffer.putInt(cc | DTR | DT_WB | RN(ARMRegisters::sp) | RD(reg) | 0x4); - } - - void pop_r(int reg, Condition cc = AL) - { - spew("%-15s {%s}", - "pop", nameGpReg(reg)); - ASSERT(ARMWord(reg) <= 0xf); - m_buffer.putInt(cc | (DTR ^ DT_PRE) | DT_LOAD | DT_UP | RN(ARMRegisters::sp) | RD(reg) | 0x4); - } - - inline void poke_r(int reg, Condition cc = AL) - { - dtr_d(false, ARMRegisters::sp, 0, reg, cc); - } - - inline void peek_r(int reg, Condition cc = AL) - { - dtr_u(true, reg, ARMRegisters::sp, 0, cc); - } - - - -#if WTF_ARM_ARCH_VERSION >= 5 - void clz_r(int rd, int rm, Condition cc = AL) - { - spewInsWithOp2("clz", cc, rd, static_cast(rm)); - m_buffer.putInt(static_cast(cc) | CLZ | RD(rd) | RM(rm)); - } -#endif - - void bkpt(ARMWord value) - { -#if WTF_ARM_ARCH_VERSION >= 5 - spew("%-15s #0x%04x", "bkpt", value); - m_buffer.putInt(BKPT | ((value & 0xfff0) << 4) | (value & 0xf)); -#else - // Cannot access to Zero memory address - dtr_dr(true, ARMRegisters::S0, ARMRegisters::S0, ARMRegisters::S0); -#endif - } - - void bx(int rm, Condition cc = AL) - { -#if WTF_ARM_ARCH_VERSION >= 5 || defined(__ARM_ARCH_4T__) - spew("bx%-13s %s", nameCC(cc), nameGpReg(rm)); - emitInst(static_cast(cc) | BX, 0, 0, RM(rm)); -#else - mov_r(ARMRegisters::pc, RM(rm), cc); -#endif - } - - JmpSrc blx(int rm, Condition cc = AL) - { -#if WTF_CPU_ARM && WTF_ARM_ARCH_VERSION >= 5 - int s = m_buffer.uncheckedSize(); - spew("blx%-12s %s", nameCC(cc), nameGpReg(rm)); - emitInst(static_cast(cc) | BLX, 0, 0, RM(rm)); -#else - ASSERT(rm != 14); - ensureSpace(2 * sizeof(ARMWord), 0); - mov_r(ARMRegisters::lr, ARMRegisters::pc, cc); - int s = m_buffer.uncheckedSize(); - bx(rm, cc); -#endif - return JmpSrc(s); - } - - static ARMWord lsl(int reg, ARMWord value) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(value <= 0x1f); - return reg | (value << 7) | (LSL << 5); - } - - static ARMWord lsr(int reg, ARMWord value) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(value <= 0x1f); - return reg | (value << 7) | (LSR << 5); - } - - static ARMWord asr(int reg, ARMWord value) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(value <= 0x1f); - return reg | (value << 7) | (ASR << 5); - } - - static ARMWord lsl_r(int reg, int shiftReg) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(shiftReg <= ARMRegisters::pc); - return reg | (shiftReg << 8) | (LSL << 5) | 0x10; - } - - static ARMWord lsr_r(int reg, int shiftReg) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(shiftReg <= ARMRegisters::pc); - return reg | (shiftReg << 8) | (LSR << 5) | 0x10; - } - - static ARMWord asr_r(int reg, int shiftReg) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(shiftReg <= ARMRegisters::pc); - return reg | (shiftReg << 8) | (ASR << 5) | 0x10; - } - - // General helpers - - void forceFlushConstantPool() - { - m_buffer.flushWithoutBarrier(true); - } - - size_t size() const - { - return m_buffer.uncheckedSize(); - } - - size_t allocSize() const - { - return m_buffer.allocSize(); - } - - void ensureSpace(int insnSpace, int constSpace) - { - m_buffer.ensureSpace(insnSpace, constSpace); - } - - void ensureSpace(int space) - { - m_buffer.ensureSpace(space); - } - - int sizeOfConstantPool() - { - return m_buffer.sizeOfConstantPool(); - } - - int flushCount() - { - return m_buffer.flushCount(); - } - - JmpDst label() - { - JmpDst label(m_buffer.size()); - spew("#label ((%d))", label.m_offset); - return label; - } - - JmpDst align(int alignment) - { - while (!m_buffer.isAligned(alignment)) - mov_r(ARMRegisters::r0, ARMRegisters::r0); - - return label(); - } - - JmpSrc loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0) - { - // The 'useConstantPool' flag really just indicates where we have - // to use the constant pool, for repatching. We might still use it, - // so ensure there's space for a pool constant irrespective of - // 'useConstantPool'. - ensureSpace(sizeof(ARMWord), sizeof(ARMWord)); - int s = m_buffer.uncheckedSize(); - ldr_un_imm(rd, InvalidBranchTarget, cc); - m_jumps.append(s | (useConstantPool & 0x1)); - return JmpSrc(s); - } - - JmpSrc jmp(Condition cc = AL, int useConstantPool = 0) - { - return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool); - } - - void* executableAllocAndCopy(ExecutableAllocator* allocator, ExecutablePool **poolp, CodeKind kind); - void executableCopy(void* buffer); - void fixUpOffsets(void* buffer); - - // Patching helpers - - static ARMWord* getLdrImmAddress(ARMWord* insn) - { -#if WTF_CPU_ARM && WTF_ARM_ARCH_VERSION >= 5 - // Check for call - if ((*insn & 0x0f7f0000) != 0x051f0000) { - // Must be BLX - ASSERT((*insn & 0x012fff30) == 0x012fff30); - insn--; - } -#endif - // Must be an ldr ..., [pc +/- imm] - ASSERT((*insn & 0x0f7f0000) == 0x051f0000); - - ARMWord addr = reinterpret_cast(insn) + DefaultPrefetching * sizeof(ARMWord); - if (*insn & DT_UP) - return reinterpret_cast(addr + (*insn & SDT_OFFSET_MASK)); - return reinterpret_cast(addr - (*insn & SDT_OFFSET_MASK)); - } - - static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool) - { - // Must be an ldr ..., [pc +/- imm] - ASSERT((*insn & 0x0f7f0000) == 0x051f0000); - - if (*insn & 0x1) - return reinterpret_cast(constPool + ((*insn & SDT_OFFSET_MASK) >> 1)); - return getLdrImmAddress(insn); - } - - static void patchPointerInternal(intptr_t from, void* to) - { - ARMWord* insn = reinterpret_cast(from); - ARMWord* addr = getLdrImmAddress(insn); - *addr = reinterpret_cast(to); - } - - static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value) - { - value = (value << 1) + 1; - ASSERT(!(value & ~0xfff)); - return (load & ~0xfff) | value; - } - - static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr); - - // Patch pointers - - static void linkPointer(void* code, JmpDst from, void* to) - { - staticSpew("##linkPointer ((%p + %#x)) points to ((%p))", - code, from.m_offset, to); - - patchPointerInternal(reinterpret_cast(code) + from.m_offset, to); - } - - static void repatchInt32(void* from, int32_t to) - { - staticSpew("##repatchInt32 ((%p)) holds ((%#x))", - from, to); - - patchPointerInternal(reinterpret_cast(from), reinterpret_cast(to)); - } - - static void repatchPointer(void* from, void* to) - { - staticSpew("##repatchPointer ((%p)) points to ((%p))", - from, to); - - patchPointerInternal(reinterpret_cast(from), to); - } - - static void repatchLoadPtrToLEA(void* from) - { - // On arm, this is a patch from LDR to ADD. It is restricted conversion, - // from special case to special case, altough enough for its purpose - ARMWord* insn = reinterpret_cast(from); - ASSERT((*insn & 0x0ff00f00) == 0x05900000); - - *insn = (*insn & 0xf00ff0ff) | 0x02800000; - ExecutableAllocator::cacheFlush(insn, sizeof(ARMWord)); - } - - static void repatchLEAToLoadPtr(void* from) - { - // Like repatchLoadPtrToLEA, this is specialized for our purpose. - ARMWord* insn = reinterpret_cast(from); - if ((*insn & 0x0ff00f00) == 0x05900000) - return; // Valid ldr instruction - ASSERT((*insn & 0x0ff00000) == 0x02800000); // Valid add instruction - ASSERT((*insn & 0x00000f00) == 0x00000000); // Simple-to-handle immediates (no rotate) - - *insn = (*insn & 0xf00ff0ff) | 0x05900000; - ExecutableAllocator::cacheFlush(insn, sizeof(ARMWord)); - } - - // Linkers - - void linkJump(JmpSrc from, JmpDst to) - { - ARMWord code = reinterpret_cast(m_buffer.data()); - ARMWord* insn = reinterpret_cast(code + from.m_offset); - ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress()); - - spew("##linkJump ((%#x)) jumps to ((%#x))", - from.m_offset, to.m_offset); - - *addr = to.m_offset; - } - - static void linkJump(void* code, JmpSrc from, void* to) - { - staticSpew("##linkJump ((%p + %#x)) jumps to ((%p))", - code, from.m_offset, to); - - patchPointerInternal(reinterpret_cast(code) + from.m_offset, to); - } - - static void relinkJump(void* from, void* to) - { - staticSpew("##relinkJump ((%p)) jumps to ((%p))", - from, to); - - patchPointerInternal(reinterpret_cast(from), to); - } - - static bool canRelinkJump(void* from, void* to) - { - return true; - } - - static void linkCall(void* code, JmpSrc from, void* to) - { - staticSpew("##linkCall ((%p + %#x)) jumps to ((%p))", - code, from.m_offset, to); - - patchPointerInternal(reinterpret_cast(code) + from.m_offset, to); - } - - static void relinkCall(void* from, void* to) - { - staticSpew("##relinkCall ((%p)) jumps to ((%p))", - from, to); - - patchPointerInternal(reinterpret_cast(from), to); - } - - // Address operations - - static void* getRelocatedAddress(void* code, JmpSrc jump) - { - return reinterpret_cast(reinterpret_cast(code) + jump.m_offset / sizeof(ARMWord)); - } - - static void* getRelocatedAddress(void* code, JmpDst label) - { - return reinterpret_cast(reinterpret_cast(code) + label.m_offset / sizeof(ARMWord)); - } - - // Address differences - - static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to) - { - return to.m_offset - from.m_offset; - } - - static int getDifferenceBetweenLabels(JmpDst from, JmpDst to) - { - return to.m_offset - from.m_offset; - } - - static unsigned getCallReturnOffset(JmpSrc call) - { - return call.m_offset + sizeof(ARMWord); - } - - // Handle immediates - - static ARMWord getOp2Byte(ARMWord imm) - { - ASSERT(imm <= 0xff); - return OP2_IMMh | (imm & 0x0f) | ((imm & 0xf0) << 4) ; - } - - static ARMWord getOp2(ARMWord imm); - - // Get an operand-2 field for immediate-shifted-registers in arithmetic - // instructions. - static ARMWord getOp2RegScale(RegisterID reg, ARMWord scale); - -#if WTF_ARM_ARCH_VERSION >= 7 - static ARMWord getImm16Op2(ARMWord imm) - { - if (imm <= 0xffff) - return (imm & 0xf000) << 4 | (imm & 0xfff); - return INVALID_IMM; - } -#endif - ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false); - void moveImm(ARMWord imm, int dest); - ARMWord encodeComplexImm(ARMWord imm, int dest); - - ARMWord getOffsetForHalfwordDataTransfer(ARMWord imm, int tmpReg) - { - // Encode immediate data in the instruction if it is possible - if (imm <= 0xff) - return getOp2Byte(imm); - // Otherwise, store the data in a temporary register - return encodeComplexImm(imm, tmpReg); - } - - // Memory load/store helpers - void dataTransferN(bool isLoad, bool isSigned, int size, RegisterID srcDst, RegisterID base, int32_t offset); - - void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset); - void dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool isSigned); - void baseIndexTransferN(bool isLoad, bool isSigned, int size, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset); - void baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset); - void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset); - void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset, RegisterID index, int32_t scale); - - void floatTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset); - /**/ - void baseIndexFloatTransfer(bool isLoad, bool isDouble, FPRegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset); - - // Constant pool hnadlers - - static ARMWord placeConstantPoolBarrier(int offset) - { - offset = (offset - sizeof(ARMWord)) >> 2; - ASSERT((offset <= BOFFSET_MAX && offset >= BOFFSET_MIN)); - return AL | B | (offset & BRANCH_MASK); - } - - // pretty-printing functions - static char const * nameGpReg(int reg) - { - ASSERT(reg <= 16); - ASSERT(reg >= 0); - static char const * const names[] = { - "r0", "r1", "r2", "r3", - "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", - "ip", "sp", "lr", "pc" - }; - return names[reg]; - } - - static char const * nameFpRegD(int reg) - { - ASSERT(reg <= 31); - ASSERT(reg >= 0); - static char const * const names[] = { - "d0", "d1", "d2", "d3", - "d4", "d5", "d6", "d7", - "d8", "d9", "d10", "d11", - "d12", "d13", "d14", "d15", - "d16", "d17", "d18", "d19", - "d20", "d21", "d22", "d23", - "d24", "d25", "d26", "d27", - "d28", "d29", "d30", "d31" - }; - return names[reg]; - } - static char const * nameFpRegS(int reg) - { - ASSERT(reg <= 31); - ASSERT(reg >= 0); - static char const * const names[] = { - "s0", "s1", "s2", "s3", - "s4", "s5", "s6", "s7", - "s8", "s9", "s10", "s11", - "s12", "s13", "s14", "s15", - "s16", "s17", "s18", "s19", - "s20", "s21", "s22", "s23", - "s24", "s25", "s26", "s27", - "s28", "s29", "s30", "s31" - }; - return names[reg]; - } - - static char const * nameCC(Condition cc) - { - ASSERT(cc <= AL); - ASSERT((cc & 0x0fffffff) == 0); - - uint32_t ccIndex = cc >> 28; - static char const * const names[] = { - "eq", "ne", - "cs", "cc", - "mi", "pl", - "vs", "vc", - "hi", "ls", - "ge", "lt", - "gt", "le", - " " // AL is the default, so don't show it. - }; - return names[ccIndex]; - } - - private: - // Decodes operand 2 immediate values (for debug output and assertions). - inline uint32_t decOp2Imm(uint32_t op2) - { - ASSERT((op2 & ~0xfff) == 0); - - uint32_t imm8 = op2 & 0xff; - uint32_t rot = ((op2 >> 7) & 0x1e); - - // 'rot' is a right-rotate count. - - uint32_t imm = (imm8 >> rot); - if (rot > 0) { - imm |= (imm8 << (32-rot)); - } - - return imm; - } - - // Format the operand 2 argument for debug spew. The operand can be - // either an immediate or a register specifier. - void fmtOp2(char * out, ARMWord op2) - { - static char const * const shifts[4] = {"LSL", "LSR", "ASR", "ROR"}; - - if ((op2 & OP2_IMM) || (op2 & OP2_IMMh)) { - // Immediate values. - - uint32_t imm = decOp2Imm(op2 & ~(OP2_IMM | OP2_IMMh)); - sprintf(out, "#0x%x @ (%d)", imm, static_cast(imm)); - } else { - // Register values. - - char const * rm = nameGpReg(op2 & 0xf); - Shift type = static_cast((op2 >> 5) & 0x3); - - // Bit 4 specifies barrel-shifter parameters in operand 2. - if (op2 & (1<<4)) { - // Register-shifted register. - // Example: "r0, LSL r6" - char const * rs = nameGpReg((op2 >> 8) & 0xf); - sprintf(out, "%s, %s %s", rm, shifts[type], rs); - } else { - // Immediate-shifted register. - // Example: "r0, ASR #31" - uint32_t imm = (op2 >> 7) & 0x1f; - - // Deal with special encodings. - if ((type == LSL) && (imm == 0)) { - // "LSL #0" doesn't shift at all (and is the default). - sprintf(out, "%s", rm); - return; - } - - if ((type == ROR) && (imm == 0)) { - // "ROR #0" is a special case ("RRX"). - sprintf(out, "%s, RRX", rm); - return; - } - - if (((type == LSR) || (type == ASR)) && (imm == 0)) { - // Both LSR and ASR have a range of 1-32, with 32 - // encoded as 0. - imm = 32; - } - - // Print the result. - - sprintf(out, "%s, %s #%u", rm, shifts[type], imm); - } - } - } - - void spewInsWithOp2(char const * ins, Condition cc, int rd, int rn, ARMWord op2) - { -#if defined(JS_METHODJIT_SPEW) - char mnemonic[16]; - snprintf(mnemonic, 16, "%s%s", ins, nameCC(cc)); - - char op2_fmt[48]; - fmtOp2(op2_fmt, op2); - - spew("%-15s %s, %s, %s", mnemonic, nameGpReg(rd), nameGpReg(rn), op2_fmt); -#endif - } - - void spewInsWithOp2(char const * ins, Condition cc, int r, ARMWord op2) - { -#if defined(JS_METHODJIT_SPEW) - char mnemonic[16]; - snprintf(mnemonic, 16, "%s%s", ins, nameCC(cc)); - - char op2_fmt[48]; - fmtOp2(op2_fmt, op2); - - spew("%-15s %s, %s", mnemonic, nameGpReg(r), op2_fmt); -#endif - } - - ARMWord RM(int reg) - { - ASSERT(reg <= ARMRegisters::pc); - return reg; - } - - ARMWord RS(int reg) - { - ASSERT(reg <= ARMRegisters::pc); - return reg << 8; - } - - ARMWord RD(int reg) - { - ASSERT(reg <= ARMRegisters::pc); - return reg << 12; - } - - ARMWord RN(int reg) - { - ASSERT(reg <= ARMRegisters::pc); - return reg << 16; - } - - ARMWord DD(int reg) - { - ASSERT(reg <= ARMRegisters::d31); - // Endoded as bits [22,15:12]. - return ((reg << 12) | (reg << 18)) & 0x0040f000; - } - - ARMWord DN(int reg) - { - ASSERT(reg <= ARMRegisters::d31); - // Endoded as bits [7,19:16]. - return ((reg << 16) | (reg << 3)) & 0x000f0080; - } - - ARMWord DM(int reg) - { - ASSERT(reg <= ARMRegisters::d31); - // Encoded as bits [5,3:0]. - return ((reg << 1) & 0x20) | (reg & 0xf); - } - - ARMWord SD(int reg) - { - ASSERT(reg <= ARMRegisters::d31); - // Endoded as bits [15:12,22]. - return ((reg << 11) | (reg << 22)) & 0x0040f000; - } - - ARMWord SM(int reg) - { - ASSERT(reg <= ARMRegisters::d31); - // Encoded as bits [5,3:0]. - return ((reg << 5) & 0x20) | ((reg >> 1) & 0xf); - } - ARMWord SN(int reg) - { - ASSERT(reg <= ARMRegisters::d31); - // Encoded as bits [19:16,7]. - return ((reg << 15) & 0xf0000) | ((reg & 1) << 7); - } - static ARMWord getConditionalField(ARMWord i) - { - return i & 0xf0000000; - } - - int genInt(int reg, ARMWord imm, bool positive); - - ARMBuffer m_buffer; - Jumps m_jumps; - public: - // VFP instruction constants - enum { - VFP_DATA = 0x0E000A00, - VFP_EXT = 0x0C000A00, - VFP_XFER = 0x0E000A08, - VFP_DXFER = 0x0C400A00, - - VFP_DBL = (1<<8), - - /*integer conversions*/ - VFP_ICVT = 0x00B80040, - VFP_FPCVT = 0x00B700C0, - - VFP_DTR = 0x01000000, - VFP_MOV = 0x00000010, - - FMSR = 0x0e000a10, - FMRS = 0x0e100a10, - FSITOD = 0x0eb80bc0, - FUITOD = 0x0eb80b40, - FTOSID = 0x0ebd0b40, - FTOSIZD = 0x0ebd0bc0, - FMSTAT = 0x0ef1fa10, - FDTR = 0x0d000b00 - - }; - enum RegType { - SIntReg32, - UIntReg32, - FloatReg32, - FloatReg64 - }; - - const char * nameType(RegType t) - { - const char * const name[4] = - {"S32", "U32", "F32", "F64"}; - return name[t]; - } - - const char * nameTypedReg(RegType t, int reg) - { - switch(t) { - case SIntReg32: - case UIntReg32: - return nameGpReg(reg); - case FloatReg32: - return nameFpRegS(reg); - case FloatReg64: - return nameFpRegD(reg); - } - return ""; - } - - bool isFloatType(RegType rt) - { - if (rt == FloatReg32 || rt == FloatReg64) - return true; - return false; - } - - bool isIntType(RegType rt) - { - if (rt == FloatReg32 || rt == FloatReg64) - return false; - return true; - } - - // ******************************************************************** - // * VFP Code: - //********************************************************************* - /* this is horrible. There needs to be some sane way of distinguishing D from S from R*/ - void emitVFPInst(ARMWord op, ARMWord rd, ARMWord rn, ARMWord op2) - { - m_buffer.putInt(op | rn | rd | op2); - } - - // NOTE: offset is the actual value that is going to be encoded. It is the offset in words, NOT in bytes. - void fmem_imm_off(bool isLoad, bool isDouble, bool isUp, int dest, int rn, ARMWord offset, Condition cc = AL) - { - char const * ins = isLoad ? "vldr.f" : "vstr.f"; - spew("%s%d %s, [%s, #%s%u]", - ins, (isDouble ? 64 : 32), (isDouble ? nameFpRegD(dest) : nameFpRegS(dest)), - nameGpReg(rn), (isUp ? "+" : "-"), offset); - ASSERT(offset <= 0xff); - emitVFPInst(static_cast(cc) | - VFP_EXT | VFP_DTR | - (isDouble ? VFP_DBL : 0) | - (isUp ? DT_UP : 0) | - (isLoad ? DT_LOAD : 0), isDouble ? DD(dest) : SD(dest), RN(rn), offset); - - } - - // WARNING: even for an int -> float conversion, all registers used - // are VFP registers. - void vcvt(RegType srcType, RegType dstType, int src, int dest, Condition cc = AL) - { - ASSERT(srcType != dstType); - ASSERT(isFloatType(srcType) || isFloatType(dstType)); - - spew("vcvt.%s.%-15s, %s,%s", - nameType(dstType), nameType(srcType), - nameTypedReg(dstType,dest), nameTypedReg(srcType,src)); - - if (isFloatType(srcType) && isFloatType (dstType)) { - // doing a float -> float conversion - bool dblToFloat = srcType == FloatReg64; - emitVFPInst(static_cast(cc) | VFP_DATA | VFP_FPCVT | - (dblToFloat ? VFP_DBL : 0), - dblToFloat ? SD(dest) : DD(dest), - dblToFloat ? DM(src) : SM(src), 0); - } else { - MOZ_ASSUME_UNREACHABLE("Other conversions did not seem useful on 2011/08/04"); - } - } - - // does r2:r1 -> dn, dn -> r2:r1, r2:r1 -> s2:s1, etc. - void vmov64 (bool fromFP, bool isDbl, int r1, int r2, int rFP, Condition cc = AL) - { - if (fromFP) { - spew("%-15s %s, %s, %s", "vmov", - nameGpReg(r1), nameGpReg(r2), nameFpRegD(rFP)); - } else { - spew("%-15s %s, %s, %s", "vmov", - nameFpRegD(rFP), nameGpReg(r1), nameGpReg(r2)); - } - emitVFPInst(static_cast(cc) | VFP_DXFER | VFP_MOV | - (fromFP ? DT_LOAD : 0) | - (isDbl ? VFP_DBL : 0), RD(r1), RN(r2), isDbl ? DM(rFP) : SM(rFP)); - } - - void fcpyd_r(int dd, int dm, Condition cc = AL) - { - spew("%-15s %s, %s", "vmov.f64", - nameFpRegD(dd), nameFpRegD(dm)); - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FCPYD, DD(dd), DM(dm), 0); - } - - void faddd_r(int dd, int dn, int dm, Condition cc = AL) - { - spew("%-15s %s, %s, %s", "vadd.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm)); - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FADDD, DD(dd), DN(dn), DM(dm)); - } - - void fnegd_r(int dd, int dm, Condition cc = AL) - { - spew("%-15s %s, %s", "fnegd", nameFpRegD(dd), nameFpRegD(dm)); - m_buffer.putInt(static_cast(cc) | FNEGD | DD(dd) | DM(dm)); - } - - void fdivd_r(int dd, int dn, int dm, Condition cc = AL) - { - spew("%-15s %s, %s, %s", "vdiv.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm)); - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FDIVD, DD(dd), DN(dn), DM(dm)); - } - - void fsubd_r(int dd, int dn, int dm, Condition cc = AL) - { - spew("%-15s %s, %s, %s", "vsub.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm)); - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FSUBD, DD(dd), DN(dn), DM(dm)); - } - - void fabsd_r(int dd, int dm, Condition cc = AL) - { - spew("%-15s %s, %s", "fabsd", nameFpRegD(dd), nameFpRegD(dm)); - m_buffer.putInt(static_cast(cc) | FABSD | DD(dd) | DM(dm)); - } - - void fmuld_r(int dd, int dn, int dm, Condition cc = AL) - { - spew("%-15s %s, %s, %s", "vmul.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm)); - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FMULD, DD(dd), DN(dn), DM(dm)); - } - - void fcmpd_r(int dd, int dm, Condition cc = AL) - { - spew("%-15s %s, %s", "vcmp.f64", nameFpRegD(dd), nameFpRegD(dm)); - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FCMPD, DD(dd), 0, DM(dm)); - } - - void fsqrtd_r(int dd, int dm, Condition cc = AL) - { - spew("%-15s %s, %s", "vsqrt.f64", nameFpRegD(dd), nameFpRegD(dm)); - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FSQRTD, DD(dd), 0, DM(dm)); - } - - void fmsr_r(int dd, int rn, Condition cc = AL) - { - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FMSR, RD(rn), SN(dd), 0); - } - - void fmrs_r(int rd, int dn, Condition cc = AL) - { - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FMRS, RD(rd), SN(dn), 0); - } - - // dear god :( - // integer registers ar encoded the same as single registers - void fsitod_r(int dd, int dm, Condition cc = AL) - { - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FSITOD, DD(dd), 0, SM(dm)); - } - - void fuitod_r(int dd, int dm, Condition cc = AL) - { - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - emitVFPInst(static_cast(cc) | FUITOD, DD(dd), 0, SM(dm)); - } - - void ftosid_r(int fd, int dm, Condition cc = AL) - { - // TODO: I don't actually know what the encoding is i'm guessing SD and DM. - emitVFPInst(static_cast(cc) | FTOSID, SD(fd), 0, DM(dm)); - } - - void ftosizd_r(int fd, int dm, Condition cc = AL) - { - // TODO: I don't actually know what the encoding is i'm guessing SD and DM. - emitVFPInst(static_cast(cc) | FTOSIZD, SD(fd), 0, DM(dm)); - } - - void fmstat(Condition cc = AL) - { - // TODO: emitInst doesn't work for VFP instructions, though it - // seems to work for current usage. - m_buffer.putInt(static_cast(cc) | FMSTAT); - } - - - // things added to make IONMONKEY happy! - // what is the offset (from the beginning of the buffer) to the address - // of the next instruction - int nextOffset() { - return m_buffer.uncheckedSize(); - } - void putInst32(uint32_t data) { - m_buffer.putInt(data); - } - uint32_t *editSrc(JmpSrc src) { - return (uint32_t*)(((char*)m_buffer.data()) + src.offset()); - } - }; // ARMAssembler - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) - -#endif /* assembler_assembler_ARMAssembler_h */ diff --git a/js/src/assembler/assembler/ARMv7Assembler.h b/js/src/assembler/assembler/ARMv7Assembler.h deleted file mode 100644 index 180dce0d152..00000000000 --- a/js/src/assembler/assembler/ARMv7Assembler.h +++ /dev/null @@ -1,1931 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2009 Apple Inc. All rights reserved. - * Copyright (C) 2010 University of Szeged - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef assembler_assembler_ARMv7Assembler_h -#define assembler_assembler_ARMv7Assembler_h - -#include "assembler/wtf/Platform.h" - -#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) - -#include "assembler/assembler/AssemblerBuffer.h" -#include "assembler/wtf/Assertions.h" -#include - -namespace JSC { - -namespace ARMRegisters { - typedef enum { - r0, - r1, - r2, - r3, - r4, - r5, - r6, - r7, wr = r7, // thumb work register - r8, - r9, sb = r9, // static base - r10, sl = r10, // stack limit - r11, fp = r11, // frame pointer - r12, ip = r12, - r13, sp = r13, - r14, lr = r14, - r15, pc = r15, - } RegisterID; - - // s0 == d0 == q0 - // s4 == d2 == q1 - // etc - typedef enum { - s0 = 0, - s1 = 1, - s2 = 2, - s3 = 3, - s4 = 4, - s5 = 5, - s6 = 6, - s7 = 7, - s8 = 8, - s9 = 9, - s10 = 10, - s11 = 11, - s12 = 12, - s13 = 13, - s14 = 14, - s15 = 15, - s16 = 16, - s17 = 17, - s18 = 18, - s19 = 19, - s20 = 20, - s21 = 21, - s22 = 22, - s23 = 23, - s24 = 24, - s25 = 25, - s26 = 26, - s27 = 27, - s28 = 28, - s29 = 29, - s30 = 30, - s31 = 31, - d0 = 0 << 1, - d1 = 1 << 1, - d2 = 2 << 1, - d3 = 3 << 1, - d4 = 4 << 1, - d5 = 5 << 1, - d6 = 6 << 1, - d7 = 7 << 1, - d8 = 8 << 1, - d9 = 9 << 1, - d10 = 10 << 1, - d11 = 11 << 1, - d12 = 12 << 1, - d13 = 13 << 1, - d14 = 14 << 1, - d15 = 15 << 1, - d16 = 16 << 1, - d17 = 17 << 1, - d18 = 18 << 1, - d19 = 19 << 1, - d20 = 20 << 1, - d21 = 21 << 1, - d22 = 22 << 1, - d23 = 23 << 1, - d24 = 24 << 1, - d25 = 25 << 1, - d26 = 26 << 1, - d27 = 27 << 1, - d28 = 28 << 1, - d29 = 29 << 1, - d30 = 30 << 1, - d31 = 31 << 1, - q0 = 0 << 2, - q1 = 1 << 2, - q2 = 2 << 2, - q3 = 3 << 2, - q4 = 4 << 2, - q5 = 5 << 2, - q6 = 6 << 2, - q7 = 7 << 2, - q8 = 8 << 2, - q9 = 9 << 2, - q10 = 10 << 2, - q11 = 11 << 2, - q12 = 12 << 2, - q13 = 13 << 2, - q14 = 14 << 2, - q15 = 15 << 2, - q16 = 16 << 2, - q17 = 17 << 2, - q18 = 18 << 2, - q19 = 19 << 2, - q20 = 20 << 2, - q21 = 21 << 2, - q22 = 22 << 2, - q23 = 23 << 2, - q24 = 24 << 2, - q25 = 25 << 2, - q26 = 26 << 2, - q27 = 27 << 2, - q28 = 28 << 2, - q29 = 29 << 2, - q30 = 30 << 2, - q31 = 31 << 2, - } FPRegisterID; -} - -class ARMv7Assembler; -class ARMThumbImmediate { - friend class ARMv7Assembler; - - typedef uint8_t ThumbImmediateType; - static const ThumbImmediateType TypeInvalid = 0; - static const ThumbImmediateType TypeEncoded = 1; - static const ThumbImmediateType TypeUInt16 = 2; - - typedef union { - int16_t asInt; - struct { - unsigned imm8 : 8; - unsigned imm3 : 3; - unsigned i : 1; - unsigned imm4 : 4; - }; - // If this is an encoded immediate, then it may describe a shift, or a pattern. - struct { - unsigned shiftValue7 : 7; - unsigned shiftAmount : 5; - }; - struct { - unsigned immediate : 8; - unsigned pattern : 4; - }; - } ThumbImmediateValue; - - // byte0 contains least significant bit; not using an array to make client code endian agnostic. - typedef union { - int32_t asInt; - struct { - uint8_t byte0; - uint8_t byte1; - uint8_t byte2; - uint8_t byte3; - }; - } PatternBytes; - - ALWAYS_INLINE static void countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N) - { - if (value & ~((1 << N) - 1)) /* check for any of the top N bits (of 2N bits) are set */ - value >>= N; /* if any were set, lose the bottom N */ - else /* if none of the top N bits are set, */ - zeros += N; /* then we have identified N leading zeros */ - } - - static int32_t countLeadingZeros(uint32_t value) - { - if (!value) - return 32; - - int32_t zeros = 0; - countLeadingZerosPartial(value, zeros, 16); - countLeadingZerosPartial(value, zeros, 8); - countLeadingZerosPartial(value, zeros, 4); - countLeadingZerosPartial(value, zeros, 2); - countLeadingZerosPartial(value, zeros, 1); - return zeros; - } - - ARMThumbImmediate() - : m_type(TypeInvalid) - { - m_value.asInt = 0; - } - - ARMThumbImmediate(ThumbImmediateType type, ThumbImmediateValue value) - : m_type(type) - , m_value(value) - { - } - - ARMThumbImmediate(ThumbImmediateType type, uint16_t value) - : m_type(TypeUInt16) - { - // Make sure this constructor is only reached with type TypeUInt16; - // this extra parameter makes the code a little clearer by making it - // explicit at call sites which type is being constructed - ASSERT_UNUSED(type, type == TypeUInt16); - - m_value.asInt = value; - } - -public: - static ARMThumbImmediate makeEncodedImm(uint32_t value) - { - ThumbImmediateValue encoding; - encoding.asInt = 0; - - // okay, these are easy. - if (value < 256) { - encoding.immediate = value; - encoding.pattern = 0; - return ARMThumbImmediate(TypeEncoded, encoding); - } - - int32_t leadingZeros = countLeadingZeros(value); - // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case. - ASSERT(leadingZeros < 24); - - // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32, - // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for - // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z). - int32_t rightShiftAmount = 24 - leadingZeros; - if (value == ((value >> rightShiftAmount) << rightShiftAmount)) { - // Shift the value down to the low byte position. The assign to - // shiftValue7 drops the implicit top bit. - encoding.shiftValue7 = value >> rightShiftAmount; - // The endoded shift amount is the magnitude of a right rotate. - encoding.shiftAmount = 8 + leadingZeros; - return ARMThumbImmediate(TypeEncoded, encoding); - } - - PatternBytes bytes; - bytes.asInt = value; - - if ((bytes.byte0 == bytes.byte1) && (bytes.byte0 == bytes.byte2) && (bytes.byte0 == bytes.byte3)) { - encoding.immediate = bytes.byte0; - encoding.pattern = 3; - return ARMThumbImmediate(TypeEncoded, encoding); - } - - if ((bytes.byte0 == bytes.byte2) && !(bytes.byte1 | bytes.byte3)) { - encoding.immediate = bytes.byte0; - encoding.pattern = 1; - return ARMThumbImmediate(TypeEncoded, encoding); - } - - if ((bytes.byte1 == bytes.byte3) && !(bytes.byte0 | bytes.byte2)) { - encoding.immediate = bytes.byte0; - encoding.pattern = 2; - return ARMThumbImmediate(TypeEncoded, encoding); - } - - return ARMThumbImmediate(); - } - - static ARMThumbImmediate makeUInt12(int32_t value) - { - return (!(value & 0xfffff000)) - ? ARMThumbImmediate(TypeUInt16, (uint16_t)value) - : ARMThumbImmediate(); - } - - static ARMThumbImmediate makeUInt12OrEncodedImm(int32_t value) - { - // If this is not a 12-bit unsigned it, try making an encoded immediate. - return (!(value & 0xfffff000)) - ? ARMThumbImmediate(TypeUInt16, (uint16_t)value) - : makeEncodedImm(value); - } - - // The 'make' methods, above, return a !isValid() value if the argument - // cannot be represented as the requested type. This methods is called - // 'get' since the argument can always be represented. - static ARMThumbImmediate makeUInt16(uint16_t value) - { - return ARMThumbImmediate(TypeUInt16, value); - } - - bool isValid() - { - return m_type != TypeInvalid; - } - - // These methods rely on the format of encoded byte values. - bool isUInt3() { return !(m_value.asInt & 0xfff8); } - bool isUInt4() { return !(m_value.asInt & 0xfff0); } - bool isUInt5() { return !(m_value.asInt & 0xffe0); } - bool isUInt6() { return !(m_value.asInt & 0xffc0); } - bool isUInt7() { return !(m_value.asInt & 0xff80); } - bool isUInt8() { return !(m_value.asInt & 0xff00); } - bool isUInt9() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfe00); } - bool isUInt10() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfc00); } - bool isUInt12() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xf000); } - bool isUInt16() { return m_type == TypeUInt16; } - uint8_t getUInt3() { ASSERT(isUInt3()); return m_value.asInt; } - uint8_t getUInt4() { ASSERT(isUInt4()); return m_value.asInt; } - uint8_t getUInt5() { ASSERT(isUInt5()); return m_value.asInt; } - uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; } - uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; } - uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; } - uint8_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; } - uint8_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; } - uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; } - uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; } - - bool isEncodedImm() { return m_type == TypeEncoded; } - -private: - ThumbImmediateType m_type; - ThumbImmediateValue m_value; -}; - - -typedef enum { - SRType_LSL, - SRType_LSR, - SRType_ASR, - SRType_ROR, - - SRType_RRX = SRType_ROR -} ARMShiftType; - -class ARMv7Assembler; -class ShiftTypeAndAmount { - friend class ARMv7Assembler; - -public: - ShiftTypeAndAmount() - { - m_u.type = (ARMShiftType)0; - m_u.amount = 0; - } - - ShiftTypeAndAmount(ARMShiftType type, unsigned amount) - { - m_u.type = type; - m_u.amount = amount & 31; - } - - unsigned lo4() { return m_u.lo4; } - unsigned hi4() { return m_u.hi4; } - -private: - union { - struct { - unsigned lo4 : 4; - unsigned hi4 : 4; - }; - struct { - unsigned type : 2; - unsigned amount : 5; - }; - } m_u; -}; - - -/* -Some features of the Thumb instruction set are deprecated in ARMv7. Deprecated features affecting -instructions supported by ARMv7-M are as follows: -• use of the PC as or in a 16-bit ADD (SP plus register) instruction -• use of the SP as in a 16-bit ADD (SP plus register) instruction -• use of the SP as in a 16-bit CMP (register) instruction -• use of MOV (register) instructions in which is the SP or PC and is also the SP or PC. -• use of as the lowest-numbered register in the register list of a 16-bit STM instruction with base -register writeback -*/ - -class ARMv7Assembler { -public: - ~ARMv7Assembler() - { - ASSERT(m_jumpsToLink.isEmpty()); - } - - typedef ARMRegisters::RegisterID RegisterID; - typedef ARMRegisters::FPRegisterID FPRegisterID; - - // (HS, LO, HI, LS) -> (AE, B, A, BE) - // (VS, VC) -> (O, NO) - typedef enum { - ConditionEQ, - ConditionNE, - ConditionHS, - ConditionLO, - ConditionMI, - ConditionPL, - ConditionVS, - ConditionVC, - ConditionHI, - ConditionLS, - ConditionGE, - ConditionLT, - ConditionGT, - ConditionLE, - ConditionAL, - - ConditionCS = ConditionHS, - ConditionCC = ConditionLO, - } Condition; - - class JmpSrc { - friend class ARMv7Assembler; - friend class ARMInstructionFormatter; - public: - JmpSrc() - : m_offset(-1) - { - } - - bool isSet() const { - return m_offset != -1; - } - - private: - JmpSrc(int offset) - : m_offset(offset) - { - } - - int m_offset; - }; - - class JmpDst { - friend class ARMv7Assembler; - friend class ARMInstructionFormatter; - public: - JmpDst() - : m_offset(-1) - , m_used(false) - { - } - - bool isUsed() const { return m_used; } - void used() { m_used = true; } - private: - JmpDst(int offset) - : m_offset(offset) - , m_used(false) - { - ASSERT(m_offset == offset); - } - - int m_offset : 31; - int m_used : 1; - }; - -private: - - struct LinkRecord { - LinkRecord(intptr_t from, intptr_t to) - : from(from) - , to(to) - { - } - - intptr_t from; - intptr_t to; - }; - - // ARMv7, Appx-A.6.3 - bool BadReg(RegisterID reg) - { - return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc); - } - - bool isSingleRegister(FPRegisterID reg) - { - // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc). - return !(reg & ~31); - } - - bool isDoubleRegister(FPRegisterID reg) - { - // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc). - return !(reg & ~(31 << 1)); - } - - bool isQuadRegister(FPRegisterID reg) - { - return !(reg & ~(31 << 2)); - } - - uint32_t singleRegisterNum(FPRegisterID reg) - { - ASSERT(isSingleRegister(reg)); - return reg; - } - - uint32_t doubleRegisterNum(FPRegisterID reg) - { - ASSERT(isDoubleRegister(reg)); - return reg >> 1; - } - - uint32_t quadRegisterNum(FPRegisterID reg) - { - ASSERT(isQuadRegister(reg)); - return reg >> 2; - } - - uint32_t singleRegisterMask(FPRegisterID rd, int highBitsShift, int lowBitShift) - { - uint32_t rdNum = singleRegisterNum(rd); - uint32_t rdMask = (rdNum >> 1) << highBitsShift; - if (rdNum & 1) - rdMask |= 1 << lowBitShift; - return rdMask; - } - - uint32_t doubleRegisterMask(FPRegisterID rd, int highBitShift, int lowBitsShift) - { - uint32_t rdNum = doubleRegisterNum(rd); - uint32_t rdMask = (rdNum & 0xf) << lowBitsShift; - if (rdNum & 16) - rdMask |= 1 << highBitShift; - return rdMask; - } - - typedef enum { - OP_ADD_reg_T1 = 0x1800, - OP_ADD_S_reg_T1 = 0x1800, - OP_SUB_reg_T1 = 0x1A00, - OP_SUB_S_reg_T1 = 0x1A00, - OP_ADD_imm_T1 = 0x1C00, - OP_ADD_S_imm_T1 = 0x1C00, - OP_SUB_imm_T1 = 0x1E00, - OP_SUB_S_imm_T1 = 0x1E00, - OP_MOV_imm_T1 = 0x2000, - OP_CMP_imm_T1 = 0x2800, - OP_ADD_imm_T2 = 0x3000, - OP_ADD_S_imm_T2 = 0x3000, - OP_SUB_imm_T2 = 0x3800, - OP_SUB_S_imm_T2 = 0x3800, - OP_AND_reg_T1 = 0x4000, - OP_EOR_reg_T1 = 0x4040, - OP_TST_reg_T1 = 0x4200, - OP_CMP_reg_T1 = 0x4280, - OP_ORR_reg_T1 = 0x4300, - OP_MVN_reg_T1 = 0x43C0, - OP_ADD_reg_T2 = 0x4400, - OP_MOV_reg_T1 = 0x4600, - OP_BLX = 0x4700, - OP_BX = 0x4700, - OP_STR_reg_T1 = 0x5000, - OP_LDR_reg_T1 = 0x5800, - OP_LDRH_reg_T1 = 0x5A00, - OP_LDRB_reg_T1 = 0x5C00, - OP_STR_imm_T1 = 0x6000, - OP_LDR_imm_T1 = 0x6800, - OP_LDRB_imm_T1 = 0x7800, - OP_LDRH_imm_T1 = 0x8800, - OP_STR_imm_T2 = 0x9000, - OP_LDR_imm_T2 = 0x9800, - OP_ADD_SP_imm_T1 = 0xA800, - OP_ADD_SP_imm_T2 = 0xB000, - OP_SUB_SP_imm_T1 = 0xB080, - OP_BKPT = 0xBE00, - OP_IT = 0xBF00, - OP_NOP_T1 = 0xBF00, - } OpcodeID; - - typedef enum { - OP_AND_reg_T2 = 0xEA00, - OP_TST_reg_T2 = 0xEA10, - OP_ORR_reg_T2 = 0xEA40, - OP_ASR_imm_T1 = 0xEA4F, - OP_LSL_imm_T1 = 0xEA4F, - OP_LSR_imm_T1 = 0xEA4F, - OP_ROR_imm_T1 = 0xEA4F, - OP_MVN_reg_T2 = 0xEA6F, - OP_EOR_reg_T2 = 0xEA80, - OP_ADD_reg_T3 = 0xEB00, - OP_ADD_S_reg_T3 = 0xEB10, - OP_SUB_reg_T2 = 0xEBA0, - OP_SUB_S_reg_T2 = 0xEBB0, - OP_CMP_reg_T2 = 0xEBB0, - OP_B_T4a = 0xF000, - OP_AND_imm_T1 = 0xF000, - OP_TST_imm = 0xF010, - OP_ORR_imm_T1 = 0xF040, - OP_MOV_imm_T2 = 0xF040, - OP_MVN_imm = 0xF060, - OP_EOR_imm_T1 = 0xF080, - OP_ADD_imm_T3 = 0xF100, - OP_ADD_S_imm_T3 = 0xF110, - OP_CMN_imm = 0xF110, - OP_SUB_imm_T3 = 0xF1A0, - OP_SUB_S_imm_T3 = 0xF1B0, - OP_CMP_imm_T2 = 0xF1B0, - OP_ADD_imm_T4 = 0xF200, - OP_MOV_imm_T3 = 0xF240, - OP_SUB_imm_T4 = 0xF2A0, - OP_MOVT = 0xF2C0, - OP_NOP_T2a = 0xF3AF, - OP_LDRB_imm_T3 = 0xF810, - OP_LDRB_reg_T2 = 0xF810, - OP_LDRH_reg_T2 = 0xF830, - OP_LDRH_imm_T3 = 0xF830, - OP_STR_imm_T4 = 0xF840, - OP_STR_reg_T2 = 0xF840, - OP_LDR_imm_T4 = 0xF850, - OP_LDR_reg_T2 = 0xF850, - OP_LDRB_imm_T2 = 0xF890, - OP_LDRH_imm_T2 = 0xF8B0, - OP_STR_imm_T3 = 0xF8C0, - OP_LDR_imm_T3 = 0xF8D0, - OP_LSL_reg_T2 = 0xFA00, - OP_LSR_reg_T2 = 0xFA20, - OP_ASR_reg_T2 = 0xFA40, - OP_ROR_reg_T2 = 0xFA60, - OP_SMULL_T1 = 0xFB80, - } OpcodeID1; - - typedef enum { - OP_B_T4b = 0x9000, - OP_NOP_T2b = 0x8000, - } OpcodeID2; - - struct FourFours { - FourFours(unsigned f3, unsigned f2, unsigned f1, unsigned f0) - { - m_u.f0 = f0; - m_u.f1 = f1; - m_u.f2 = f2; - m_u.f3 = f3; - } - - union { - unsigned value; - struct { - unsigned f0 : 4; - unsigned f1 : 4; - unsigned f2 : 4; - unsigned f3 : 4; - }; - } m_u; - }; - - class ARMInstructionFormatter; - - // false means else! - bool ifThenElseConditionBit(Condition condition, bool isIf) - { - return isIf ? (condition & 1) : !(condition & 1); - } - uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if, bool inst4if) - { - int mask = (ifThenElseConditionBit(condition, inst2if) << 3) - | (ifThenElseConditionBit(condition, inst3if) << 2) - | (ifThenElseConditionBit(condition, inst4if) << 1) - | 1; - ASSERT((condition != ConditionAL) || (mask & (mask - 1))); - return (condition << 4) | mask; - } - uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if) - { - int mask = (ifThenElseConditionBit(condition, inst2if) << 3) - | (ifThenElseConditionBit(condition, inst3if) << 2) - | 2; - ASSERT((condition != ConditionAL) || (mask & (mask - 1))); - return (condition << 4) | mask; - } - uint8_t ifThenElse(Condition condition, bool inst2if) - { - int mask = (ifThenElseConditionBit(condition, inst2if) << 3) - | 4; - ASSERT((condition != ConditionAL) || (mask & (mask - 1))); - return (condition << 4) | mask; - } - - uint8_t ifThenElse(Condition condition) - { - int mask = 8; - ASSERT((condition != ConditionAL) || (mask & (mask - 1))); - return (condition << 4) | mask; - } - -public: - - void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isValid()); - - if (rn == ARMRegisters::sp) { - if (!(rd & 8) && imm.isUInt10()) { - m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, imm.getUInt10() >> 2); - return; - } else if ((rd == ARMRegisters::sp) && imm.isUInt9()) { - m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, imm.getUInt9() >> 2); - return; - } - } else if (!((rd | rn) & 8)) { - if (imm.isUInt3()) { - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); - return; - } else if ((rd == rn) && imm.isUInt8()) { - m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8()); - return; - } - } - - if (imm.isEncodedImm()) - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3, rn, rd, imm); - else { - ASSERT(imm.isUInt12()); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4, rn, rd, imm); - } - } - - void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - // NOTE: In an IT block, add doesn't modify the flags register. - void add(RegisterID rd, RegisterID rn, RegisterID rm) - { - if (rd == rn) - m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd); - else if (rd == rm) - m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rn, rd); - else if (!((rd | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd); - else - add(rd, rn, rm, ShiftTypeAndAmount()); - } - - // Not allowed in an IT (if then) block. - void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isEncodedImm()); - - if (!((rd | rn) & 8)) { - if (imm.isUInt3()) { - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); - return; - } else if ((rd == rn) && imm.isUInt8()) { - m_formatter.oneWordOp5Reg3Imm8(OP_ADD_S_imm_T2, rd, imm.getUInt8()); - return; - } - } - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3, rn, rd, imm); - } - - // Not allowed in an IT (if then) block? - void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - // Not allowed in an IT (if then) block. - void add_S(RegisterID rd, RegisterID rn, RegisterID rm) - { - if (!((rd | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_reg_T1, rm, rn, rd); - else - add_S(rd, rn, rm, ShiftTypeAndAmount()); - } - - void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(imm.isEncodedImm()); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm); - } - - void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm) - { - if ((rd == rn) && !((rd | rm) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd); - else if ((rd == rm) && !((rd | rn) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rn, rd); - else - ARM_and(rd, rn, rm, ShiftTypeAndAmount()); - } - - void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - ShiftTypeAndAmount shift(SRType_ASR, shiftAmount); - m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void asr(RegisterID rd, RegisterID rn, RegisterID rm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ASR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); - } - - // Only allowed in IT (if then) block if last instruction. - JmpSrc b() - { - m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b); - return JmpSrc(m_formatter.size()); - } - - // Only allowed in IT (if then) block if last instruction. - JmpSrc blx(RegisterID rm) - { - ASSERT(rm != ARMRegisters::pc); - m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8); - return JmpSrc(m_formatter.size()); - } - - // Only allowed in IT (if then) block if last instruction. - JmpSrc bx(RegisterID rm) - { - m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0); - return JmpSrc(m_formatter.size()); - } - - void bkpt(uint8_t imm=0) - { - m_formatter.oneWordOp8Imm8(OP_BKPT, imm); - } - - void cmn(RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isEncodedImm()); - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm); - } - - void cmp(RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isEncodedImm()); - - if (!(rn & 8) && imm.isUInt8()) - m_formatter.oneWordOp5Reg3Imm8(OP_CMP_imm_T1, rn, imm.getUInt8()); - else - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm); - } - - void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm)); - } - - void cmp(RegisterID rn, RegisterID rm) - { - if ((rn | rm) & 8) - cmp(rn, rm, ShiftTypeAndAmount()); - else - m_formatter.oneWordOp10Reg3Reg3(OP_CMP_reg_T1, rm, rn); - } - - // xor is not spelled with an 'e'. :-( - void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(imm.isEncodedImm()); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1, rn, rd, imm); - } - - // xor is not spelled with an 'e'. :-( - void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_EOR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - // xor is not spelled with an 'e'. :-( - void eor(RegisterID rd, RegisterID rn, RegisterID rm) - { - if ((rd == rn) && !((rd | rm) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rm, rd); - else if ((rd == rm) && !((rd | rn) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rn, rd); - else - eor(rd, rn, rm, ShiftTypeAndAmount()); - } - - void it(Condition cond) - { - m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond)); - } - - void it(Condition cond, bool inst2if) - { - m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if)); - } - - void it(Condition cond, bool inst2if, bool inst3if) - { - m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if)); - } - - void it(Condition cond, bool inst2if, bool inst3if, bool inst4if) - { - m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if)); - } - - // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. - void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rn != ARMRegisters::pc); // LDR (literal) - ASSERT(imm.isUInt12()); - - if (!((rt | rn) & 8) && imm.isUInt7()) - m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt); - else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10()) - m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, imm.getUInt10() >> 2); - else - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12()); - } - - // If index is set, this is a regular offset or a pre-indexed load; - // if index is not set then is is a post-index load. - // - // If wback is set rn is updated - this is a pre or post index load, - // if wback is not set this is a regular offset memory access. - // - // (-255 <= offset <= 255) - // _reg = REG[rn] - // _tmp = _reg + offset - // MEM[index ? _tmp : _reg] = REG[rt] - // if (wback) REG[rn] = _tmp - void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) - { - ASSERT(rt != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(index || wback); - ASSERT(!wback | (rt != rn)); - - bool add = true; - if (offset < 0) { - add = false; - offset = -offset; - } - ASSERT((offset & ~0xff) == 0); - - offset |= (wback << 8); - offset |= (add << 9); - offset |= (index << 10); - offset |= (1 << 11); - - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset); - } - - // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. - void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) - { - ASSERT(rn != ARMRegisters::pc); // LDR (literal) - ASSERT(!BadReg(rm)); - ASSERT(shift <= 3); - - if (!shift && !((rt | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1, rm, rn, rt); - else - m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm)); - } - - // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. - void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rn != ARMRegisters::pc); // LDR (literal) - ASSERT(imm.isUInt12()); - - if (!((rt | rn) & 8) && imm.isUInt6()) - m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt); - else - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12()); - } - - // If index is set, this is a regular offset or a pre-indexed load; - // if index is not set then is is a post-index load. - // - // If wback is set rn is updated - this is a pre or post index load, - // if wback is not set this is a regular offset memory access. - // - // (-255 <= offset <= 255) - // _reg = REG[rn] - // _tmp = _reg + offset - // MEM[index ? _tmp : _reg] = REG[rt] - // if (wback) REG[rn] = _tmp - void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) - { - ASSERT(rt != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(index || wback); - ASSERT(!wback | (rt != rn)); - - bool add = true; - if (offset < 0) { - add = false; - offset = -offset; - } - ASSERT((offset & ~0xff) == 0); - - offset |= (wback << 8); - offset |= (add << 9); - offset |= (index << 10); - offset |= (1 << 11); - - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset); - } - - void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) - { - ASSERT(!BadReg(rt)); // Memory hint - ASSERT(rn != ARMRegisters::pc); // LDRH (literal) - ASSERT(!BadReg(rm)); - ASSERT(shift <= 3); - - if (!shift && !((rt | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1, rm, rn, rt); - else - m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm)); - } - - void ldrb(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rn != ARMRegisters::pc); // LDR (literal) - ASSERT(imm.isUInt12()); - - if (!((rt | rn) & 8) && imm.isUInt5()) - m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRB_imm_T1, imm.getUInt5(), rn, rt); - else - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T2, rn, rt, imm.getUInt12()); - } - - void ldrb(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) - { - ASSERT(rt != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(index || wback); - ASSERT(!wback | (rt != rn)); - - bool add = true; - if (offset < 0) { - add = false; - offset = -offset; - } - - ASSERT(!(offset & ~0xff)); - - offset |= (wback << 8); - offset |= (add << 9); - offset |= (index << 10); - offset |= (1 << 11); - - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T3, rn, rt, offset); - } - - void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) - { - ASSERT(rn != ARMRegisters::pc); // LDR (literal) - ASSERT(!BadReg(rm)); - ASSERT(shift <= 3); - - if (!shift && !((rt | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRB_reg_T1, rm, rn, rt); - else - m_formatter.twoWordOp12Reg4FourFours(OP_LDRB_reg_T2, rn, FourFours(rt, 0, shift, rm)); - } - - void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - ShiftTypeAndAmount shift(SRType_LSL, shiftAmount); - m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void lsl(RegisterID rd, RegisterID rn, RegisterID rm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm)); - } - - void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - ShiftTypeAndAmount shift(SRType_LSR, shiftAmount); - m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void lsr(RegisterID rd, RegisterID rn, RegisterID rm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); - } - - void movT3(RegisterID rd, ARMThumbImmediate imm) - { - ASSERT(imm.isValid()); - ASSERT(!imm.isEncodedImm()); - ASSERT(!BadReg(rd)); - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm); - } - - void mov(RegisterID rd, ARMThumbImmediate imm) - { - ASSERT(imm.isValid()); - ASSERT(!BadReg(rd)); - - if ((rd < 8) && imm.isUInt8()) - m_formatter.oneWordOp5Reg3Imm8(OP_MOV_imm_T1, rd, imm.getUInt8()); - else if (imm.isEncodedImm()) - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2, 0xf, rd, imm); - else - movT3(rd, imm); - } - - void mov(RegisterID rd, RegisterID rm) - { - m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd); - } - - void movt(RegisterID rd, ARMThumbImmediate imm) - { - ASSERT(imm.isUInt16()); - ASSERT(!BadReg(rd)); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm); - } - - void mvn(RegisterID rd, ARMThumbImmediate imm) - { - ASSERT(imm.isEncodedImm()); - ASSERT(!BadReg(rd)); - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm); - } - - void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void mvn(RegisterID rd, RegisterID rm) - { - if (!((rd | rm) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd); - else - mvn(rd, rm, ShiftTypeAndAmount()); - } - - void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(imm.isEncodedImm()); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm); - } - - void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ORR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void orr(RegisterID rd, RegisterID rn, RegisterID rm) - { - if ((rd == rn) && !((rd | rm) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd); - else if ((rd == rm) && !((rd | rn) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd); - else - orr(rd, rn, rm, ShiftTypeAndAmount()); - } - - void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - ShiftTypeAndAmount shift(SRType_ROR, shiftAmount); - m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void ror(RegisterID rd, RegisterID rn, RegisterID rm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); - } - - void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm) - { - ASSERT(!BadReg(rdLo)); - ASSERT(!BadReg(rdHi)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - ASSERT(rdLo != rdHi); - m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm)); - } - - // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. - void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rt != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isUInt12()); - - if (!((rt | rn) & 8) && imm.isUInt7()) - m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt); - else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10()) - m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, imm.getUInt10() >> 2); - else - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12()); - } - - // If index is set, this is a regular offset or a pre-indexed store; - // if index is not set then is is a post-index store. - // - // If wback is set rn is updated - this is a pre or post index store, - // if wback is not set this is a regular offset memory access. - // - // (-255 <= offset <= 255) - // _reg = REG[rn] - // _tmp = _reg + offset - // MEM[index ? _tmp : _reg] = REG[rt] - // if (wback) REG[rn] = _tmp - void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) - { - ASSERT(rt != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(index || wback); - ASSERT(!wback | (rt != rn)); - - bool add = true; - if (offset < 0) { - add = false; - offset = -offset; - } - ASSERT((offset & ~0xff) == 0); - - offset |= (wback << 8); - offset |= (add << 9); - offset |= (index << 10); - offset |= (1 << 11); - - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset); - } - - // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. - void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) - { - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - ASSERT(shift <= 3); - - if (!shift && !((rt | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1, rm, rn, rt); - else - m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm)); - } - - void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isValid()); - - if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) { - m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2); - return; - } else if (!((rd | rn) & 8)) { - if (imm.isUInt3()) { - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); - return; - } else if ((rd == rn) && imm.isUInt8()) { - m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8()); - return; - } - } - - if (imm.isEncodedImm()) - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3, rn, rd, imm); - else { - ASSERT(imm.isUInt12()); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4, rn, rd, imm); - } - } - - void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - // NOTE: In an IT block, add doesn't modify the flags register. - void sub(RegisterID rd, RegisterID rn, RegisterID rm) - { - if (!((rd | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd); - else - sub(rd, rn, rm, ShiftTypeAndAmount()); - } - - // Not allowed in an IT (if then) block. - void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isValid()); - - if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) { - m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2); - return; - } else if (!((rd | rn) & 8)) { - if (imm.isUInt3()) { - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); - return; - } else if ((rd == rn) && imm.isUInt8()) { - m_formatter.oneWordOp5Reg3Imm8(OP_SUB_S_imm_T2, rd, imm.getUInt8()); - return; - } - } - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3, rn, rd, imm); - } - - // Not allowed in an IT (if then) block? - void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - // Not allowed in an IT (if then) block. - void sub_S(RegisterID rd, RegisterID rn, RegisterID rm) - { - if (!((rd | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_reg_T1, rm, rn, rd); - else - sub_S(rd, rn, rm, ShiftTypeAndAmount()); - } - - void tst(RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(!BadReg(rn)); - ASSERT(imm.isEncodedImm()); - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm); - } - - void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm)); - } - - void tst(RegisterID rn, RegisterID rm) - { - if ((rn | rm) & 8) - tst(rn, rm, ShiftTypeAndAmount()); - else - m_formatter.oneWordOp10Reg3Reg3(OP_TST_reg_T1, rm, rn); - } - - void vadd_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm) - { - m_formatter.vfpOp(0x0b00ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16)); - } - - void vcmp_F64(FPRegisterID rd, FPRegisterID rm) - { - m_formatter.vfpOp(0x0bc0eeb4 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rm, 21, 16)); - } - - void vcvt_F64_S32(FPRegisterID fd, FPRegisterID sm) - { - m_formatter.vfpOp(0x0bc0eeb8 | doubleRegisterMask(fd, 6, 28) | singleRegisterMask(sm, 16, 21)); - } - - void vcvt_S32_F64(FPRegisterID sd, FPRegisterID fm) - { - m_formatter.vfpOp(0x0bc0eebd | singleRegisterMask(sd, 28, 6) | doubleRegisterMask(fm, 21, 16)); - } - - void vldr(FPRegisterID rd, RegisterID rn, int32_t imm) - { - vmem(rd, rn, imm, true); - } - - void vmov(RegisterID rd, FPRegisterID sn) - { - m_formatter.vfpOp(0x0a10ee10 | (rd << 28) | singleRegisterMask(sn, 0, 23)); - } - - void vmov(FPRegisterID sn, RegisterID rd) - { - m_formatter.vfpOp(0x0a10ee00 | (rd << 28) | singleRegisterMask(sn, 0, 23)); - } - - // move FPSCR flags to APSR. - void vmrs_APSR_nzcv_FPSCR() - { - m_formatter.vfpOp(0xfa10eef1); - } - - void vmul_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm) - { - m_formatter.vfpOp(0x0b00ee20 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16)); - } - - void vstr(FPRegisterID rd, RegisterID rn, int32_t imm) - { - vmem(rd, rn, imm, false); - } - - void vsub_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm) - { - m_formatter.vfpOp(0x0b40ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16)); - } - - - JmpDst label() - { - return JmpDst(m_formatter.size()); - } - - JmpDst align(int alignment) - { - while (!m_formatter.isAligned(alignment)) - bkpt(); - - return label(); - } - - static void* getRelocatedAddress(void* code, JmpSrc jump) - { - ASSERT(jump.m_offset != -1); - - return reinterpret_cast(reinterpret_cast(code) + jump.m_offset); - } - - static void* getRelocatedAddress(void* code, JmpDst destination) - { - ASSERT(destination.m_offset != -1); - - return reinterpret_cast(reinterpret_cast(code) + destination.m_offset); - } - - static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst) - { - return dst.m_offset - src.m_offset; - } - - static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst) - { - return dst.m_offset - src.m_offset; - } - - static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst) - { - return dst.m_offset - src.m_offset; - } - - // Assembler admin methods: - - size_t size() const - { - return m_formatter.size(); - } - - void* executableAllocAndCopy(ExecutableAllocator* allocator, ExecutablePool** poolp, CodeKind kind) - { - void* copy = m_formatter.executableAllocAndCopy(allocator, poolp, kind); - - unsigned jumpCount = m_jumpsToLink.size(); - for (unsigned i = 0; i < jumpCount; ++i) { - uint16_t* location = reinterpret_cast(reinterpret_cast(copy) + m_jumpsToLink[i].from); - uint16_t* target = reinterpret_cast(reinterpret_cast(copy) + m_jumpsToLink[i].to); - linkJumpAbsolute(location, target); - } - m_jumpsToLink.clear(); - - ASSERT(copy); - return copy; - } - - static unsigned getCallReturnOffset(JmpSrc call) - { - ASSERT(call.m_offset >= 0); - return call.m_offset; - } - - // Linking & patching: - // - // 'link' and 'patch' methods are for use on unprotected code - such as the code - // within the AssemblerBuffer, and code being patched by the patch buffer. Once - // code has been finalized it is (platform support permitting) within a non- - // writable region of memory; to modify the code in an execute-only execuable - // pool the 'repatch' and 'relink' methods should be used. - - void linkJump(JmpSrc from, JmpDst to) - { - ASSERT(to.m_offset != -1); - ASSERT(from.m_offset != -1); - m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset)); - } - - static void linkJump(void* code, JmpSrc from, void* to) - { - ASSERT(from.m_offset != -1); - - uint16_t* location = reinterpret_cast(reinterpret_cast(code) + from.m_offset); - linkJumpAbsolute(location, to); - } - - // bah, this mathod should really be static, since it is used by the LinkBuffer. - // return a bool saying whether the link was successful? - static void linkCall(void* code, JmpSrc from, void* to) - { - ASSERT(!(reinterpret_cast(code) & 1)); - ASSERT(from.m_offset != -1); - ASSERT(reinterpret_cast(to) & 1); - - setPointer(reinterpret_cast(reinterpret_cast(code) + from.m_offset) - 1, to); - } - - static void linkPointer(void* code, JmpDst where, void* value) - { - setPointer(reinterpret_cast(code) + where.m_offset, value); - } - - static void relinkJump(void* from, void* to) - { - ASSERT(!(reinterpret_cast(from) & 1)); - ASSERT(!(reinterpret_cast(to) & 1)); - - linkJumpAbsolute(reinterpret_cast(from), to); - - ExecutableAllocator::cacheFlush(reinterpret_cast(from) - 5, 5 * sizeof(uint16_t)); - } - - static bool canRelinkJump(void* from, void* to) - { - return true; - } - - static void relinkCall(void* from, void* to) - { - ASSERT(!(reinterpret_cast(from) & 1)); - ASSERT(reinterpret_cast(to) & 1); - - setPointer(reinterpret_cast(from) - 1, to); - - ExecutableAllocator::cacheFlush(reinterpret_cast(from) - 5, 4 * sizeof(uint16_t)); - } - - static void repatchInt32(void* where, int32_t value) - { - ASSERT(!(reinterpret_cast(where) & 1)); - - setInt32(where, value); - - ExecutableAllocator::cacheFlush(reinterpret_cast(where) - 4, 4 * sizeof(uint16_t)); - } - - static void repatchPointer(void* where, void* value) - { - ASSERT(!(reinterpret_cast(where) & 1)); - - setPointer(where, value); - - ExecutableAllocator::cacheFlush(reinterpret_cast(where) - 4, 4 * sizeof(uint16_t)); - } - - static void repatchLoadPtrToLEA(void* where) - { - ASSERT(!(reinterpret_cast(where) & 1)); - - uint16_t* loadOp = reinterpret_cast(where) + 4; - ASSERT((*loadOp & 0xfff0) == OP_LDR_reg_T2); - - *loadOp = OP_ADD_reg_T3 | (*loadOp & 0xf); - ExecutableAllocator::cacheFlush(loadOp, sizeof(uint16_t)); - } - - static void repatchLEAToLoadPtr(void* where) - { - ASSERT(!(reinterpret_cast(where) & 1)); - - uint16_t* loadOp = reinterpret_cast(where) + 4; - if ((*loadOp & 0xfff0) == OP_LDR_reg_T2) - return; - - ASSERT((*loadOp & 0xfff0) == OP_ADD_reg_T3); - - *loadOp = OP_LDR_reg_T2 | (*loadOp & 0xf); - ExecutableAllocator::cacheFlush(loadOp, sizeof(uint16_t)); - } - -private: - - // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. - // (i.e. +/-(0..255) 32-bit words) - void vmem(FPRegisterID rd, RegisterID rn, int32_t imm, bool isLoad) - { - bool up; - uint32_t offset; - if (imm < 0) { - offset = -imm; - up = false; - } else { - offset = imm; - up = true; - } - - // offset is effectively leftshifted by 2 already (the bottom two bits are zero, and not - // reperesented in the instruction. Left shift by 14, to mov it into position 0x00AA0000. - ASSERT((offset & ~(0xff << 2)) == 0); - offset <<= 14; - - m_formatter.vfpOp(0x0b00ed00 | offset | (up << 7) | (isLoad << 4) | doubleRegisterMask(rd, 6, 28) | rn); - } - - static void setInt32(void* code, uint32_t value) - { - uint16_t* location = reinterpret_cast(code); - ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2)); - - ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast(value)); - ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast(value >> 16)); - location[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); - location[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-3] >> 8) & 0xf, lo16); - location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); - location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16); - - ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t)); - } - - static void setPointer(void* code, void* value) - { - setInt32(code, reinterpret_cast(value)); - } - - static bool isB(void* address) - { - uint16_t* instruction = static_cast(address); - return ((instruction[0] & 0xf800) == OP_B_T4a) && ((instruction[1] & 0xd000) == OP_B_T4b); - } - - static bool isBX(void* address) - { - uint16_t* instruction = static_cast(address); - return (instruction[0] & 0xff87) == OP_BX; - } - - static bool isMOV_imm_T3(void* address) - { - uint16_t* instruction = static_cast(address); - return ((instruction[0] & 0xFBF0) == OP_MOV_imm_T3) && ((instruction[1] & 0x8000) == 0); - } - - static bool isMOVT(void* address) - { - uint16_t* instruction = static_cast(address); - return ((instruction[0] & 0xFBF0) == OP_MOVT) && ((instruction[1] & 0x8000) == 0); - } - - static bool isNOP_T1(void* address) - { - uint16_t* instruction = static_cast(address); - return instruction[0] == OP_NOP_T1; - } - - static bool isNOP_T2(void* address) - { - uint16_t* instruction = static_cast(address); - return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b); - } - - static void linkJumpAbsolute(uint16_t* instruction, void* target) - { - // FIMXE: this should be up in the MacroAssembler layer. :-( - const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip; - - ASSERT(!(reinterpret_cast(instruction) & 1)); - ASSERT(!(reinterpret_cast(target) & 1)); - - ASSERT( (isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1)) - || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2)) ); - - intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); - - // From Cortex-A8 errata: - // If the 32-bit Thumb-2 branch instruction spans two 4KiB regions and - // the target of the branch falls within the first region it is - // possible for the processor to incorrectly determine the branch - // instruction, and it is also possible in some cases for the processor - // to enter a deadlock state. - // The instruction is spanning two pages if it ends at an address ending 0x002 - bool spansTwo4K = ((reinterpret_cast(instruction) & 0xfff) == 0x002); - // The target is in the first page if the jump branch back by [3..0x1002] bytes - bool targetInFirstPage = (relative >= -0x1002) && (relative < -2); - bool wouldTriggerA8Errata = spansTwo4K && targetInFirstPage; - - if (((relative << 7) >> 7) == relative && !wouldTriggerA8Errata) { - // ARM encoding for the top two bits below the sign bit is 'peculiar'. - if (relative >= 0) - relative ^= 0xC00000; - - // All branch offsets should be an even distance. - ASSERT(!(relative & 1)); - // There may be a better way to fix this, but right now put the NOPs first, since in the - // case of an conditional branch this will be coming after an ITTT predicating *three* - // instructions! Looking backwards to modify the ITTT to an IT is not easy, due to - // variable wdith encoding - the previous instruction might *look* like an ITTT but - // actually be the second half of a 2-word op. - instruction[-5] = OP_NOP_T1; - instruction[-4] = OP_NOP_T2a; - instruction[-3] = OP_NOP_T2b; - instruction[-2] = OP_B_T4a | ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12); - instruction[-1] = OP_B_T4b | ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1); - } else { - ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast(reinterpret_cast(target) + 1)); - ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast(reinterpret_cast(target) >> 16)); - instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); - instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16); - instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); - instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16); - instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3); - } - } - - static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op, ARMThumbImmediate imm) - { - return op | (imm.m_value.i << 10) | imm.m_value.imm4; - } - static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm) - { - return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8; - } - - class ARMInstructionFormatter { - public: - void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm) - { - m_buffer.putShort(op | (rd << 8) | imm); - } - - void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2) - { - m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2); - } - - void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3) - { - m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3); - } - - void oneWordOp8Imm8(OpcodeID op, uint8_t imm) - { - m_buffer.putShort(op | imm); - } - - void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2) - { - m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7)); - } - void oneWordOp9Imm7(OpcodeID op, uint8_t imm) - { - m_buffer.putShort(op | imm); - } - - void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2) - { - m_buffer.putShort(op | (reg1 << 3) | reg2); - } - - void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff) - { - m_buffer.putShort(op | reg); - m_buffer.putShort(ff.m_u.value); - } - - void twoWordOp16FourFours(OpcodeID1 op, FourFours ff) - { - m_buffer.putShort(op); - m_buffer.putShort(ff.m_u.value); - } - - void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2) - { - m_buffer.putShort(op1); - m_buffer.putShort(op2); - } - - void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm) - { - ARMThumbImmediate newImm = imm; - newImm.m_value.imm4 = imm4; - - m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op, newImm)); - m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm)); - } - - void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm) - { - m_buffer.putShort(op | reg1); - m_buffer.putShort((reg2 << 12) | imm); - } - - void vfpOp(int32_t op) - { - m_buffer.putInt(op); - } - - - // Administrative methods: - - size_t size() const { return m_buffer.size(); } - bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } - void* data() const { return m_buffer.data(); } - void* executableAllocAndCopy(ExecutableAllocator* allocator, ExecutablePool** poolp, CodeKind kind) { - return m_buffer.executableAllocAndCopy(allocator, poolp, kind); - } - bool oom() const { return m_buffer.oom(); } - - private: - AssemblerBuffer m_buffer; - } m_formatter; - - Vector m_jumpsToLink; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) - -#endif /* assembler_assembler_ARMv7Assembler_h */ diff --git a/js/src/assembler/assembler/AbstractMacroAssembler.h b/js/src/assembler/assembler/AbstractMacroAssembler.h deleted file mode 100644 index 597a1473ddc..00000000000 --- a/js/src/assembler/assembler/AbstractMacroAssembler.h +++ /dev/null @@ -1,659 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef assembler_assembler_AbstractMacroAssembler_h -#define assembler_assembler_AbstractMacroAssembler_h - -#include "assembler/wtf/Platform.h" -#include "assembler/assembler/MacroAssemblerCodeRef.h" -#include "assembler/assembler/CodeLocation.h" - -#if ENABLE_ASSEMBLER - -namespace JSC { - -class LinkBuffer; -class RepatchBuffer; - -template -class AbstractMacroAssembler { -public: - typedef AssemblerType AssemblerType_T; - - typedef MacroAssemblerCodePtr CodePtr; - typedef MacroAssemblerCodeRef CodeRef; - - class Jump; - - typedef typename AssemblerType::RegisterID RegisterID; - typedef typename AssemblerType::FPRegisterID FPRegisterID; - typedef typename AssemblerType::JmpSrc JmpSrc; - typedef typename AssemblerType::JmpDst JmpDst; - -#ifdef DEBUG - void setSpewPath(bool isOOLPath) - { - m_assembler.isOOLPath = isOOLPath; - } -#endif - - // Section 1: MacroAssembler operand types - // - // The following types are used as operands to MacroAssembler operations, - // describing immediate and memory operands to the instructions to be planted. - - - enum Scale { - TimesOne, - TimesTwo, - TimesFour, - TimesEight - }; - - // Address: - // - // Describes a simple base-offset address. - struct Address { - explicit Address() {} - - explicit Address(RegisterID base, int32_t offset = 0) - : base(base) - , offset(offset) - { - } - - RegisterID base; - int32_t offset; - }; - - struct ExtendedAddress { - explicit ExtendedAddress(RegisterID base, intptr_t offset = 0) - : base(base) - , offset(offset) - { - } - - RegisterID base; - intptr_t offset; - }; - - // ImplicitAddress: - // - // This class is used for explicit 'load' and 'store' operations - // (as opposed to situations in which a memory operand is provided - // to a generic operation, such as an integer arithmetic instruction). - // - // In the case of a load (or store) operation we want to permit - // addresses to be implicitly constructed, e.g. the two calls: - // - // load32(Address(addrReg), destReg); - // load32(addrReg, destReg); - // - // Are equivalent, and the explicit wrapping of the Address in the former - // is unnecessary. - struct ImplicitAddress { - explicit ImplicitAddress(RegisterID base) - : base(base) - , offset(0) - { - } - - MOZ_IMPLICIT ImplicitAddress(Address address) - : base(address.base) - , offset(address.offset) - { - } - - RegisterID base; - int32_t offset; - }; - - // BaseIndex: - // - // Describes a complex addressing mode. - struct BaseIndex { - BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0) - : base(base) - , index(index) - , scale(scale) - , offset(offset) - { - } - - RegisterID base; - RegisterID index; - Scale scale; - int32_t offset; - }; - - // AbsoluteAddress: - // - // Describes an memory operand given by a pointer. For regular load & store - // operations an unwrapped void* will be used, rather than using this. - struct AbsoluteAddress { - explicit AbsoluteAddress(const void* ptr) - : m_ptr(ptr) - { - } - - const void* m_ptr; - }; - - // TrustedImmPtr: - // - // A pointer sized immediate operand to an instruction - this is wrapped - // in a class requiring explicit construction in order to differentiate - // from pointers used as absolute addresses to memory operations - struct TrustedImmPtr { - explicit TrustedImmPtr(const void* value) - : m_value(value) - { - } - - intptr_t asIntptr() - { - return reinterpret_cast(m_value); - } - - const void* m_value; - }; - - struct ImmPtr : public TrustedImmPtr { - explicit ImmPtr(const void* value) - : TrustedImmPtr(value) - { - } - }; - - // TrustedImm32: - // - // A 32bit immediate operand to an instruction - this is wrapped in a - // class requiring explicit construction in order to prevent RegisterIDs - // (which are implemented as an enum) from accidentally being passed as - // immediate values. - struct TrustedImm32 { - explicit TrustedImm32(int32_t value) - : m_value(value) -#if WTF_CPU_ARM || WTF_CPU_MIPS - , m_isPointer(false) -#endif - { - } - -#if !WTF_CPU_X86_64 - explicit TrustedImm32(TrustedImmPtr ptr) - : m_value(ptr.asIntptr()) -#if WTF_CPU_ARM || WTF_CPU_MIPS - , m_isPointer(true) -#endif - { - } -#endif - - int32_t m_value; -#if WTF_CPU_ARM || WTF_CPU_MIPS - // We rely on being able to regenerate code to recover exception handling - // information. Since ARMv7 supports 16-bit immediates there is a danger - // that if pointer values change the layout of the generated code will change. - // To avoid this problem, always generate pointers (and thus Imm32s constructed - // from ImmPtrs) with a code sequence that is able to represent any pointer - // value - don't use a more compact form in these cases. - // Same for MIPS. - bool m_isPointer; -#endif - }; - - - struct Imm32 : public TrustedImm32 { - explicit Imm32(int32_t value) - : TrustedImm32(value) - { - } -#if !WTF_CPU_X86_64 - explicit Imm32(TrustedImmPtr ptr) - : TrustedImm32(ptr) - { - } -#endif - }; - - struct ImmDouble { - union { - struct { -#if WTF_CPU_BIG_ENDIAN || WTF_CPU_MIDDLE_ENDIAN - uint32_t msb, lsb; -#else - uint32_t lsb, msb; -#endif - } s; - uint64_t u64; - double d; - } u; - - explicit ImmDouble(double d) { - u.d = d; - } - }; - - // Section 2: MacroAssembler code buffer handles - // - // The following types are used to reference items in the code buffer - // during JIT code generation. For example, the type Jump is used to - // track the location of a jump instruction so that it may later be - // linked to a label marking its destination. - - - // Label: - // - // A Label records a point in the generated instruction stream, typically such that - // it may be used as a destination for a jump. - class Label { - template - friend class AbstractMacroAssembler; - friend class Jump; - friend class MacroAssemblerCodeRef; - friend class LinkBuffer; - - public: - Label() - { - } - - explicit Label(AbstractMacroAssembler* masm) - : m_label(masm->m_assembler.label()) - { - } - - bool isUsed() const { return m_label.isUsed(); } - void used() { m_label.used(); } - bool isSet() const { return m_label.isValid(); } - private: - JmpDst m_label; - }; - - // DataLabelPtr: - // - // A DataLabelPtr is used to refer to a location in the code containing a pointer to be - // patched after the code has been generated. - class DataLabelPtr { - template - friend class AbstractMacroAssembler; - friend class LinkBuffer; - public: - DataLabelPtr() - { - } - - explicit DataLabelPtr(AbstractMacroAssembler* masm) - : m_label(masm->m_assembler.label()) - { - } - - bool isSet() const { return m_label.isValid(); } - - private: - JmpDst m_label; - }; - - // DataLabel32: - // - // A DataLabel32 is used to refer to a location in the code containing a - // 32-bit constant to be patched after the code has been generated. - class DataLabel32 { - template - friend class AbstractMacroAssembler; - friend class LinkBuffer; - public: - DataLabel32() - { - } - - explicit DataLabel32(AbstractMacroAssembler* masm) - : m_label(masm->m_assembler.label()) - { - } - - private: - JmpDst m_label; - }; - - // Call: - // - // A Call object is a reference to a call instruction that has been planted - // into the code buffer - it is typically used to link the call, setting the - // relative offset such that when executed it will call to the desired - // destination. - class Call { - template - friend class AbstractMacroAssembler; - - public: - enum Flags { - None = 0x0, - Linkable = 0x1, - Near = 0x2, - LinkableNear = 0x3 - }; - - Call() - : m_flags(None) - { - } - - Call(JmpSrc jmp, Flags flags) - : m_jmp(jmp) - , m_flags(flags) - { - } - - bool isFlagSet(Flags flag) - { - return !!(m_flags & flag); - } - - static Call fromTailJump(Jump jump) - { - return Call(jump.m_jmp, Linkable); - } - - JmpSrc m_jmp; - private: - Flags m_flags; - }; - - // Jump: - // - // A jump object is a reference to a jump instruction that has been planted - // into the code buffer - it is typically used to link the jump, setting the - // relative offset such that when executed it will jump to the desired - // destination. - class Jump { - template - friend class AbstractMacroAssembler; - friend class Call; - friend class LinkBuffer; - public: - Jump() - { - } - - explicit Jump(JmpSrc jmp) - : m_jmp(jmp) - { - } - - void link(AbstractMacroAssembler* masm) const - { - masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label()); - } - - void linkTo(Label label, AbstractMacroAssembler* masm) const - { - masm->m_assembler.linkJump(m_jmp, label.m_label); - } - - bool isSet() const { return m_jmp.isSet(); } - - private: - JmpSrc m_jmp; - }; - - // JumpList: - // - // A JumpList is a set of Jump objects. - // All jumps in the set will be linked to the same destination. - class JumpList { - friend class LinkBuffer; - - public: - typedef js::Vector JumpVector; - - JumpList() {} - - JumpList(const JumpList &other) - { - m_jumps.appendAll(other.m_jumps); - } - - JumpList &operator=(const JumpList &other) - { - m_jumps.clear(); - m_jumps.append(other.m_jumps); - return *this; - } - - void link(AbstractMacroAssembler* masm) - { - size_t size = m_jumps.length(); - for (size_t i = 0; i < size; ++i) - m_jumps[i].link(masm); - m_jumps.clear(); - } - - void linkTo(Label label, AbstractMacroAssembler* masm) - { - size_t size = m_jumps.length(); - for (size_t i = 0; i < size; ++i) - m_jumps[i].linkTo(label, masm); - m_jumps.clear(); - } - - void append(Jump jump) - { - m_jumps.append(jump); - } - - void append(const JumpList& other) - { - m_jumps.append(other.m_jumps.begin(), other.m_jumps.length()); - } - - void clear() - { - m_jumps.clear(); - } - - bool empty() - { - return !m_jumps.length(); - } - - const JumpVector& jumps() const { return m_jumps; } - - private: - JumpVector m_jumps; - }; - - - // Section 3: Misc admin methods - - static CodePtr trampolineAt(CodeRef ref, Label label) - { - return CodePtr(AssemblerType::getRelocatedAddress(ref.m_code.dataLocation(), label.m_label)); - } - - size_t size() - { - return m_assembler.size(); - } - - unsigned char *buffer() - { - return m_assembler.buffer(); - } - - bool oom() - { - return m_assembler.oom(); - } - - void executableCopy(void* buffer) - { - ASSERT(!oom()); - m_assembler.executableCopy(buffer); - } - - Label label() - { - return Label(this); - } - - DataLabel32 dataLabel32() - { - return DataLabel32(this); - } - - Label align() - { - m_assembler.align(16); - return Label(this); - } - - ptrdiff_t differenceBetween(Label from, Jump to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); - } - - ptrdiff_t differenceBetween(Label from, Call to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); - } - - ptrdiff_t differenceBetween(Label from, Label to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); - } - - ptrdiff_t differenceBetween(Label from, DataLabelPtr to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); - } - - ptrdiff_t differenceBetween(Label from, DataLabel32 to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); - } - - ptrdiff_t differenceBetween(DataLabel32 from, Label to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); - } - - ptrdiff_t differenceBetween(DataLabelPtr from, Label to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); - } - - ptrdiff_t differenceBetween(DataLabelPtr from, Jump to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); - } - - ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); - } - - ptrdiff_t differenceBetween(DataLabelPtr from, Call to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); - } - -protected: - AssemblerType m_assembler; - - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkJump(void* code, Jump jump, CodeLocationLabel target) - { - AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation()); - } - - static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value) - { - AssemblerType::linkPointer(code, label, value); - } - - static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label) - { - return AssemblerType::getRelocatedAddress(code, label); - } - - static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label) - { - return AssemblerType::getRelocatedAddress(code, label); - } - - static unsigned getLinkerCallReturnOffset(Call call) - { - return AssemblerType::getCallReturnOffset(call.m_jmp); - } - - static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination) - { - AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation()); - } - - static bool canRepatchJump(CodeLocationJump jump, CodeLocationLabel destination) - { - return AssemblerType::canRelinkJump(jump.dataLocation(), destination.dataLocation()); - } - - static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination) - { - AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress()); - } - - static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value) - { - AssemblerType::repatchInt32(dataLabel32.dataLocation(), value); - } - - static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value) - { - AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value); - } - - static void repatchLoadPtrToLEA(CodeLocationInstruction instruction) - { - AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation()); - } - - static void repatchLEAToLoadPtr(CodeLocationInstruction instruction) - { - AssemblerType::repatchLEAToLoadPtr(instruction.dataLocation()); - } -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif /* assembler_assembler_AbstractMacroAssembler_h */ diff --git a/js/src/assembler/assembler/AssemblerBufferWithConstantPool.h b/js/src/assembler/assembler/AssemblerBufferWithConstantPool.h deleted file mode 100644 index 0ee7b7d3dc8..00000000000 --- a/js/src/assembler/assembler/AssemblerBufferWithConstantPool.h +++ /dev/null @@ -1,386 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2009 University of Szeged - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef assembler_assembler_AssemblerBufferWithConstantPool_h -#define assembler_assembler_AssemblerBufferWithConstantPool_h - -#include "assembler/wtf/Platform.h" - -#if ENABLE_ASSEMBLER - -#include "assembler/assembler/AssemblerBuffer.h" -#include "assembler/wtf/SegmentedVector.h" -#include "assembler/wtf/Assertions.h" - -#define ASSEMBLER_HAS_CONSTANT_POOL 1 - -namespace JSC { - -/* - On a constant pool 4 or 8 bytes data can be stored. The values can be - constants or addresses. The addresses should be 32 or 64 bits. The constants - should be double-precisions float or integer numbers which are hard to be - encoded as few machine instructions. - - TODO: The pool is desinged to handle both 32 and 64 bits values, but - currently only the 4 bytes constants are implemented and tested. - - The AssemblerBuffer can contain multiple constant pools. Each pool is inserted - into the instruction stream - protected by a jump instruction from the - execution flow. - - The flush mechanism is called when no space remain to insert the next instruction - into the pool. Three values are used to determine when the constant pool itself - have to be inserted into the instruction stream (Assembler Buffer): - - - maxPoolSize: size of the constant pool in bytes, this value cannot be - larger than the maximum offset of a PC relative memory load - - - barrierSize: size of jump instruction in bytes which protects the - constant pool from execution - - - maxInstructionSize: maximum length of a machine instruction in bytes - - There are some callbacks which solve the target architecture specific - address handling: - - - TYPE patchConstantPoolLoad(TYPE load, int value): - patch the 'load' instruction with the index of the constant in the - constant pool and return the patched instruction. - - - void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr): - patch the a PC relative load instruction at 'loadAddr' address with the - final relative offset. The offset can be computed with help of - 'constPoolAddr' (the address of the constant pool) and index of the - constant (which is stored previously in the load instruction itself). - - - TYPE placeConstantPoolBarrier(int size): - return with a constant pool barrier instruction which jumps over the - constant pool. - - The 'put*WithConstant*' functions should be used to place a data into the - constant pool. -*/ - -template -class AssemblerBufferWithConstantPool: public AssemblerBuffer { - typedef SegmentedVector LoadOffsets; -public: - enum { - UniqueConst, - ReusableConst, - UnusedEntry - }; - - AssemblerBufferWithConstantPool() - : AssemblerBuffer() - , m_numConsts(0) - , m_maxDistance(maxPoolSize) - , m_lastConstDelta(0) - , m_flushCount(0) - { - m_pool = static_cast(js_malloc(maxPoolSize)); - m_mask = static_cast(js_malloc(maxPoolSize / sizeof(uint32_t))); - } - - ~AssemblerBufferWithConstantPool() - { - js_free(m_mask); - js_free(m_pool); - } - - void ensureSpace(int space) - { - flushIfNoSpaceFor(space); - AssemblerBuffer::ensureSpace(space); - } - - void ensureSpace(int insnSpace, int constSpace) - { - flushIfNoSpaceFor(insnSpace, constSpace); - AssemblerBuffer::ensureSpace(insnSpace); - } - - bool isAligned(int alignment) - { - flushIfNoSpaceFor(alignment); - return AssemblerBuffer::isAligned(alignment); - } - - void putByteUnchecked(int value) - { - AssemblerBuffer::putByteUnchecked(value); - correctDeltas(1); - } - - void putByte(int value) - { - flushIfNoSpaceFor(1); - AssemblerBuffer::putByte(value); - correctDeltas(1); - } - - void putShortUnchecked(int value) - { - AssemblerBuffer::putShortUnchecked(value); - correctDeltas(2); - } - - void putShort(int value) - { - flushIfNoSpaceFor(2); - AssemblerBuffer::putShort(value); - correctDeltas(2); - } - - // Puts 1 word worth of data into the instruction stream - void putIntUnchecked(int value) - { - AssemblerBuffer::putIntUnchecked(value); - correctDeltas(4); - } - // Puts one word worth of data into the instruction stream, and makes sure - // there is enough space to place it, dumping the constant pool if there isn't - void putInt(int value) - { - flushIfNoSpaceFor(4); - AssemblerBuffer::putInt(value); - correctDeltas(4); - } - // puts 64 bits worth of data into the instruction stream - void putInt64Unchecked(int64_t value) - { - AssemblerBuffer::putInt64Unchecked(value); - correctDeltas(8); - } - - int size() - { - flushIfNoSpaceFor(maxInstructionSize, sizeof(uint64_t)); - return AssemblerBuffer::size(); - } - - int uncheckedSize() const - { - return AssemblerBuffer::size(); - } - - // copy all of our instructions and pools into their final location - void* executableAllocAndCopy(ExecutableAllocator* allocator, ExecutablePool** poolp, CodeKind kind) - { - flushConstantPool(false); - return AssemblerBuffer::executableAllocAndCopy(allocator, poolp, kind); - } - - // places 1 int worth of data into a pool, and mashes an instruction into place to - // hold this offset. - // the caller of putIntWithConstantInt passes in some token that represents an - // instruction, as well as the raw data that is to be placed in the pool. - // Traditionally, this 'token' has been the instruction that we wish to encode - // in the end, however, I have started encoding it in a much simpler manner, - // using bitfields and a fairly flat representation. - void putIntWithConstantInt(uint32_t insn, uint32_t constant, bool isReusable = false) - { - flushIfNoSpaceFor(4, 4); - - m_loadOffsets.append(AssemblerBuffer::size()); - if (isReusable) - for (int i = 0; i < m_numConsts; ++i) { - if (m_mask[i] == ReusableConst && m_pool[i] == constant) { - AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, i)); - correctDeltas(4); - return; - } - } - - m_pool[m_numConsts] = constant; - m_mask[m_numConsts] = static_cast(isReusable ? ReusableConst : UniqueConst); - - AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, m_numConsts)); - ++m_numConsts; - - correctDeltas(4, 4); - } - - void putIntWithConstantDouble(uint32_t insn, double constant) - { - flushIfNoSpaceFor(4, 8); - - m_loadOffsets.append(AssemblerBuffer::size()); - bool isReusable = false; - - union DoublePun { - struct { -#if defined(IS_LITTLE_ENDIAN) - uint32_t lo, hi; -#else - uint32_t hi, lo; -#endif - } s; - double d; - } dpun; - - dpun.d = constant; - - m_pool[m_numConsts] = dpun.s.lo; - m_pool[m_numConsts+1] = dpun.s.hi; - m_mask[m_numConsts] = static_cast(isReusable ? ReusableConst : UniqueConst); - m_mask[m_numConsts+1] = static_cast(isReusable ? ReusableConst : UniqueConst); - - AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, m_numConsts)); - m_numConsts+=2; - - correctDeltas(4, 8); - } - - // This flushing mechanism can be called after any unconditional jumps. - void flushWithoutBarrier(bool isForced = false) - { - // Flush if constant pool is more than 60% full to avoid overuse of this function. - if (isForced || (5 * m_numConsts * sizeof(uint32_t)) > (3 * maxPoolSize)) - flushConstantPool(false); - } - - // return the address of the pool; we really shouldn't be using this. - uint32_t* poolAddress() - { - return m_pool; - } - - // how many constants have been placed into the pool thusfar? - int sizeOfConstantPool() - { - return m_numConsts; - } - - int flushCount() - { - return m_flushCount; - } - -private: - void correctDeltas(int insnSize) - { - m_maxDistance -= insnSize; - ASSERT(m_maxDistance >= 0); - m_lastConstDelta -= insnSize; - if (m_lastConstDelta < 0) - m_lastConstDelta = 0; - } - - void correctDeltas(int insnSize, int constSize) - { - correctDeltas(insnSize); - - m_maxDistance -= m_lastConstDelta; - ASSERT(m_maxDistance >= 0); - m_lastConstDelta = constSize; - } - - // place a constant pool after the last instruction placed, and - // optionally place a jump to ensure we don't start executing the pool. - void flushConstantPool(bool useBarrier = true) - { - GenericAssembler::staticSpew(" -- FLUSHING CONSTANT POOL WITH %d CONSTANTS --\n", - m_numConsts); - if (m_numConsts == 0) - return; - m_flushCount++; - int alignPool = (AssemblerBuffer::size() + (useBarrier ? barrierSize : 0)) & (sizeof(uint64_t) - 1); - - if (alignPool) - alignPool = sizeof(uint64_t) - alignPool; - - // Callback to protect the constant pool from execution - if (useBarrier) - AssemblerBuffer::putInt(AssemblerType::placeConstantPoolBarrier(m_numConsts * sizeof(uint32_t) + alignPool)); - - if (alignPool) { - if (alignPool & 1) - AssemblerBuffer::putByte(AssemblerType::padForAlign8); - if (alignPool & 2) - AssemblerBuffer::putShort(AssemblerType::padForAlign16); - if (alignPool & 4) - AssemblerBuffer::putInt(AssemblerType::padForAlign32); - } - - int constPoolOffset = AssemblerBuffer::size(); - append(reinterpret_cast(m_pool), m_numConsts * sizeof(uint32_t)); - - // Patch each PC relative load - for (LoadOffsets::Iterator iter = m_loadOffsets.begin(); iter != m_loadOffsets.end(); ++iter) { - void* loadAddr = reinterpret_cast(m_buffer + *iter); - AssemblerType::patchConstantPoolLoad(loadAddr, reinterpret_cast(m_buffer + constPoolOffset)); - } - - m_loadOffsets.clear(); - m_numConsts = 0; - m_maxDistance = maxPoolSize; - ASSERT(m_maxDistance >= 0); - - } - - void flushIfNoSpaceFor(int nextInsnSize) - { - if (m_numConsts == 0) { - m_maxDistance = maxPoolSize; - return; - } - int lastConstDelta = m_lastConstDelta > nextInsnSize ? m_lastConstDelta - nextInsnSize : 0; - if ((m_maxDistance < nextInsnSize + lastConstDelta + barrierSize + (int)sizeof(uint32_t))) - flushConstantPool(); - } - - void flushIfNoSpaceFor(int nextInsnSize, int nextConstSize) - { - if (m_numConsts == 0) { - m_maxDistance = maxPoolSize; - return; - } - if ((m_maxDistance < nextInsnSize + m_lastConstDelta + nextConstSize + barrierSize + (int)sizeof(uint32_t)) || - (m_numConsts * sizeof(uint32_t) + nextConstSize >= maxPoolSize)) - flushConstantPool(); - } - - uint32_t* m_pool; - char* m_mask; - LoadOffsets m_loadOffsets; - - int m_numConsts; - int m_maxDistance; - int m_lastConstDelta; - int m_flushCount; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif /* assembler_assembler_AssemblerBufferWithConstantPool_h */ diff --git a/js/src/assembler/assembler/CodeLocation.h b/js/src/assembler/assembler/CodeLocation.h deleted file mode 100644 index 10e4815cbdb..00000000000 --- a/js/src/assembler/assembler/CodeLocation.h +++ /dev/null @@ -1,189 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef assembler_assembler_CodeLocation_h -#define assembler_assembler_CodeLocation_h - -#include "assembler/wtf/Platform.h" -#include "assembler/assembler/MacroAssemblerCodeRef.h" - -#if ENABLE_ASSEMBLER - -namespace JSC { - -class CodeLocationInstruction; -class CodeLocationLabel; -class CodeLocationJump; -class CodeLocationCall; -class CodeLocationNearCall; -class CodeLocationDataLabel32; -class CodeLocationDataLabelPtr; - -// The CodeLocation* types are all pretty much do-nothing wrappers around -// CodePtr (or MacroAssemblerCodePtr, to give it its full name). These -// classes only exist to provide type-safety when linking and patching code. -// -// The one new piece of functionallity introduced by these classes is the -// ability to create (or put another way, to re-discover) another CodeLocation -// at an offset from one you already know. When patching code to optimize it -// we often want to patch a number of instructions that are short, fixed -// offsets apart. To reduce memory overhead we will only retain a pointer to -// one of the instructions, and we will use the *AtOffset methods provided by -// CodeLocationCommon to find the other points in the code to modify. -class CodeLocationCommon : public MacroAssemblerCodePtr { -public: - CodeLocationInstruction instructionAtOffset(int offset); - CodeLocationLabel labelAtOffset(int offset); - CodeLocationJump jumpAtOffset(int offset); - CodeLocationCall callAtOffset(int offset); - CodeLocationNearCall nearCallAtOffset(int offset); - CodeLocationDataLabelPtr dataLabelPtrAtOffset(int offset); - CodeLocationDataLabel32 dataLabel32AtOffset(int offset); - -protected: - CodeLocationCommon() - { - } - - explicit CodeLocationCommon(MacroAssemblerCodePtr location) - : MacroAssemblerCodePtr(location) - { - } -}; - -class CodeLocationInstruction : public CodeLocationCommon { -public: - CodeLocationInstruction() {} - explicit CodeLocationInstruction(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationInstruction(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationLabel : public CodeLocationCommon { -public: - CodeLocationLabel() {} - explicit CodeLocationLabel(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationLabel(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationJump : public CodeLocationCommon { -public: - CodeLocationJump() {} - explicit CodeLocationJump(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationJump(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationCall : public CodeLocationCommon { -public: - CodeLocationCall() {} - explicit CodeLocationCall(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationCall(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationNearCall : public CodeLocationCommon { -public: - CodeLocationNearCall() {} - explicit CodeLocationNearCall(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationNearCall(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationDataLabel32 : public CodeLocationCommon { -public: - CodeLocationDataLabel32() {} - explicit CodeLocationDataLabel32(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationDataLabel32(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationDataLabelPtr : public CodeLocationCommon { -public: - CodeLocationDataLabelPtr() {} - explicit CodeLocationDataLabelPtr(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationDataLabelPtr(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -inline CodeLocationInstruction CodeLocationCommon::instructionAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationInstruction(reinterpret_cast(dataLocation()) + offset); -} - -inline CodeLocationLabel CodeLocationCommon::labelAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationLabel(reinterpret_cast(dataLocation()) + offset); -} - -inline CodeLocationJump CodeLocationCommon::jumpAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationJump(reinterpret_cast(dataLocation()) + offset); -} - -inline CodeLocationCall CodeLocationCommon::callAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationCall(reinterpret_cast(dataLocation()) + offset); -} - -inline CodeLocationNearCall CodeLocationCommon::nearCallAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationNearCall(reinterpret_cast(dataLocation()) + offset); -} - -inline CodeLocationDataLabelPtr CodeLocationCommon::dataLabelPtrAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationDataLabelPtr(reinterpret_cast(dataLocation()) + offset); -} - -inline CodeLocationDataLabel32 CodeLocationCommon::dataLabel32AtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationDataLabel32(reinterpret_cast(dataLocation()) + offset); -} - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif /* assembler_assembler_CodeLocation_h */ diff --git a/js/src/assembler/assembler/LinkBuffer.h b/js/src/assembler/assembler/LinkBuffer.h deleted file mode 100644 index d78ec2b438f..00000000000 --- a/js/src/assembler/assembler/LinkBuffer.h +++ /dev/null @@ -1,221 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef assembler_assembler_LinkBuffer_h -#define assembler_assembler_LinkBuffer_h - -#include "assembler/wtf/Platform.h" - -#if ENABLE_ASSEMBLER - -#include "assembler/assembler/MacroAssembler.h" - -namespace JSC { - -// LinkBuffer: -// -// This class assists in linking code generated by the macro assembler, once code generation -// has been completed, and the code has been copied to is final location in memory. At this -// time pointers to labels within the code may be resolved, and relative offsets to external -// addresses may be fixed. -// -// Specifically: -// * Jump objects may be linked to external targets, -// * The address of Jump objects may taken, such that it can later be relinked. -// * The return address of a Call may be acquired. -// * The address of a Label pointing into the code may be resolved. -// * The value referenced by a DataLabel may be set. -// -class LinkBuffer { - typedef MacroAssemblerCodeRef CodeRef; - typedef MacroAssembler::Label Label; - typedef MacroAssembler::Jump Jump; - typedef MacroAssembler::JumpList JumpList; - typedef MacroAssembler::Call Call; - typedef MacroAssembler::DataLabel32 DataLabel32; - typedef MacroAssembler::DataLabelPtr DataLabelPtr; - -public: - // 'ok' should be checked after this constructor is called; it's false if OOM occurred. - LinkBuffer(MacroAssembler* masm, ExecutableAllocator* executableAllocator, - ExecutablePool** poolp, bool* ok, CodeKind codeKind) - { - // LinkBuffer is only used by Yarr. MacroAssemblerCodeRef::release relies on this. - MOZ_ASSERT(codeKind == REGEXP_CODE); - m_codeKind = codeKind; - m_code = executableAllocAndCopy(*masm, executableAllocator, poolp); - m_executablePool = *poolp; - m_size = masm->m_assembler.size(); // must come after call to executableAllocAndCopy()! - m_allocSize = masm->m_assembler.allocSize(); -#ifndef NDEBUG - m_completed = false; -#endif - *ok = !!m_code; - } - - ~LinkBuffer() - { - ASSERT(!m_executablePool || m_completed); - } - - // These methods are used to link or set values at code generation time. - - void link(Call call, FunctionPtr function) - { - ASSERT(call.isFlagSet(Call::Linkable)); - MacroAssembler::linkCall(code(), call, function); - } - - void link(Jump jump, CodeLocationLabel label) - { - MacroAssembler::linkJump(code(), jump, label); - } - - void link(JumpList list, CodeLocationLabel label) - { - for (unsigned i = 0; i < list.m_jumps.length(); ++i) - MacroAssembler::linkJump(code(), list.m_jumps[i], label); - } - - void patch(DataLabelPtr label, void* value) - { - MacroAssembler::linkPointer(code(), label.m_label, value); - } - - void patch(DataLabelPtr label, CodeLocationLabel value) - { - MacroAssembler::linkPointer(code(), label.m_label, value.executableAddress()); - } - - // These methods are used to obtain handles to allow the code to be relinked / repatched later. - - CodeLocationCall locationOf(Call call) - { - ASSERT(call.isFlagSet(Call::Linkable)); - ASSERT(!call.isFlagSet(Call::Near)); - return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp)); - } - - CodeLocationJump locationOf(Jump j) - { - return CodeLocationJump(MacroAssembler::getLinkerAddress(code(), j.m_jmp)); - } - - CodeLocationNearCall locationOfNearCall(Call call) - { - ASSERT(call.isFlagSet(Call::Linkable)); - ASSERT(call.isFlagSet(Call::Near)); - return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp)); - } - - CodeLocationLabel locationOf(Label label) - { - return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), label.m_label)); - } - - CodeLocationDataLabelPtr locationOf(DataLabelPtr label) - { - return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), label.m_label)); - } - - CodeLocationDataLabel32 locationOf(DataLabel32 label) - { - return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), label.m_label)); - } - - // This method obtains the return address of the call, given as an offset from - // the start of the code. - unsigned returnAddressOffset(Call call) - { - return MacroAssembler::getLinkerCallReturnOffset(call); - } - - // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called - // once to complete generation of the code. 'finalizeCode()' is suited to situations - // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is - // suited to adding to an existing allocation. - CodeRef finalizeCode() - { - performFinalization(); - - MOZ_ASSERT(m_allocSize >= m_size); - return CodeRef(m_code, m_executablePool, m_allocSize); - } - CodeLocationLabel finalizeCodeAddendum() - { - performFinalization(); - - return CodeLocationLabel(code()); - } - - // Useful as a proxy to detect OOM. - void* unsafeCode() { - return code(); - } - -protected: - // Keep this private! - the underlying code should only be obtained externally via - // finalizeCode() or finalizeCodeAddendum(). - void* code() - { - return m_code; - } - - void *executableAllocAndCopy(MacroAssembler &masm, ExecutableAllocator *allocator, - ExecutablePool **poolp) - { - return masm.m_assembler.executableAllocAndCopy(allocator, poolp, m_codeKind); - } - - void performFinalization() - { -#ifndef NDEBUG - ASSERT(!m_completed); - m_completed = true; -#endif - - ExecutableAllocator::makeExecutable(code(), m_size); - ExecutableAllocator::cacheFlush(code(), m_size); - } - - ExecutablePool* m_executablePool; - void* m_code; - size_t m_size; - size_t m_allocSize; - CodeKind m_codeKind; -#ifndef NDEBUG - bool m_completed; -#endif -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif /* assembler_assembler_LinkBuffer_h */ diff --git a/js/src/assembler/assembler/MIPSAssembler.h b/js/src/assembler/assembler/MIPSAssembler.h deleted file mode 100644 index 4d500c94812..00000000000 --- a/js/src/assembler/assembler/MIPSAssembler.h +++ /dev/null @@ -1,1081 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. - * Copyright (C) 2009 University of Szeged - * All rights reserved. - * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef assembler_assembler_MIPSAssembler_h -#define assembler_assembler_MIPSAssembler_h - -#if ENABLE(ASSEMBLER) && CPU(MIPS) - -#include "assembler/assembler/AssemblerBuffer.h" -#include "assembler/wtf/Assertions.h" -#include "assembler/wtf/SegmentedVector.h" - -#define IPFX " %s" -#define ISPFX " " -#ifdef JS_METHODJIT_SPEW -# define MAYBE_PAD (isOOLPath ? "> " : "") -#else -# define MAYBE_PAD "" -#endif - -namespace JSC { - -typedef uint32_t MIPSWord; - -namespace MIPSRegisters { -typedef enum { - r0 = 0, - r1, - r2, - r3, - r4, - r5, - r6, - r7, - r8, - r9, - r10, - r11, - r12, - r13, - r14, - r15, - r16, - r17, - r18, - r19, - r20, - r21, - r22, - r23, - r24, - r25, - r26, - r27, - r28, - r29, - r30, - r31, - zero = r0, - at = r1, - v0 = r2, - v1 = r3, - a0 = r4, - a1 = r5, - a2 = r6, - a3 = r7, - t0 = r8, - t1 = r9, - t2 = r10, - t3 = r11, - t4 = r12, - t5 = r13, - t6 = r14, - t7 = r15, - s0 = r16, - s1 = r17, - s2 = r18, - s3 = r19, - s4 = r20, - s5 = r21, - s6 = r22, - s7 = r23, - t8 = r24, - t9 = r25, - k0 = r26, - k1 = r27, - gp = r28, - sp = r29, - fp = r30, - ra = r31 -} RegisterID; - -typedef enum { - f0 = 0, - f1, - f2, - f3, - f4, - f5, - f6, - f7, - f8, - f9, - f10, - f11, - f12, - f13, - f14, - f15, - f16, - f17, - f18, - f19, - f20, - f21, - f22, - f23, - f24, - f25, - f26, - f27, - f28, - f29, - f30, - f31 -} FPRegisterID; - -} // namespace MIPSRegisters - -class MIPSAssembler : public GenericAssembler { -public: - typedef MIPSRegisters::RegisterID RegisterID; - typedef MIPSRegisters::FPRegisterID FPRegisterID; - typedef SegmentedVector Jumps; - unsigned char *buffer() const { return m_buffer.buffer(); } - bool oom() const { return m_buffer.oom(); } - - // MIPS instruction opcode field position - enum { - OP_SH_RD = 11, - OP_SH_RT = 16, - OP_SH_RS = 21, - OP_SH_SHAMT = 6, - OP_SH_CODE = 16, - OP_SH_FD = 6, - OP_SH_FS = 11, - OP_SH_FT = 16 - }; - - class JmpSrc { - friend class MIPSAssembler; - public: - JmpSrc() - : m_offset(-1) - { - } - - bool isSet() const { - return m_offset != -1; - } - - private: - JmpSrc(int offset) - : m_offset(offset) - { - } - - int m_offset; - }; - - class JmpDst { - friend class MIPSAssembler; - public: - JmpDst() - : m_offset(-1) - , m_used(false) - { - } - - bool isUsed() const { return m_used; } - void used() { m_used = true; } - bool isValid() const { return m_offset != -1; } - private: - JmpDst(int offset) - : m_offset(offset) - , m_used(false) - { - ASSERT(m_offset == offset); - } - - int m_offset : 31; - int m_used : 1; - }; - - void emitInst(MIPSWord op) - { - void* oldBase = m_buffer.data(); - - m_buffer.putInt(op); - - void* newBase = m_buffer.data(); - if (oldBase != newBase) - relocateJumps(oldBase, newBase); - } - - void nop() - { - emitInst(0x00000000); - } - - /* Need to insert one load data delay nop for mips1. */ - void loadDelayNop() - { -#if WTF_MIPS_ISA(1) - nop(); -#endif - } - - /* Need to insert one coprocessor access delay nop for mips1. */ - void copDelayNop() - { -#if WTF_MIPS_ISA(1) - nop(); -#endif - } - - void movz(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x0000000a | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void move(RegisterID rd, RegisterID rs) - { - /* addu */ - emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS)); - } - - /* Set an immediate value to a register. This may generate 1 or 2 - instructions. */ - void li(RegisterID dest, int imm) - { - if (imm >= -32768 && imm <= 32767) - addiu(dest, MIPSRegisters::zero, imm); - else if (imm >= 0 && imm < 65536) - ori(dest, MIPSRegisters::zero, imm); - else { - lui(dest, imm >> 16); - if (imm & 0xffff) - ori(dest, dest, imm); - } - } - - void lui(RegisterID rt, int imm) - { - emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff)); - } - - void addiu(RegisterID rt, RegisterID rs, int imm) - { - emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (imm & 0xffff)); - } - - void addu(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void subu(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void mult(RegisterID rs, RegisterID rt) - { - emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT)); - } - - void div(RegisterID rs, RegisterID rt) - { - emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT)); - } - - void mfhi(RegisterID rd) - { - emitInst(0x00000010 | (rd << OP_SH_RD)); - } - - void mflo(RegisterID rd) - { - emitInst(0x00000012 | (rd << OP_SH_RD)); - } - - void mul(RegisterID rd, RegisterID rs, RegisterID rt) - { -#if WTF_MIPS_ISA_AT_LEAST(32) - emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); -#else - mult(rs, rt); - mflo(rd); -#endif - } - - void andInsn(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void andi(RegisterID rt, RegisterID rs, int imm) - { - emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (imm & 0xffff)); - } - - void nor(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void orInsn(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void ori(RegisterID rt, RegisterID rs, int imm) - { - emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (imm & 0xffff)); - } - - void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void xori(RegisterID rt, RegisterID rs, int imm) - { - emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (imm & 0xffff)); - } - - void slt(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void sltu(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void sltiu(RegisterID rt, RegisterID rs, int imm) - { - emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (imm & 0xffff)); - } - - void sll(RegisterID rd, RegisterID rt, int shamt) - { - emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | ((shamt & 0x1f) << OP_SH_SHAMT)); - } - - void sllv(RegisterID rd, RegisterID rt, int rs) - { - emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | (rs << OP_SH_RS)); - } - - void sra(RegisterID rd, RegisterID rt, int shamt) - { - emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | ((shamt & 0x1f) << OP_SH_SHAMT)); - } - - void srav(RegisterID rd, RegisterID rt, RegisterID rs) - { - emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | (rs << OP_SH_RS)); - } - - void srl(RegisterID rd, RegisterID rt, int shamt) - { - emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | ((shamt & 0x1f) << OP_SH_SHAMT)); - } - - void srlv(RegisterID rd, RegisterID rt, RegisterID rs) - { - emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | (rs << OP_SH_RS)); - } - - void lb(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x80000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void lbu(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void lw(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void lwl(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void lwr(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void lh(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x84000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void lhu(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void sb(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0xa0000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - } - - void sh(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0xa4000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - } - - void sw(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - } - - void jr(RegisterID rs) - { - emitInst(0x00000008 | (rs << OP_SH_RS)); - } - - void jalr(RegisterID rs) - { - emitInst(0x0000f809 | (rs << OP_SH_RS)); - } - - void jal() - { - emitInst(0x0c000000); - } - - void bkpt() - { - int value = 512; /* BRK_BUG */ - emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE)); - } - - void bgez(RegisterID rs, int imm) - { - emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff)); - } - - void bltz(RegisterID rs, int imm) - { - emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff)); - } - - void beq(RegisterID rs, RegisterID rt, int imm) - { - emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff)); - } - - void bne(RegisterID rs, RegisterID rt, int imm) - { - emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff)); - } - - void bc1t() - { - emitInst(0x45010000); - } - - void bc1f() - { - emitInst(0x45000000); - } - - JmpSrc newJmpSrc() - { - return JmpSrc(m_buffer.size()); - } - - void appendJump() - { - m_jumps.append(m_buffer.size()); - } - - void movd(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46200006 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS) - | (ft << OP_SH_FT)); - } - - void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS) - | (ft << OP_SH_FT)); - } - - void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS) - | (ft << OP_SH_FT)); - } - - void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS) - | (ft << OP_SH_FT)); - } - - void negd(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46200007 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void absd(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46200005 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void lwc1(FPRegisterID ft, RegisterID rs, int offset) - { - emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - copDelayNop(); - } - - void ldc1(FPRegisterID ft, RegisterID rs, int offset) - { - emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - } - - void swc1(FPRegisterID ft, RegisterID rs, int offset) - { - emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - } - - void sdc1(FPRegisterID ft, RegisterID rs, int offset) - { - emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - } - - void mtc1(RegisterID rt, FPRegisterID fs) - { - emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT)); - copDelayNop(); - } - - void mthc1(RegisterID rt, FPRegisterID fs) - { - emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT)); - copDelayNop(); - } - - void mfc1(RegisterID rt, FPRegisterID fs) - { - emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT)); - copDelayNop(); - } - - void sqrtd(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void truncwd(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void cvtdw(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void cvtds(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46000021 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void cvtsd(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46200020 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void cvtwd(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void ceqd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cngtd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cnged(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cltd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cled(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cueqd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void coled(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void coltd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void culed(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cultd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - // General helpers - - JmpDst label() - { - return JmpDst(m_buffer.size()); - } - - JmpDst align(int alignment) - { - while (!m_buffer.isAligned(alignment)) - bkpt(); - - return label(); - } - - static void* getRelocatedAddress(void* code, JmpSrc jump) - { - ASSERT(jump.m_offset != -1); - void* b = reinterpret_cast((reinterpret_cast(code)) + jump.m_offset); - return b; - } - - static void* getRelocatedAddress(void* code, JmpDst label) - { - void* b = reinterpret_cast((reinterpret_cast(code)) + label.m_offset); - return b; - } - - static int getDifferenceBetweenLabels(JmpDst from, JmpDst to) - { - return to.m_offset - from.m_offset; - } - - static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to) - { - return to.m_offset - from.m_offset; - } - - static int getDifferenceBetweenLabels(JmpSrc from, JmpDst to) - { - return to.m_offset - from.m_offset; - } - - // Assembler admin methods: - - size_t size() const - { - return m_buffer.size(); - } - - size_t allocSize() const - { - return m_buffer.allocSize(); - } - - void executableCopy(void* buffer) - { - memcpy(buffer, m_buffer.data(), m_buffer.size()); - relocateJumps(m_buffer.data(), buffer); - } - - void* executableAllocAndCopy(ExecutableAllocator* allocator, ExecutablePool** poolp, CodeKind kind) - { - void *result = m_buffer.executableAllocAndCopy(allocator, poolp, kind); - if (!result) - return 0; - - relocateJumps(m_buffer.data(), result); - return result; - } - - static unsigned getCallReturnOffset(JmpSrc call) - { - // The return address is after a call and a delay slot instruction - return call.m_offset; - } - - // Linking & patching: - // - // 'link' and 'patch' methods are for use on unprotected code - such as the code - // within the AssemblerBuffer, and code being patched by the patch buffer. Once - // code has been finalized it is (platform support permitting) within a non- - // writable region of memory; to modify the code in an execute-only execuable - // pool the 'repatch' and 'relink' methods should be used. - - void linkJump(JmpSrc from, JmpDst to) - { - ASSERT(to.m_offset != -1); - ASSERT(from.m_offset != -1); - MIPSWord* insn = reinterpret_cast(reinterpret_cast(m_buffer.data()) + from.m_offset); - MIPSWord* toPos = reinterpret_cast(reinterpret_cast(m_buffer.data()) + to.m_offset); - - ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5))); - insn = insn - 6; - linkWithOffset(insn, toPos); - } - - static void linkJump(void* code, JmpSrc from, void* to) - { - ASSERT(from.m_offset != -1); - MIPSWord* insn = reinterpret_cast(reinterpret_cast(code) + from.m_offset); - - ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5))); - insn = insn - 6; - linkWithOffset(insn, to); - } - - static bool canRelinkJump(void* from, void* to) - { - return true; - } - - static void linkCall(void* code, JmpSrc from, void* to) - { - MIPSWord* insn = reinterpret_cast(reinterpret_cast(code) + from.m_offset); - linkCallInternal(insn, to); - } - - static void linkPointer(void* code, JmpDst from, void* to) - { - MIPSWord* insn = reinterpret_cast(reinterpret_cast(code) + from.m_offset); - ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui - *insn = (*insn & 0xffff0000) | ((reinterpret_cast(to) >> 16) & 0xffff); - insn++; - ASSERT((*insn & 0xfc000000) == 0x34000000); // ori - *insn = (*insn & 0xffff0000) | (reinterpret_cast(to) & 0xffff); - } - - static void relinkJump(void* from, void* to) - { - MIPSWord* insn = reinterpret_cast(from); - - ASSERT(!(*(insn - 1)) && !(*(insn - 5))); - insn = insn - 6; - int flushSize = linkWithOffset(insn, to); - - ExecutableAllocator::cacheFlush(insn, flushSize); - } - - static void relinkCall(void* from, void* to) - { - void* start; - int size = linkCallInternal(from, to); - if (size == sizeof(MIPSWord)) - start = reinterpret_cast(reinterpret_cast(from) - 2 * sizeof(MIPSWord)); - else - start = reinterpret_cast(reinterpret_cast(from) - 4 * sizeof(MIPSWord)); - - ExecutableAllocator::cacheFlush(start, size); - } - - static void repatchInt32(void* from, int32_t to) - { - MIPSWord* insn = reinterpret_cast(from); - ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui - *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff); - insn++; - ASSERT((*insn & 0xfc000000) == 0x34000000); // ori - *insn = (*insn & 0xffff0000) | (to & 0xffff); - insn--; - ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord)); - } - - static void repatchPointer(void* from, void* to) - { - repatchInt32(from, reinterpret_cast(to)); - } - - static void repatchLoadPtrToLEA(void* from) - { - MIPSWord* insn = reinterpret_cast(from); - insn = insn + 3; - ASSERT((*insn & 0xfc000000) == 0x8c000000); // lw - /* lw -> addiu */ - *insn = 0x24000000 | (*insn & 0x03ffffff); - - ExecutableAllocator::cacheFlush(insn, sizeof(MIPSWord)); - } - - static void repatchLEAToLoadPtr(void* from) - { - MIPSWord* insn = reinterpret_cast(from); - insn = insn + 3; - if ((*insn & 0xfc000000) == 0x8c000000) - return; // Valid lw instruction - - ASSERT((*insn & 0xfc000000) == 0x24000000); // addiu - /* addiu -> lw */ - *insn = 0x8c000000 | (*insn & 0x03ffffff); - - ExecutableAllocator::cacheFlush(insn, sizeof(MIPSWord)); - } - -private: - - /* Update each jump in the buffer of newBase. */ - void relocateJumps(void* oldBase, void* newBase) - { - // Check each jump - for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) { - int pos = *iter; - MIPSWord* insn = reinterpret_cast(reinterpret_cast(newBase) + pos); - insn = insn + 2; - // Need to make sure we have 5 valid instructions after pos - if ((unsigned int)pos >= m_buffer.size() - 5 * sizeof(MIPSWord)) - continue; - - if ((*insn & 0xfc000000) == 0x08000000) { // j - int offset = *insn & 0x03ffffff; - int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase; - int topFourBits = (oldInsnAddress + 4) >> 28; - int oldTargetAddress = (topFourBits << 28) | (offset << 2); - int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase; - int newInsnAddress = (int)insn; - if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28)) - *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff); - else { - /* lui */ - *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff); - /* ori */ - *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff); - /* jr */ - *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS); - } - } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui - int high = (*insn & 0xffff) << 16; - int low = *(insn + 1) & 0xffff; - int oldTargetAddress = high | low; - int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase; - /* lui */ - *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff); - /* ori */ - *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff); - } - } - } - - static int linkWithOffset(MIPSWord* insn, void* to) - { - ASSERT((*insn & 0xfc000000) == 0x10000000 // beq - || (*insn & 0xfc000000) == 0x14000000 // bne - || (*insn & 0xffff0000) == 0x45010000 // bc1t - || (*insn & 0xffff0000) == 0x45000000); // bc1f - intptr_t diff = (reinterpret_cast(to) - - reinterpret_cast(insn) - 4) >> 2; - - if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) { - /* - Convert the sequence: - beq $2, $3, target - nop - b 1f - nop - nop - nop - 1: - - to the new sequence if possible: - bne $2, $3, 1f - nop - j target - nop - nop - nop - 1: - - OR to the new sequence: - bne $2, $3, 1f - nop - lui $25, target >> 16 - ori $25, $25, target & 0xffff - jr $25 - nop - 1: - - Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t. - */ - - if (*(insn + 2) == 0x10000003) { - if ((*insn & 0xfc000000) == 0x10000000) // beq - *insn = (*insn & 0x03ff0000) | 0x14000005; // bne - else if ((*insn & 0xfc000000) == 0x14000000) // bne - *insn = (*insn & 0x03ff0000) | 0x10000005; // beq - else if ((*insn & 0xffff0000) == 0x45010000) // bc1t - *insn = 0x45000005; // bc1f - else if ((*insn & 0xffff0000) == 0x45000000) // bc1f - *insn = 0x45010005; // bc1t - else - ASSERT(0); - } - - insn = insn + 2; - if ((reinterpret_cast(insn) + 4) >> 28 - == reinterpret_cast(to) >> 28) { - *insn = 0x08000000 | ((reinterpret_cast(to) >> 2) & 0x3ffffff); - *(insn + 1) = 0; - return 4 * sizeof(MIPSWord); - } - - intptr_t newTargetAddress = reinterpret_cast(to); - /* lui */ - *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff); - /* ori */ - *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff); - /* jr */ - *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS); - return 5 * sizeof(MIPSWord); - } - - *insn = (*insn & 0xffff0000) | (diff & 0xffff); - return sizeof(MIPSWord); - } - - static int linkCallInternal(void* from, void* to) - { - MIPSWord* insn = reinterpret_cast(from); - insn = insn - 4; - - if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal - if ((reinterpret_cast(from) - 4) >> 28 - == reinterpret_cast(to) >> 28) { - *(insn + 2) = 0x0c000000 | ((reinterpret_cast(to) >> 2) & 0x3ffffff); - return sizeof(MIPSWord); - } - - /* lui $25, (to >> 16) & 0xffff */ - *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast(to) >> 16) & 0xffff); - /* ori $25, $25, to & 0xffff */ - *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast(to) & 0xffff); - /* jalr $25 */ - *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS); - return 3 * sizeof(MIPSWord); - } - - ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui - ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori - - /* lui */ - *insn = (*insn & 0xffff0000) | ((reinterpret_cast(to) >> 16) & 0xffff); - /* ori */ - *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast(to) & 0xffff); - return 2 * sizeof(MIPSWord); - } - - AssemblerBuffer m_buffer; - Jumps m_jumps; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) && CPU(MIPS) - -#endif /* assembler_assembler_MIPSAssembler_h */ diff --git a/js/src/assembler/assembler/MacroAssembler.h b/js/src/assembler/assembler/MacroAssembler.h index b4694426296..129d88cfe86 100644 --- a/js/src/assembler/assembler/MacroAssembler.h +++ b/js/src/assembler/assembler/MacroAssembler.h @@ -36,361 +36,32 @@ #if WTF_CPU_ARM_THUMB2 #include "assembler/assembler/MacroAssemblerARMv7.h" -namespace JSC { typedef MacroAssemblerARMv7 MacroAssemblerBase; } +namespace JSC { typedef MacroAssemblerARMv7 MacroAssembler; } #elif WTF_CPU_ARM_TRADITIONAL #include "assembler/assembler/MacroAssemblerARM.h" -namespace JSC { typedef MacroAssemblerARM MacroAssemblerBase; } +namespace JSC { typedef MacroAssemblerARM MacroAssembler; } #elif WTF_CPU_MIPS #include "assembler/assembler/MacroAssemblerMIPS.h" -namespace JSC { typedef MacroAssemblerMIPS MacroAssemblerBase; } +namespace JSC { typedef MacroAssemblerMIPS MacroAssembler; } #elif WTF_CPU_X86 #include "assembler/assembler/MacroAssemblerX86.h" -namespace JSC { typedef MacroAssemblerX86 MacroAssemblerBase; } +namespace JSC { typedef MacroAssemblerX86 MacroAssembler; } #elif WTF_CPU_X86_64 #include "assembler/assembler/MacroAssemblerX86_64.h" -namespace JSC { typedef MacroAssemblerX86_64 MacroAssemblerBase; } +namespace JSC { typedef MacroAssemblerX86_64 MacroAssembler; } #elif WTF_CPU_SPARC #include "assembler/assembler/MacroAssemblerSparc.h" -namespace JSC { typedef MacroAssemblerSparc MacroAssemblerBase; } +namespace JSC { typedef MacroAssemblerSparc MacroAssembler; } #else #error "The MacroAssembler is not supported on this platform." #endif - -namespace JSC { - -class MacroAssembler : public MacroAssemblerBase { -public: - - using MacroAssemblerBase::pop; - using MacroAssemblerBase::jump; - using MacroAssemblerBase::branch32; - using MacroAssemblerBase::branch16; -#if WTF_CPU_X86_64 - using MacroAssemblerBase::branchPtr; - using MacroAssemblerBase::branchTestPtr; -#endif - - - // Platform agnostic onvenience functions, - // described in terms of other macro assembly methods. - void pop() - { - addPtr(Imm32(sizeof(void*)), stackPointerRegister); - } - - void peek(RegisterID dest, int index = 0) - { - loadPtr(Address(stackPointerRegister, (index * sizeof(void*))), dest); - } - - void poke(RegisterID src, int index = 0) - { - storePtr(src, Address(stackPointerRegister, (index * sizeof(void*)))); - } - - void poke(TrustedImm32 value, int index = 0) - { - store32(value, Address(stackPointerRegister, (index * sizeof(void*)))); - } - - void poke(TrustedImmPtr imm, int index = 0) - { - storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*)))); - } - - - // Backwards banches, these are currently all implemented using existing forwards branch mechanisms. - void branchPtr(Condition cond, RegisterID op1, ImmPtr imm, Label target) - { - branchPtr(cond, op1, imm).linkTo(target, this); - } - - void branch32(Condition cond, RegisterID op1, RegisterID op2, Label target) - { - branch32(cond, op1, op2).linkTo(target, this); - } - - void branch32(Condition cond, RegisterID op1, TrustedImm32 imm, Label target) - { - branch32(cond, op1, imm).linkTo(target, this); - } - - void branch32(Condition cond, RegisterID left, Address right, Label target) - { - branch32(cond, left, right).linkTo(target, this); - } - - void branch16(Condition cond, BaseIndex left, RegisterID right, Label target) - { - branch16(cond, left, right).linkTo(target, this); - } - - void branchTestPtr(Condition cond, RegisterID reg, Label target) - { - branchTestPtr(cond, reg).linkTo(target, this); - } - - void jump(Label target) - { - jump().linkTo(target, this); - } - - - // Ptr methods - // On 32-bit platforms (i.e. x86), these methods directly map onto their 32-bit equivalents. - // FIXME: should this use a test for 32-bitness instead of this specific exception? -#if !WTF_CPU_X86_64 - void addPtr(RegisterID src, RegisterID dest) - { - add32(src, dest); - } - - void addPtr(Imm32 imm32, Address address) - { - add32(imm32, address); - } - - void addPtr(Imm32 imm, RegisterID srcDest) - { - add32(imm, srcDest); - } - - void addPtr(ImmPtr imm, RegisterID dest) - { - add32(Imm32(imm), dest); - } - - void addPtr(Imm32 imm, RegisterID src, RegisterID dest) - { - add32(imm, src, dest); - } - - void andPtr(RegisterID src, RegisterID dest) - { - and32(src, dest); - } - - void andPtr(Imm32 imm, RegisterID srcDest) - { - and32(imm, srcDest); - } - - void andPtr(ImmPtr ptr, RegisterID srcDest) - { - and32(Imm32(ptr), srcDest); - } - - void negPtr(RegisterID srcDest) - { - neg32(srcDest); - } - - void notPtr(RegisterID srcDest) - { - not32(srcDest); - } - - void orPtr(RegisterID src, RegisterID dest) - { - or32(src, dest); - } - - void orPtr(ImmPtr imm, RegisterID dest) - { - or32(Imm32(imm), dest); - } - - void orPtr(Imm32 imm, RegisterID dest) - { - or32(imm, dest); - } - - void subPtr(RegisterID src, RegisterID dest) - { - sub32(src, dest); - } - - void subPtr(Imm32 imm, RegisterID dest) - { - sub32(imm, dest); - } - - void subPtr(ImmPtr imm, RegisterID dest) - { - sub32(Imm32(imm), dest); - } - - void subPtr(ImmPtr imm, Address address) - { - sub32(Imm32(imm), address); - } - - void xorPtr(RegisterID src, RegisterID dest) - { - xor32(src, dest); - } - - void xorPtr(Imm32 imm, RegisterID srcDest) - { - xor32(imm, srcDest); - } - - - void loadPtr(ImplicitAddress address, RegisterID dest) - { - load32(address, dest); - } - - void loadPtr(BaseIndex address, RegisterID dest) - { - load32(address, dest); - } - - void loadPtr(void* address, RegisterID dest) - { - load32(address, dest); - } - - DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest) - { - return load32WithAddressOffsetPatch(address, dest); - } - - void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - set32(cond, left, right, dest); - } - - void storePtr(RegisterID src, ImplicitAddress address) - { - store32(src, address); - } - - void storePtr(RegisterID src, void* address) - { - store32(src, address); - } - - void storePtr(TrustedImmPtr imm, ImplicitAddress address) - { - store32(Imm32(imm), address); - } - - void storePtr(TrustedImmPtr imm, BaseIndex address) - { - store32(Imm32(imm), address); - } - - void storePtr(TrustedImmPtr imm, void* address) - { - store32(Imm32(imm), address); - } - - DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address) - { - return store32WithAddressOffsetPatch(src, address); - } - - - Jump branchPtr(Condition cond, RegisterID left, RegisterID right) - { - return branch32(cond, left, right); - } - - Jump branchPtr(Condition cond, RegisterID left, ImmPtr right) - { - return branch32(cond, left, Imm32(right)); - } - - Jump branchPtr(Condition cond, RegisterID left, Imm32 right) - { - return branch32(cond, left, right); - } - - Jump branchPtr(Condition cond, RegisterID left, Address right) - { - return branch32(cond, left, right); - } - - Jump branchPtr(Condition cond, Address left, RegisterID right) - { - return branch32(cond, left, right); - } - - Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right) - { - return branch32(cond, left, right); - } - - Jump branchPtr(Condition cond, Address left, ImmPtr right) - { - return branch32(cond, left, Imm32(right)); - } - - Jump branchPtr(Condition cond, AbsoluteAddress left, ImmPtr right, RegisterID scratch) - { - return branch32(cond, left, Imm32(right)); - } - - Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask) - { - return branchTest32(cond, reg, mask); - } - - Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - return branchTest32(cond, reg, mask); - } - - Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - return branchTest32(cond, address, mask); - } - - Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - return branchTest32(cond, address, mask); - } - - - Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest) - { - return branchAdd32(cond, src, dest); - } - - Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest) - { - return branchSub32(cond, imm, dest); - } - - using MacroAssemblerBase::branchTest8; - Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1)) - { - return MacroAssemblerBase::branchTest8(cond, Address(address.base, address.offset), mask); - } - - void rshiftPtr(Imm32 imm, RegisterID dest) - { - rshift32(imm, dest); - } - - void lshiftPtr(Imm32 imm, RegisterID dest) - { - lshift32(imm, dest); - } -#endif - -}; - -} // namespace JSC - #endif // ENABLE(ASSEMBLER) #endif /* assembler_assembler_MacroAssembler_h */ diff --git a/js/src/assembler/assembler/MacroAssemblerARM.cpp b/js/src/assembler/assembler/MacroAssemblerARM.cpp index 73336e9b9cc..91c5591d2e8 100644 --- a/js/src/assembler/assembler/MacroAssemblerARM.cpp +++ b/js/src/assembler/assembler/MacroAssemblerARM.cpp @@ -40,6 +40,7 @@ #include #include #include +#include // lame check for kernel version // see bug 586550 @@ -94,34 +95,6 @@ static bool isVFPPresent() const bool MacroAssemblerARM::s_isVFPPresent = isVFPPresent(); -#if WTF_CPU_ARMV5_OR_LOWER -/* On ARMv5 and below, natural alignment is required. */ -void MacroAssemblerARM::load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) -{ - ARMWord op2; - - ASSERT(address.scale >= 0 && address.scale <= 3); - op2 = m_assembler.lsl(address.index, static_cast(address.scale)); - - if (address.offset >= 0 && address.offset + 0x2 <= 0xff) { - m_assembler.add_r(ARMRegisters::S0, address.base, op2); - m_assembler.ldrh_u(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset)); - m_assembler.ldrh_u(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset + 0x2)); - } else if (address.offset < 0 && address.offset >= -0xff) { - m_assembler.add_r(ARMRegisters::S0, address.base, op2); - m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset)); - m_assembler.ldrh_d(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset - 0x2)); - } else { - m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset); - m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, op2); - m_assembler.ldrh_r(dest, address.base, ARMRegisters::S0); - m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::OP2_IMM | 0x2); - m_assembler.ldrh_r(ARMRegisters::S0, address.base, ARMRegisters::S0); - } - m_assembler.orr_r(dest, dest, m_assembler.lsl(ARMRegisters::S0, 16)); -} -#endif - } #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) diff --git a/js/src/assembler/assembler/MacroAssemblerARM.h b/js/src/assembler/assembler/MacroAssemblerARM.h index 75cfd1ed151..d46047706d8 100644 --- a/js/src/assembler/assembler/MacroAssemblerARM.h +++ b/js/src/assembler/assembler/MacroAssemblerARM.h @@ -36,1505 +36,11 @@ #if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL -#include "assembler/assembler/ARMAssembler.h" -#include "assembler/assembler/AbstractMacroAssembler.h" - namespace JSC { -class MacroAssemblerARM : public AbstractMacroAssembler { - static const int DoubleConditionMask = 0x0f; - static const int DoubleConditionBitSpecial = 0x8; +class MacroAssemblerARM { public: - enum Condition { - Equal = ARMAssembler::EQ, - NotEqual = ARMAssembler::NE, - Above = ARMAssembler::HI, - AboveOrEqual = ARMAssembler::CS, - Below = ARMAssembler::CC, - BelowOrEqual = ARMAssembler::LS, - GreaterThan = ARMAssembler::GT, - GreaterThanOrEqual = ARMAssembler::GE, - LessThan = ARMAssembler::LT, - LessThanOrEqual = ARMAssembler::LE, - Overflow = ARMAssembler::VS, - Signed = ARMAssembler::MI, - Zero = ARMAssembler::EQ, - NonZero = ARMAssembler::NE - }; - - enum DoubleCondition { - // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. - DoubleEqual = ARMAssembler::EQ, - DoubleNotEqual = ARMAssembler::NE | DoubleConditionBitSpecial, - DoubleGreaterThan = ARMAssembler::GT, - DoubleGreaterThanOrEqual = ARMAssembler::GE, - DoubleLessThan = ARMAssembler::CC, - DoubleLessThanOrEqual = ARMAssembler::LS, - // If either operand is NaN, these conditions always evaluate to true. - DoubleEqualOrUnordered = ARMAssembler::EQ | DoubleConditionBitSpecial, - DoubleNotEqualOrUnordered = ARMAssembler::NE, - DoubleGreaterThanOrUnordered = ARMAssembler::HI, - DoubleGreaterThanOrEqualOrUnordered = ARMAssembler::CS, - DoubleLessThanOrUnordered = ARMAssembler::LT, - DoubleLessThanOrEqualOrUnordered = ARMAssembler::LE - }; - - static const RegisterID stackPointerRegister = ARMRegisters::sp; - static const RegisterID linkRegister = ARMRegisters::lr; - - static const Scale ScalePtr = TimesFour; - static const unsigned int TotalRegisters = 16; - - void add32(RegisterID src, RegisterID dest) - { - m_assembler.adds_r(dest, dest, src); - } - - void add32(TrustedImm32 imm, Address address) - { - load32(address, ARMRegisters::S1); - add32(imm, ARMRegisters::S1); - store32(ARMRegisters::S1, address); - } - - void add32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); - } - - void add32(Address src, RegisterID dest) - { - load32(src, ARMRegisters::S1); - add32(ARMRegisters::S1, dest); - } - - void and32(Address src, RegisterID dest) - { - load32(src, ARMRegisters::S1); - and32(ARMRegisters::S1, dest); - } - - void and32(RegisterID src, RegisterID dest) - { - m_assembler.ands_r(dest, dest, src); - } - - void and32(Imm32 imm, RegisterID dest) - { - ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); - if (w & ARMAssembler::OP2_INV_IMM) - m_assembler.bics_r(dest, dest, w & ~ARMAssembler::OP2_INV_IMM); - else - m_assembler.ands_r(dest, dest, w); - } - - void lshift32(RegisterID shift_amount, RegisterID dest) - { - ARMWord w = ARMAssembler::getOp2(0x1f); - ASSERT(w != ARMAssembler::INVALID_IMM); - m_assembler.and_r(ARMRegisters::S0, shift_amount, w); - - m_assembler.movs_r(dest, m_assembler.lsl_r(dest, ARMRegisters::S0)); - } - - void lshift32(Imm32 imm, RegisterID dest) - { - m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); - } - - void mul32(RegisterID src, RegisterID dest) - { - if (src == dest) { - move(src, ARMRegisters::S0); - src = ARMRegisters::S0; - } - m_assembler.muls_r(dest, dest, src); - } - - void mul32(Imm32 imm, RegisterID src, RegisterID dest) - { - move(imm, ARMRegisters::S0); - m_assembler.muls_r(dest, src, ARMRegisters::S0); - } - - void neg32(RegisterID srcDest) - { - m_assembler.rsbs_r(srcDest, srcDest, ARMAssembler::getOp2(0)); - } - - void not32(RegisterID dest) - { - m_assembler.mvns_r(dest, dest); - } - - void or32(RegisterID src, RegisterID dest) - { - m_assembler.orrs_r(dest, dest, src); - } - - void or32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); - } - - void rshift32(RegisterID shift_amount, RegisterID dest) - { - ARMWord w = ARMAssembler::getOp2(0x1f); - ASSERT(w != ARMAssembler::INVALID_IMM); - m_assembler.and_r(ARMRegisters::S0, shift_amount, w); - - m_assembler.movs_r(dest, m_assembler.asr_r(dest, ARMRegisters::S0)); - } - - void rshift32(Imm32 imm, RegisterID dest) - { - m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f)); - } - - void urshift32(RegisterID shift_amount, RegisterID dest) - { - ARMWord w = ARMAssembler::getOp2(0x1f); - ASSERT(w != ARMAssembler::INVALID_IMM); - m_assembler.and_r(ARMRegisters::S0, shift_amount, w); - - m_assembler.movs_r(dest, m_assembler.lsr_r(dest, ARMRegisters::S0)); - } - - void urshift32(Imm32 imm, RegisterID dest) - { - m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f)); - } - - void sub32(RegisterID src, RegisterID dest) - { - m_assembler.subs_r(dest, dest, src); - } - - void sub32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); - } - - void sub32(TrustedImm32 imm, Address address) - { - load32(address, ARMRegisters::S1); - sub32(imm, ARMRegisters::S1); - store32(ARMRegisters::S1, address); - } - - void sub32(Address src, RegisterID dest) - { - load32(src, ARMRegisters::S1); - sub32(ARMRegisters::S1, dest); - } - - void or32(Address address, RegisterID dest) - { - load32(address, ARMRegisters::S1); - or32(ARMRegisters::S1, dest); - } - - void xor32(RegisterID src, RegisterID dest) - { - m_assembler.eors_r(dest, dest, src); - } - - void xor32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); - } - - void xor32(Address src, RegisterID dest) - { - load32(src, ARMRegisters::S1); - m_assembler.eors_r(dest, dest, ARMRegisters::S1); - } - - void load8(BaseIndex address, RegisterID dest) - { - load8ZeroExtend(address, dest); - } - - void load8SignExtend(ImplicitAddress address, RegisterID dest) - { - m_assembler.dataTransferN(true, true, 8, dest, address.base, address.offset); - } - - void load8ZeroExtend(ImplicitAddress address, RegisterID dest) - { - m_assembler.dataTransferN(true, false, 8, dest, address.base, address.offset); - } - - void load8SignExtend(BaseIndex address, RegisterID dest) - { - m_assembler.baseIndexTransferN(true, true, 8, dest, - address.base, address.index, address.scale, address.offset); - } - - void load8ZeroExtend(BaseIndex address, RegisterID dest) - { - m_assembler.baseIndexTransferN(true, false, 8, dest, - address.base, address.index, address.scale, address.offset); - } - - /* this is *identical* to the zero extending case*/ - void load8(ImplicitAddress address, RegisterID dest) - { - load8ZeroExtend(address, dest); - } - - void load16Unaligned(BaseIndex address, RegisterID dest) - { - load16(address, dest); - } - - void load16SignExtend(ImplicitAddress address, RegisterID dest) - { - m_assembler.dataTransferN(true, true, 16, dest, address.base, address.offset); - } - - void load16ZeroExtend(ImplicitAddress address, RegisterID dest) - { - m_assembler.dataTransferN(true, false, 16, dest, address.base, address.offset); - } - void load16SignExtend(BaseIndex address, RegisterID dest) - { - m_assembler.baseIndexTransferN(true, true, 16, dest, - address.base, address.index, address.scale, address.offset); - } - void load16ZeroExtend(BaseIndex address, RegisterID dest) - { - m_assembler.baseIndexTransferN(true, false, 16, dest, - address.base, address.index, address.scale, address.offset); - } - - void load32(ImplicitAddress address, RegisterID dest) - { - m_assembler.dataTransfer32(true, dest, address.base, address.offset); - } - - void load32(BaseIndex address, RegisterID dest) - { - m_assembler.baseIndexTransfer32(true, dest, address.base, address.index, static_cast(address.scale), address.offset); - } - -#if WTF_CPU_ARMV5_OR_LOWER - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest); -#else - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) - { - load32(address, dest); - } -#endif - - DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) - { - ASSERT(address.base != ARMRegisters::S0); - DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARMRegisters::S0, 0); - m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0); - return dataLabel; - } - - DataLabel32 load64WithAddressOffsetPatch(Address address, RegisterID hi, RegisterID lo) - { - ASSERT(address.base != ARMRegisters::S0); - ASSERT(lo != ARMRegisters::S0); - DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARMRegisters::S0, 0); - m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base); - m_assembler.dtr_u(true, lo, ARMRegisters::S0, 0); - m_assembler.dtr_u(true, hi, ARMRegisters::S0, 4); - return dataLabel; - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - Label label(this); - load32(address, dest); - return label; - } - - void load16(BaseIndex address, RegisterID dest) - { - m_assembler.add_r(ARMRegisters::S1, address.base, m_assembler.lsl(address.index, address.scale)); - load16(Address(ARMRegisters::S1, address.offset), dest); - } - - void load16(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= 0) - m_assembler.ldrh_u(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(address.offset, ARMRegisters::S0)); - else - m_assembler.ldrh_d(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(-address.offset, ARMRegisters::S0)); - } - - DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) - { - ASSERT(address.base != ARMRegisters::S0); - DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARMRegisters::S0, 0); - m_assembler.dtr_ur(false, src, address.base, ARMRegisters::S0); - return dataLabel; - } - - DataLabel32 store64WithAddressOffsetPatch(RegisterID hi, RegisterID lo, Address address) - { - ASSERT(hi != ARMRegisters::S0); - ASSERT(lo != ARMRegisters::S0); - ASSERT(address.base != ARMRegisters::S0); - DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset); - m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base); - m_assembler.dtr_u(false, lo, ARMRegisters::S0, 0); - m_assembler.dtr_u(false, hi, ARMRegisters::S0, 4); - return dataLabel; - } - - DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, RegisterID lo, Address address) - { - ASSERT(lo != ARMRegisters::S0); - ASSERT(lo != ARMRegisters::S1); - ASSERT(lo != address.base); - ASSERT(address.base != ARMRegisters::S0); - ASSERT(address.base != ARMRegisters::S1); - DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset); - m_assembler.moveImm(hi.m_value, ARMRegisters::S1); - m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base); - m_assembler.dtr_u(false, lo, ARMRegisters::S0, 0); - m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 4); - return dataLabel; - } - - DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, Imm32 lo, Address address) - { - ASSERT(address.base != ARMRegisters::S0); - ASSERT(address.base != ARMRegisters::S1); - DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset); - m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base); - m_assembler.moveImm(lo.m_value, ARMRegisters::S1); - m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); - /* TODO: improve this by getting another scratch register. */ - m_assembler.moveImm(hi.m_value, ARMRegisters::S1); - m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 4); - return dataLabel; - } - - void store32(RegisterID src, ImplicitAddress address) - { - m_assembler.dataTransfer32(false, src, address.base, address.offset); - } - - void store32(RegisterID src, BaseIndex address) - { - m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast(address.scale), address.offset); - } - - void store32(TrustedImm32 imm, BaseIndex address) - { - if (imm.m_isPointer) - m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); - else - move(imm, ARMRegisters::S1); - store32(ARMRegisters::S1, address); - } - - void store32(TrustedImm32 imm, ImplicitAddress address) - { - if (imm.m_isPointer) - m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); - else - move(imm, ARMRegisters::S1); - store32(ARMRegisters::S1, address); - } - - void store32(RegisterID src, void* address) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); - m_assembler.dtr_u(false, src, ARMRegisters::S0, 0); - } - - void store32(TrustedImm32 imm, void* address) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); - if (imm.m_isPointer) - m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); - else - m_assembler.moveImm(imm.m_value, ARMRegisters::S1); - m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); - } - - void store16(RegisterID src, ImplicitAddress address) - { - m_assembler.dataTransferN(false, false, 16, src, address.base, address.offset); - } - void store16(RegisterID src, BaseIndex address) - { - m_assembler.baseIndexTransferN(false, false, 16, src, address.base, address.index, static_cast(address.scale), address.offset); - } - - void store16(TrustedImm32 imm, BaseIndex address) - { - if (imm.m_isPointer) - MOZ_ASSUME_UNREACHABLE("What are you trying to do with 16 bits of a pointer?"); - else - move(imm, ARMRegisters::S1); - store16(ARMRegisters::S1, address); - } - void store16(TrustedImm32 imm, ImplicitAddress address) - { - if (imm.m_isPointer) - MOZ_ASSUME_UNREACHABLE("What are you trying to do with 16 bits of a pointer?"); - else - move(imm, ARMRegisters::S1); - store16(ARMRegisters::S1, address); - } - - void store16(RegisterID src, void* address) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); - m_assembler.mem_imm_off(false, false, 16, true, src, ARMRegisters::S0, 0); - } - - void store16(TrustedImm32 imm, void* address) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); - if (imm.m_isPointer) - MOZ_ASSUME_UNREACHABLE("What are you trying to do with 16 bits of a pointer?"); - else - m_assembler.moveImm(imm.m_value, ARMRegisters::S1); - m_assembler.mem_imm_off(false, false, 16, true, ARMRegisters::S1, ARMRegisters::S0, 0); - } - - void store8(RegisterID src, ImplicitAddress address) - { - m_assembler.dataTransferN(false, false, 8, src, address.base, address.offset); - } - - void store8(RegisterID src, BaseIndex address) - { - m_assembler.baseIndexTransferN(false, false, 8, src, address.base, address.index, static_cast(address.scale), address.offset); - } - - void store8(TrustedImm32 imm, BaseIndex address) - { - if (imm.m_isPointer) - MOZ_ASSUME_UNREACHABLE("What are you trying to do with 8 bits of a pointer?"); - else - move(imm, ARMRegisters::S1); - store8(ARMRegisters::S1, address); - } - - void store8(TrustedImm32 imm, ImplicitAddress address) - { - if (imm.m_isPointer) - MOZ_ASSUME_UNREACHABLE("What are you trying to do with 16 bits of a pointer?"); - else - move(imm, ARMRegisters::S1); - store8(ARMRegisters::S1, address); - } - - void store8(RegisterID src, void* address) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); - m_assembler.mem_imm_off(false, false, 8, true, src, ARMRegisters::S0, 0); - } - - void store8(TrustedImm32 imm, void* address) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); - if (imm.m_isPointer) - MOZ_ASSUME_UNREACHABLE("What are you trying to do with 16 bits of a pointer?"); - else - m_assembler.moveImm(imm.m_value, ARMRegisters::S1); - m_assembler.mem_imm_off(false, false, 8, true, ARMRegisters::S1, ARMRegisters::S0, 0); - } - - void pop(RegisterID dest) - { - m_assembler.pop_r(dest); - } - - void push(RegisterID src) - { - m_assembler.push_r(src); - } - - void push(Address address) - { - load32(address, ARMRegisters::S1); - push(ARMRegisters::S1); - } - - void push(Imm32 imm) - { - move(imm, ARMRegisters::S0); - push(ARMRegisters::S0); - } - - void move(TrustedImm32 imm, RegisterID dest) - { - if (imm.m_isPointer) - m_assembler.ldr_un_imm(dest, imm.m_value); - else - m_assembler.moveImm(imm.m_value, dest); - } - - void move(RegisterID src, RegisterID dest) - { - m_assembler.mov_r(dest, src); - } - - void move(TrustedImmPtr imm, RegisterID dest) - { - move(Imm32(imm), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - m_assembler.mov_r(ARMRegisters::S0, reg1); - m_assembler.mov_r(reg1, reg2); - m_assembler.mov_r(reg2, ARMRegisters::S0); - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest) - move(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest) - move(src, dest); - } - - Jump branch8(Condition cond, Address left, Imm32 right) - { - load8(left, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0) - { - m_assembler.cmp_r(left, right); - return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); - } - - Jump branch32(Condition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0) - { - ASSERT(left != ARMRegisters::S0); - if (right.m_isPointer) { - m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value); - m_assembler.cmp_r(left, ARMRegisters::S0); - } else { - // This is a rather cute (if not confusing) pattern. - // unfortunately, it is not quite conducive to switching from - // cmp to cmn, so I'm doing so manually. - // m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); - - // try to shoehorn the immediate into the compare instruction - ARMWord arg = m_assembler.getOp2(right.m_value); - if (arg != m_assembler.INVALID_IMM) { - m_assembler.cmp_r(left, arg); - } else { - // if it does not fit, try to shoehorn a negative in, and use a negated compare - // p.s. why couldn't arm just include the sign bit in the imm, rather than the inst. - arg = m_assembler.getOp2(-right.m_value); - if (arg != m_assembler.INVALID_IMM) { - m_assembler.cmn_r(left, arg); - } else { - // If we get here, we *need* to use a temp register and any way of loading a value - // will enable us to load a negative easily, so there is no reason to switch from - // cmp to cmn. - m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); - } - } - } - return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); - } - - // Like branch32, but emit a consistently-structured sequence such that the - // number of instructions emitted is constant, regardless of the argument - // values. For ARM, this is identical to branch32WithPatch, except that it - // does not generate a DataLabel32. - Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right) - { - m_assembler.ldr_un_imm(ARMRegisters::S1, right.m_value); - return branch32(cond, left, ARMRegisters::S1, true); - } - - // As branch32_force32, but allow the value ('right') to be patched. - Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel) - { - ASSERT(left != ARMRegisters::S1); - dataLabel = moveWithPatch(right, ARMRegisters::S1); - return branch32(cond, left, ARMRegisters::S1, true); - } - - Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel) - { - ASSERT(left.base != ARMRegisters::S1); - load32(left, ARMRegisters::S1); - dataLabel = moveWithPatch(right, ARMRegisters::S0); - return branch32(cond, ARMRegisters::S1, ARMRegisters::S0, true); - } - - Jump branch32(Condition cond, RegisterID left, Address right) - { - /*If the load only takes a single instruction, then we could just do a load into*/ - load32(right, ARMRegisters::S1); - return branch32(cond, left, ARMRegisters::S1); - } - - Jump branch32(Condition cond, Address left, RegisterID right) - { - load32(left, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch32(Condition cond, Address left, TrustedImm32 right) - { - load32(left, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right) - { - load32(left, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right) - { - load32WithUnalignedHalfWords(left, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch16(Condition cond, BaseIndex left, RegisterID right) - { - (void)(cond); - (void)(left); - (void)(right); - ASSERT_NOT_REACHED(); - return jump(); - } - - Jump branch16(Condition cond, BaseIndex left, Imm32 right) - { - load16(left, ARMRegisters::S0); - move(right, ARMRegisters::S1); - m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S1); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - load8(address, ARMRegisters::S1); - return branchTest32(cond, ARMRegisters::S1, mask); - } - - Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) - { - ASSERT((cond == Zero) || (cond == NonZero)); - m_assembler.tst_r(reg, mask); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true); - if (w & ARMAssembler::OP2_INV_IMM) - m_assembler.bics_r(ARMRegisters::S0, reg, w & ~ARMAssembler::OP2_INV_IMM); - else - m_assembler.tst_r(reg, w); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - load32(address, ARMRegisters::S1); - return branchTest32(cond, ARMRegisters::S1, mask); - } - - Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - load32(address, ARMRegisters::S1); - return branchTest32(cond, ARMRegisters::S1, mask); - } - - Jump jump() - { - return Jump(m_assembler.jmp()); - } - - void jump(RegisterID target) - { - m_assembler.bx(target); - } - - void jump(Address address) - { - load32(address, ARMRegisters::pc); - } - - Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - add32(imm, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchAdd32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - void mull32(RegisterID src1, RegisterID src2, RegisterID dest) - { - if (src1 == dest) { - move(src1, ARMRegisters::S0); - src1 = ARMRegisters::S0; - } - m_assembler.mull_r(ARMRegisters::S1, dest, src2, src1); - m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31)); - } - - Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Overflow) { - mull32(src, dest, dest); - cond = NonZero; - } - else - mul32(src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Overflow) { - move(imm, ARMRegisters::S0); - mull32(ARMRegisters::S0, src, dest); - cond = NonZero; - } - else - mul32(imm, src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(imm, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchSub32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchSub32(Condition cond, Imm32 imm, Address dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(imm, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchNeg32(Condition cond, RegisterID srcDest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - neg32(srcDest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); - or32(src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - // Encode a NOP using "MOV rX, rX", where 'X' is defined by 'tag', and is - // in the range r0-r14. - void nop(int tag) - { - ASSERT((tag >= 0) && (tag <= 14)); - m_assembler.mov_r(tag, tag); - } - - void breakpoint() - { - m_assembler.bkpt(0); - } - - Call nearCall() - { -#if WTF_ARM_ARCH_VERSION >= 5 - Call call(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true), Call::LinkableNear); - m_assembler.blx(ARMRegisters::S1); - return call; -#else - prepareCall(); - return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear); -#endif - } - - Call call(RegisterID target) - { - m_assembler.blx(target); - JmpSrc jmpSrc; - return Call(jmpSrc, Call::None); - } - - void call(Address address) - { - call32(address.base, address.offset); - } - - void ret() - { - m_assembler.bx(linkRegister); - } - - void set32(Condition cond, Address left, RegisterID right, RegisterID dest) - { - load32(left, ARMRegisters::S1); - set32(cond, ARMRegisters::S1, right, dest); - } - - void set32(Condition cond, RegisterID left, Address right, RegisterID dest) - { - load32(right, ARMRegisters::S1); - set32(cond, left, ARMRegisters::S1, dest); - } - - void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - m_assembler.cmp_r(left, right); - m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); - } - - void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); - } - - void set32(Condition cond, Address left, Imm32 right, RegisterID dest) - { - load32(left, ARMRegisters::S1); - set32(cond, ARMRegisters::S1, right, dest); - } - - void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - // ARM doesn't have byte registers - set32(cond, left, right, dest); - } - - void set8(Condition cond, Address left, RegisterID right, RegisterID dest) - { - // ARM doesn't have byte registers - load32(left, ARMRegisters::S1); - set32(cond, ARMRegisters::S1, right, dest); - } - - void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - // ARM doesn't have byte registers - set32(cond, left, right, dest); - } - - void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - load32(address, ARMRegisters::S1); - if (mask.m_value == -1) - m_assembler.cmp_r(0, ARMRegisters::S1); - else - m_assembler.tst_r(ARMRegisters::S1, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); - } - - void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - // ARM doesn't have byte registers - setTest32(cond, address, mask, dest); - } - - void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) - { - m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); - } - - void lea(Address address, RegisterID dest) - { - m_assembler.add_r(dest, address.base, m_assembler.getImm(address.offset, ARMRegisters::S0)); - } - - void lea(BaseIndex address, RegisterID dest) - { - /* This could be better? */ - move(address.index, ARMRegisters::S1); - if (address.scale != 0) - lshift32(Imm32(address.scale), ARMRegisters::S1); - if (address.offset) - add32(Imm32(address.offset), ARMRegisters::S1); - add32(address.base, ARMRegisters::S1); - move(ARMRegisters::S1, dest); - } - - void add32(TrustedImm32 imm, AbsoluteAddress address) - { - m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr)); - m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); - add32(imm, ARMRegisters::S1); - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address.m_ptr)); - m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); - } - - void sub32(TrustedImm32 imm, AbsoluteAddress address) - { - m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr)); - m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); - sub32(imm, ARMRegisters::S1); - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address.m_ptr)); - m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); - } - - void load32(const void* address, RegisterID dest) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); - m_assembler.dtr_u(true, dest, ARMRegisters::S0, 0); - } - - Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) - { - load32(left.m_ptr, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right) - { - load32(left.m_ptr, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Call call() - { -#if WTF_ARM_ARCH_VERSION >= 5 - Call call(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true), Call::Linkable); - m_assembler.blx(ARMRegisters::S1); - return call; -#else - prepareCall(); - return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable); -#endif - } - - Call tailRecursiveCall() - { - return Call::fromTailJump(jump()); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - return Call::fromTailJump(oldJump); - } - - DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) - { - DataLabelPtr dataLabel(this); - m_assembler.ldr_un_imm(dest, reinterpret_cast(initialValue.m_value)); - return dataLabel; - } - - DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest) - { - DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(dest, initialValue.m_value); - return dataLabel; - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1); - Jump jump = branch32(cond, left, ARMRegisters::S1, true); - return jump; - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - load32(left, ARMRegisters::S1); - dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0); - Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true); - return jump; - } - - DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) - { - DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1); - store32(ARMRegisters::S1, address); - return dataLabel; - } - - DataLabelPtr storePtrWithPatch(ImplicitAddress address) - { - return storePtrWithPatch(ImmPtr(0), address); - } - - // Floating point operators - static bool supportsFloatingPoint() - { - return s_isVFPPresent; - } - - static bool supportsFloatingPointTruncate() - { - return true; - } - - static bool supportsFloatingPointSqrt() - { - return s_isVFPPresent; - } - - void moveDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fcpyd_r(dest, src); - } - - void loadDouble(ImplicitAddress address, FPRegisterID dest) - { - // Load a double from base+offset. - m_assembler.doubleTransfer(true, dest, address.base, address.offset); - } - - void loadDouble(BaseIndex address, FPRegisterID dest) - { - m_assembler.baseIndexFloatTransfer(true, true, dest, - address.base, address.index, - address.scale, address.offset); - } - - DataLabelPtr loadDouble(const void* address, FPRegisterID dest) - { - DataLabelPtr label = moveWithPatch(ImmPtr(address), ARMRegisters::S0); - m_assembler.doubleTransfer(true, dest, ARMRegisters::S0, 0); - return label; - } - - void fastLoadDouble(RegisterID lo, RegisterID hi, FPRegisterID fpReg) { - m_assembler.vmov64(false, true, lo, hi, fpReg); - } - - void loadFloat(ImplicitAddress address, FPRegisterID dest) - { - ASSERT((address.offset & 0x3) == 0); - // as long as this is a sane mapping, (*2) should just work - m_assembler.floatTransfer(true, floatShadow(dest), address.base, address.offset); - m_assembler.vcvt(m_assembler.FloatReg32, m_assembler.FloatReg64, floatShadow(dest), dest); - } - void loadFloat(BaseIndex address, FPRegisterID dest) - { - FPRegisterID dest_s = floatShadow(dest); - m_assembler.baseIndexFloatTransfer(true, false, dest_s, - address.base, address.index, - address.scale, address.offset); - m_assembler.vcvt(m_assembler.FloatReg32, m_assembler.FloatReg64, dest_s, dest); - } - - DataLabelPtr loadFloat(const void* address, FPRegisterID dest) - { - FPRegisterID dest_s = floatShadow(dest); - DataLabelPtr label = moveWithPatch(ImmPtr(address), ARMRegisters::S0); - m_assembler.fmem_imm_off(true, false, true, dest_s, ARMRegisters::S0, 0); - m_assembler.vcvt(m_assembler.FloatReg32, m_assembler.FloatReg64, dest_s, dest); - return label; - } - - void storeDouble(FPRegisterID src, ImplicitAddress address) - { - // Store a double at base+offset. - m_assembler.doubleTransfer(false, src, address.base, address.offset); - } - - void storeDouble(FPRegisterID src, BaseIndex address) - { - m_assembler.baseIndexFloatTransfer(false, true, src, - address.base, address.index, - address.scale, address.offset); - } - - void storeDouble(ImmDouble imm, Address address) - { - store32(Imm32(imm.u.s.lsb), address); - store32(Imm32(imm.u.s.msb), Address(address.base, address.offset + 4)); - } - - void storeDouble(ImmDouble imm, BaseIndex address) - { - store32(Imm32(imm.u.s.lsb), address); - store32(Imm32(imm.u.s.msb), - BaseIndex(address.base, address.index, address.scale, address.offset + 4)); - } - void fastStoreDouble(FPRegisterID fpReg, RegisterID lo, RegisterID hi) { - m_assembler.vmov64(true, true, lo, hi, fpReg); - } - - // the StoreFloat functions take an FPRegisterID that is really of the corresponding Double register. - // but the double has already been converted into a float - void storeFloat(FPRegisterID src, ImplicitAddress address) - { - m_assembler.floatTransfer(false, floatShadow(src), address.base, address.offset); - } - - void storeFloat(FPRegisterID src, BaseIndex address) - { - m_assembler.baseIndexFloatTransfer(false, false, floatShadow(src), - address.base, address.index, - address.scale, address.offset); - } - void storeFloat(ImmDouble imm, Address address) - { - union { - float f; - uint32_t u32; - } u; - u.f = imm.u.d; - store32(Imm32(u.u32), address); - } - - void storeFloat(ImmDouble imm, BaseIndex address) - { - union { - float f; - uint32_t u32; - } u; - u.f = imm.u.d; - store32(Imm32(u.u32), address); - } - - void addDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.faddd_r(dest, dest, src); - } - - void addDouble(Address src, FPRegisterID dest) - { - loadDouble(src, ARMRegisters::SD0); - addDouble(ARMRegisters::SD0, dest); - } - - void divDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fdivd_r(dest, dest, src); - } - - void divDouble(Address src, FPRegisterID dest) - { - ASSERT_NOT_REACHED(); // Untested - loadDouble(src, ARMRegisters::SD0); - divDouble(ARMRegisters::SD0, dest); - } - - void subDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fsubd_r(dest, dest, src); - } - - void subDouble(Address src, FPRegisterID dest) - { - loadDouble(src, ARMRegisters::SD0); - subDouble(ARMRegisters::SD0, dest); - } - - void mulDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fmuld_r(dest, dest, src); - } - - void mulDouble(Address src, FPRegisterID dest) - { - loadDouble(src, ARMRegisters::SD0); - mulDouble(ARMRegisters::SD0, dest); - } - - void negDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fnegd_r(dest, src); - } - - void absDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fabsd_r(dest, src); - } - - void sqrtDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fsqrtd_r(dest, src); - } - - void convertInt32ToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.fmsr_r(floatShadow(dest), src); - m_assembler.fsitod_r(dest, floatShadow(dest)); - } - - void convertUInt32ToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.fmsr_r(floatShadow(dest), src); - m_assembler.fuitod_r(dest, floatShadow(dest)); - } - - void convertInt32ToDouble(Address src, FPRegisterID dest) - { - // flds does not worth the effort here - load32(src, ARMRegisters::S1); - convertInt32ToDouble(ARMRegisters::S1, dest); - } - - void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) - { - ASSERT_NOT_REACHED(); // Untested - // flds does not worth the effort here - m_assembler.ldr_un_imm(ARMRegisters::S1, (ARMWord)src.m_ptr); - m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); - convertInt32ToDouble(ARMRegisters::S1, dest); - } - - void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vcvt(m_assembler.FloatReg64, m_assembler.FloatReg32, src, floatShadow(dest)); - } - - Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) - { - m_assembler.fcmpd_r(left, right); - m_assembler.fmstat(); - if (cond & DoubleConditionBitSpecial) - m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS); - return Jump(m_assembler.jmp(static_cast(cond & ~DoubleConditionMask))); - } - - // Truncates 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) - { - m_assembler.ftosizd_r(floatShadow(ARMRegisters::SD0), src); - // If FTOSIZD (VCVT.S32.F64) can't fit the result into a 32-bit - // integer, it saturates at INT_MAX or INT_MIN. Testing this is - // probably quicker than testing FPSCR for exception. - m_assembler.fmrs_r(dest, floatShadow(ARMRegisters::SD0)); - m_assembler.cmn_r(dest, ARMAssembler::getOp2(-0x7fffffff)); - m_assembler.cmp_r(dest, ARMAssembler::getOp2(0x80000000), ARMCondition(NonZero)); - return Jump(m_assembler.jmp(ARMCondition(Zero))); - } - - // Convert 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, 0). - void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) - { - m_assembler.ftosid_r(floatShadow(ARMRegisters::SD0), src); - m_assembler.fmrs_r(dest, floatShadow(ARMRegisters::SD0)); - - // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. - m_assembler.fsitod_r(ARMRegisters::SD0, floatShadow(ARMRegisters::SD0)); - failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0)); - - // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0 - failureCases.append(branchTest32(Zero, dest)); - } - - void zeroDouble(FPRegisterID srcDest) - { - m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0)); - convertInt32ToDouble(ARMRegisters::S0, srcDest); - } - - void ensureSpace(int space) - { - m_assembler.ensureSpace(space); - } - - void forceFlushConstantPool() - { - m_assembler.forceFlushConstantPool(); - } - - int flushCount() - { - return m_assembler.flushCount(); - } - -protected: - ARMAssembler::Condition ARMCondition(Condition cond) - { - return static_cast(cond); - } - - void ensureSpace(int insnSpace, int constSpace) - { - m_assembler.ensureSpace(insnSpace, constSpace); - } - - int sizeOfConstantPool() - { - return m_assembler.sizeOfConstantPool(); - } - -#if WTF_ARM_ARCH_VERSION < 5 - void prepareCall() - { -#if WTF_ARM_ARCH_VERSION < 5 - ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); - - m_assembler.mov_r(linkRegister, ARMRegisters::pc); -#endif - } -#endif - -#if WTF_ARM_ARCH_VERSION < 5 - void call32(RegisterID base, int32_t offset) - { -#if WTF_ARM_ARCH_VERSION >= 5 - int targetReg = ARMRegisters::S1; -#else - int targetReg = ARMRegisters::pc; -#endif - int tmpReg = ARMRegisters::S1; - - if (base == ARMRegisters::sp) - offset += 4; - - if (offset >= 0) { - if (offset <= 0xfff) { - prepareCall(); - m_assembler.dtr_u(true, targetReg, base, offset); - } else if (offset <= 0xfffff) { - m_assembler.add_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); - prepareCall(); - m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff); - } else { - ARMWord reg = m_assembler.getImm(offset, tmpReg); - prepareCall(); - m_assembler.dtr_ur(true, targetReg, base, reg); - } - } else { - offset = -offset; - if (offset <= 0xfff) { - prepareCall(); - m_assembler.dtr_d(true, targetReg, base, offset); - } else if (offset <= 0xfffff) { - m_assembler.sub_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); - prepareCall(); - m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff); - } else { - ARMWord reg = m_assembler.getImm(offset, tmpReg); - prepareCall(); - m_assembler.dtr_dr(true, targetReg, base, reg); - } - } -#if WTF_ARM_ARCH_VERSION >= 5 - m_assembler.blx(targetReg); -#endif - } -#else - void call32(RegisterID base, int32_t offset) - { - // TODO: Why is SP special? - if (base == ARMRegisters::sp) - offset += 4; - - // Branch to the address stored in base+offset, using one of the - // following sequences: - // ---- - // LDR ip, [base, ±offset] - // BLX ip - // ---- - // ADD/SUB ip, base, #(offset & 0xff000) - // LDR ip, [ip, #(offset & 0xfff)] - // BLX ip - // ---- - // LDR ip, =offset - // LDR ip, [base, ±ip] - // BLX ip - - if (offset >= 0) { - if (offset <= 0xfff) { - m_assembler.dtr_u(true, ARMRegisters::S0, base, offset); - } else if (offset <= 0xfffff) { - m_assembler.add_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); - m_assembler.dtr_u(true, ARMRegisters::S0, ARMRegisters::S0, offset & 0xfff); - } else { - m_assembler.moveImm(offset, ARMRegisters::S0); - m_assembler.dtr_ur(true, ARMRegisters::S0, base, ARMRegisters::S0); - } - } else { - offset = -offset; - if (offset <= 0xfff) { - m_assembler.dtr_d(true, ARMRegisters::S0, base, offset); - } else if (offset <= 0xfffff) { - m_assembler.sub_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); - m_assembler.dtr_d(true, ARMRegisters::S0, ARMRegisters::S0, offset & 0xfff); - } else { - m_assembler.moveImm(offset, ARMRegisters::S0); - m_assembler.dtr_dr(true, ARMRegisters::S0, base, ARMRegisters::S0); - } - } - m_assembler.blx(ARMRegisters::S0); - } -#endif - -private: - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - ARMAssembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - + static bool supportsFloatingPoint() { return s_isVFPPresent; } static const bool s_isVFPPresent; }; diff --git a/js/src/assembler/assembler/MacroAssemblerARMv7.h b/js/src/assembler/assembler/MacroAssemblerARMv7.h index 8da41765c3e..881e4bd64e9 100644 --- a/js/src/assembler/assembler/MacroAssemblerARMv7.h +++ b/js/src/assembler/assembler/MacroAssemblerARMv7.h @@ -35,1184 +35,11 @@ #if ENABLE(ASSEMBLER) -#include "assembler/assembler/ARMv7Assembler.h" -#include "assembler/assembler/AbstractMacroAssembler.h" - namespace JSC { -class MacroAssemblerARMv7 : public AbstractMacroAssembler { - // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7? - // - dTR is likely used more than aTR, and we'll get better instruction - // encoding if it's in the low 8 registers. - static const ARMRegisters::RegisterID dataTempRegister = ARMRegisters::ip; - static const RegisterID addressTempRegister = ARMRegisters::r3; - static const FPRegisterID fpTempRegister = ARMRegisters::d7; - static const unsigned int TotalRegisters = 16; - - struct ArmAddress { - enum AddressType { - HasOffset, - HasIndex - } type; - RegisterID base; - union { - int32_t offset; - struct { - RegisterID index; - Scale scale; - }; - } u; - - explicit ArmAddress(RegisterID base, int32_t offset = 0) - : type(HasOffset) - , base(base) - { - u.offset = offset; - } - - explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne) - : type(HasIndex) - , base(base) - { - u.index = index; - u.scale = scale; - } - }; - +class MacroAssemblerARMv7 { public: - - static const Scale ScalePtr = TimesFour; - - enum Condition { - Equal = ARMv7Assembler::ConditionEQ, - NotEqual = ARMv7Assembler::ConditionNE, - Above = ARMv7Assembler::ConditionHI, - AboveOrEqual = ARMv7Assembler::ConditionHS, - Below = ARMv7Assembler::ConditionLO, - BelowOrEqual = ARMv7Assembler::ConditionLS, - GreaterThan = ARMv7Assembler::ConditionGT, - GreaterThanOrEqual = ARMv7Assembler::ConditionGE, - LessThan = ARMv7Assembler::ConditionLT, - LessThanOrEqual = ARMv7Assembler::ConditionLE, - Overflow = ARMv7Assembler::ConditionVS, - Signed = ARMv7Assembler::ConditionMI, - Zero = ARMv7Assembler::ConditionEQ, - NonZero = ARMv7Assembler::ConditionNE - }; - enum DoubleCondition { - // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. - DoubleEqual = ARMv7Assembler::ConditionEQ, - DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently. - DoubleGreaterThan = ARMv7Assembler::ConditionGT, - DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE, - DoubleLessThan = ARMv7Assembler::ConditionLO, - DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS, - // If either operand is NaN, these conditions always evaluate to true. - DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently. - DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE, - DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI, - DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS, - DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT, - DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE - }; - - static const RegisterID stackPointerRegister = ARMRegisters::sp; - static const RegisterID linkRegister = ARMRegisters::lr; - - // Integer arithmetic operations: - // - // Operations are typically two operand - operation(source, srcDst) - // For many operations the source may be an Imm32, the srcDst operand - // may often be a memory location (explictly described using an Address - // object). - - void add32(RegisterID src, RegisterID dest) - { - m_assembler.add(dest, dest, src); - } - - void add32(TrustedImm32 imm, RegisterID dest) - { - add32(imm, dest, dest); - } - - void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.add(dest, src, armImm); - else { - move(imm, dataTempRegister); - m_assembler.add(dest, src, dataTempRegister); - } - } - - void add32(TrustedImm32 imm, Address address) - { - load32(address, dataTempRegister); - - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.add(dataTempRegister, dataTempRegister, armImm); - else { - // Hrrrm, since dataTempRegister holds the data loaded, - // use addressTempRegister to hold the immediate. - move(imm, addressTempRegister); - m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister); - } - - store32(dataTempRegister, address); - } - - void add32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - add32(dataTempRegister, dest); - } - - void add32(TrustedImm32 imm, AbsoluteAddress address) - { - load32(address.m_ptr, dataTempRegister); - - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.add(dataTempRegister, dataTempRegister, armImm); - else { - // Hrrrm, since dataTempRegister holds the data loaded, - // use addressTempRegister to hold the immediate. - move(imm, addressTempRegister); - m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister); - } - - store32(dataTempRegister, address.m_ptr); - } - - void and32(RegisterID src, RegisterID dest) - { - m_assembler.ARM_and(dest, dest, src); - } - - void and32(Imm32 imm, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.ARM_and(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.ARM_and(dest, dest, dataTempRegister); - } - } - - void lshift32(RegisterID shift_amount, RegisterID dest) - { - // Clamp the shift to the range 0..31 - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); - ASSERT(armImm.isValid()); - m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); - - m_assembler.lsl(dest, dest, dataTempRegister); - } - - void lshift32(Imm32 imm, RegisterID dest) - { - m_assembler.lsl(dest, dest, imm.m_value & 0x1f); - } - - void mul32(RegisterID src, RegisterID dest) - { - m_assembler.smull(dest, dataTempRegister, dest, src); - } - - void mul32(Imm32 imm, RegisterID src, RegisterID dest) - { - move(imm, dataTempRegister); - m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); - } - - void not32(RegisterID srcDest) - { - m_assembler.mvn(srcDest, srcDest); - } - - void or32(RegisterID src, RegisterID dest) - { - m_assembler.orr(dest, dest, src); - } - - void or32(TrustedImm32 imm, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.orr(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.orr(dest, dest, dataTempRegister); - } - } - - void rshift32(RegisterID shift_amount, RegisterID dest) - { - // Clamp the shift to the range 0..31 - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); - ASSERT(armImm.isValid()); - m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); - - m_assembler.asr(dest, dest, dataTempRegister); - } - - void rshift32(Imm32 imm, RegisterID dest) - { - m_assembler.asr(dest, dest, imm.m_value & 0x1f); - } - - void urshift32(RegisterID shift_amount, RegisterID dest) - { - // Clamp the shift to the range 0..31 - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); - ASSERT(armImm.isValid()); - m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); - - m_assembler.lsr(dest, dest, dataTempRegister); - } - - void urshift32(Imm32 imm, RegisterID dest) - { - m_assembler.lsr(dest, dest, imm.m_value & 0x1f); - } - - void sub32(RegisterID src, RegisterID dest) - { - m_assembler.sub(dest, dest, src); - } - - void sub32(TrustedImm32 imm, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.sub(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.sub(dest, dest, dataTempRegister); - } - } - - void sub32(TrustedImm32 imm, Address address) - { - load32(address, dataTempRegister); - - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.sub(dataTempRegister, dataTempRegister, armImm); - else { - // Hrrrm, since dataTempRegister holds the data loaded, - // use addressTempRegister to hold the immediate. - move(imm, addressTempRegister); - m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister); - } - - store32(dataTempRegister, address); - } - - void sub32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - sub32(dataTempRegister, dest); - } - - void sub32(TrustedImm32 imm, AbsoluteAddress address) - { - load32(address.m_ptr, dataTempRegister); - - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.sub(dataTempRegister, dataTempRegister, armImm); - else { - // Hrrrm, since dataTempRegister holds the data loaded, - // use addressTempRegister to hold the immediate. - move(imm, addressTempRegister); - m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister); - } - - store32(dataTempRegister, address.m_ptr); - } - - void xor32(RegisterID src, RegisterID dest) - { - m_assembler.eor(dest, dest, src); - } - - void xor32(TrustedImm32 imm, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.eor(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.eor(dest, dest, dataTempRegister); - } - } - - // Memory access operations: - // - // Loads are of the form load(address, destination) and stores of the form - // store(source, address). The source for a store may be an Imm32. Address - // operand objects to loads and store will be implicitly constructed if a - // register is passed. - -private: - void load32(ArmAddress address, RegisterID dest) - { - if (address.type == ArmAddress::HasIndex) - m_assembler.ldr(dest, address.base, address.u.index, address.u.scale); - else if (address.u.offset >= 0) { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); - ASSERT(armImm.isValid()); - m_assembler.ldr(dest, address.base, armImm); - } else { - ASSERT(address.u.offset >= -255); - m_assembler.ldr(dest, address.base, address.u.offset, true, false); - } - } - - void load16(ArmAddress address, RegisterID dest) - { - if (address.type == ArmAddress::HasIndex) - m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale); - else if (address.u.offset >= 0) { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); - ASSERT(armImm.isValid()); - m_assembler.ldrh(dest, address.base, armImm); - } else { - ASSERT(address.u.offset >= -255); - m_assembler.ldrh(dest, address.base, address.u.offset, true, false); - } - } - - void load8(ArmAddress address, RegisterID dest) - { - if (address.type == ArmAddress::HasIndex) - m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale); - else if (address.u.offset >= 0) { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); - ASSERT(armImm.isValid()); - m_assembler.ldrb(dest, address.base, armImm); - } else { - ASSERT(address.u.offset >= -255); - m_assembler.ldrb(dest, address.base, address.u.offset, true, false); - } - } - - void store32(RegisterID src, ArmAddress address) - { - if (address.type == ArmAddress::HasIndex) - m_assembler.str(src, address.base, address.u.index, address.u.scale); - else if (address.u.offset >= 0) { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); - ASSERT(armImm.isValid()); - m_assembler.str(src, address.base, armImm); - } else { - ASSERT(address.u.offset >= -255); - m_assembler.str(src, address.base, address.u.offset, true, false); - } - } - -public: - void load32(ImplicitAddress address, RegisterID dest) - { - load32(setupArmAddress(address), dest); - } - - void load32(BaseIndex address, RegisterID dest) - { - load32(setupArmAddress(address), dest); - } - - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) - { - load32(setupArmAddress(address), dest); - } - - void load32(const void* address, RegisterID dest) - { - move(ImmPtr(address), addressTempRegister); - m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); - } - - void load8(ImplicitAddress address, RegisterID dest) - { - load8(setupArmAddress(address), dest); - } - - DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) - { - DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister); - load32(ArmAddress(address.base, dataTempRegister), dest); - return label; - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - Label label(this); - moveFixedWidthEncoding(Imm32(address.offset), dataTempRegister); - load32(ArmAddress(address.base, dataTempRegister), dest); - return label; - } - - void load16(BaseIndex address, RegisterID dest) - { - m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale); - } - - void load16(ImplicitAddress address, RegisterID dest) - { - m_assembler.ldrh(dest, address.base, address.offset); - } - - DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) - { - DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister); - store32(src, ArmAddress(address.base, dataTempRegister)); - return label; - } - - void store32(RegisterID src, ImplicitAddress address) - { - store32(src, setupArmAddress(address)); - } - - void store32(RegisterID src, BaseIndex address) - { - store32(src, setupArmAddress(address)); - } - - void store32(TrustedImm32 imm, ImplicitAddress address) - { - move(imm, dataTempRegister); - store32(dataTempRegister, setupArmAddress(address)); - } - - void store32(RegisterID src, void* address) - { - move(ImmPtr(address), addressTempRegister); - m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); - } - - void store32(TrustedImm32 imm, void* address) - { - move(imm, dataTempRegister); - store32(dataTempRegister, address); - } - - - // Floating-point operations: - static bool supportsFloatingPoint() { return true; } - // On x86(_64) the MacroAssembler provides an interface to truncate a double to an integer. - // If a value is not representable as an integer, and possibly for some values that are, - // (on x86 INT_MIN, since this is indistinguishable from results for out-of-range/NaN input) - // a branch will be taken. It is not clear whether this interface will be well suited to - // other platforms. On ARMv7 the hardware truncation operation produces multiple possible - // failure values (saturates to INT_MIN & INT_MAX, NaN reulsts in a value of 0). This is a - // temporary solution while we work out what this interface should be. Either we need to - // decide to make this interface work on all platforms, rework the interface to make it more - // generic, or decide that the MacroAssembler cannot practically be used to abstracted these - // operations, and make clients go directly to the m_assembler to plant truncation instructions. - // In short, FIXME:. - static bool supportsFloatingPointTruncate() { return false; } - - static bool supportsFloatingPointSqrt() - { - return false; - } - - void loadDouble(ImplicitAddress address, FPRegisterID dest) - { - RegisterID base = address.base; - int32_t offset = address.offset; - - // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. - if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { - add32(Imm32(offset), base, addressTempRegister); - base = addressTempRegister; - offset = 0; - } - - m_assembler.vldr(dest, base, offset); - } - - void storeDouble(FPRegisterID src, ImplicitAddress address) - { - RegisterID base = address.base; - int32_t offset = address.offset; - - // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. - if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { - add32(Imm32(offset), base, addressTempRegister); - base = addressTempRegister; - offset = 0; - } - - m_assembler.vstr(src, base, offset); - } - - void addDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vadd_F64(dest, dest, src); - } - - void addDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - addDouble(fpTempRegister, dest); - } - - void subDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vsub_F64(dest, dest, src); - } - - void subDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - subDouble(fpTempRegister, dest); - } - - void mulDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vmul_F64(dest, dest, src); - } - - void mulDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - mulDouble(fpTempRegister, dest); - } - - void sqrtDouble(FPRegisterID, FPRegisterID) - { - ASSERT_NOT_REACHED(); - } - - void convertInt32ToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.vmov(fpTempRegister, src); - m_assembler.vcvt_F64_S32(dest, fpTempRegister); - } - - Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) - { - m_assembler.vcmp_F64(left, right); - m_assembler.vmrs_APSR_nzcv_FPSCR(); - - if (cond == DoubleNotEqual) { - // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump. - Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); - Jump result = makeBranch(ARMv7Assembler::ConditionNE); - unordered.link(this); - return result; - } - if (cond == DoubleEqualOrUnordered) { - Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); - Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE); - unordered.link(this); - // We get here if either unordered, or equal. - Jump result = makeJump(); - notEqual.link(this); - return result; - } - return makeBranch(cond); - } - - Jump branchTruncateDoubleToInt32(FPRegisterID, RegisterID) - { - ASSERT_NOT_REACHED(); - return jump(); - } - - - // Stack manipulation operations: - // - // The ABI is assumed to provide a stack abstraction to memory, - // containing machine word sized units of data. Push and pop - // operations add and remove a single register sized unit of data - // to or from the stack. Peek and poke operations read or write - // values on the stack, without moving the current stack position. - - void pop(RegisterID dest) - { - // store postindexed with writeback - m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true); - } - - void push(RegisterID src) - { - // store preindexed with writeback - m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true); - } - - void push(Address address) - { - load32(address, dataTempRegister); - push(dataTempRegister); - } - - void push(Imm32 imm) - { - move(imm, dataTempRegister); - push(dataTempRegister); - } - - // Register move operations: - // - // Move values in registers. - - void move(TrustedImm32 imm, RegisterID dest) - { - uint32_t value = imm.m_value; - - if (imm.m_isPointer) - moveFixedWidthEncoding(imm, dest); - else { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value); - - if (armImm.isValid()) - m_assembler.mov(dest, armImm); - else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid()) - m_assembler.mvn(dest, armImm); - else { - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value)); - if (value & 0xffff0000) - m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16)); - } - } - } - - void move(RegisterID src, RegisterID dest) - { - m_assembler.mov(dest, src); - } - - void move(TrustedImmPtr imm, RegisterID dest) - { - move(Imm32(imm), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - move(reg1, dataTempRegister); - move(reg2, reg1); - move(dataTempRegister, reg2); - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest) - move(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest) - move(src, dest); - } - - - // Forwards / external control flow operations: - // - // This set of jump and conditional branch operations return a Jump - // object which may linked at a later point, allow forwards jump, - // or jumps that will require external linkage (after the code has been - // relocated). - // - // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge - // respecitvely, for unsigned comparisons the names b, a, be, and ae are - // used (representing the names 'below' and 'above'). - // - // Operands to the comparision are provided in the expected order, e.g. - // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when - // treated as a signed 32bit value, is less than or equal to 5. - // - // jz and jnz test whether the first operand is equal to zero, and take - // an optional second operand of a mask under which to perform the test. -private: - - // Should we be using TEQ for equal/not-equal? - void compare32(RegisterID left, Imm32 right) - { - int32_t imm = right.m_value; - if (!imm) - m_assembler.tst(left, left); - else { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm); - if (armImm.isValid()) - m_assembler.cmp(left, armImm); - if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid()) - m_assembler.cmn(left, armImm); - else { - move(Imm32(imm), dataTempRegister); - m_assembler.cmp(left, dataTempRegister); - } - } - } - - void test32(RegisterID reg, Imm32 mask) - { - int32_t imm = mask.m_value; - - if (imm == -1) - m_assembler.tst(reg, reg); - else { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm); - if (armImm.isValid()) - m_assembler.tst(reg, armImm); - else { - move(mask, dataTempRegister); - m_assembler.tst(reg, dataTempRegister); - } - } - } - -public: - Jump branch32(Condition cond, RegisterID left, RegisterID right) - { - m_assembler.cmp(left, right); - return Jump(makeBranch(cond)); - } - - Jump branch32(Condition cond, RegisterID left, TrustedImm32 right) - { - compare32(left, right); - return Jump(makeBranch(cond)); - } - - Jump branch32(Condition cond, RegisterID left, Address right) - { - load32(right, dataTempRegister); - return branch32(cond, left, dataTempRegister); - } - - Jump branch32(Condition cond, Address left, RegisterID right) - { - load32(left, dataTempRegister); - return branch32(cond, dataTempRegister, right); - } - - Jump branch32(Condition cond, Address left, TrustedImm32 right) - { - // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ - load32(left, addressTempRegister); - return branch32(cond, addressTempRegister, right); - } - - Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right) - { - // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ - load32(left, addressTempRegister); - return branch32(cond, addressTempRegister, right); - } - - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right) - { - // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ - load32WithUnalignedHalfWords(left, addressTempRegister); - return branch32(cond, addressTempRegister, right); - } - - Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) - { - load32(left.m_ptr, dataTempRegister); - return branch32(cond, dataTempRegister, right); - } - - Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right) - { - // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ - load32(left.m_ptr, addressTempRegister); - return branch32(cond, addressTempRegister, right); - } - - Jump branch16(Condition cond, BaseIndex left, RegisterID right) - { - load16(left, dataTempRegister); - m_assembler.lsl(addressTempRegister, right, 16); - m_assembler.lsl(dataTempRegister, dataTempRegister, 16); - return branch32(cond, dataTempRegister, addressTempRegister); - } - - Jump branch16(Condition cond, BaseIndex left, Imm32 right) - { - // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ - load16(left, addressTempRegister); - m_assembler.lsl(addressTempRegister, addressTempRegister, 16); - return branch32(cond, addressTempRegister, Imm32(right.m_value << 16)); - } - - Jump branch8(Condition cond, RegisterID left, Imm32 right) - { - compare32(left, right); - return Jump(makeBranch(cond)); - } - - Jump branch8(Condition cond, Address left, Imm32 right) - { - // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/ - load8(left, addressTempRegister); - return branch8(cond, addressTempRegister, right); - } - - Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) - { - ASSERT((cond == Zero) || (cond == NonZero)); - m_assembler.tst(reg, mask); - return Jump(makeBranch(cond)); - } - - Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - test32(reg, mask); - return Jump(makeBranch(cond)); - } - - Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ - load32(address, addressTempRegister); - return branchTest32(cond, addressTempRegister, mask); - } - - Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ - load32(address, addressTempRegister); - return branchTest32(cond, addressTempRegister, mask); - } - - Jump branchTest8(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - test32(reg, mask); - return Jump(makeBranch(cond)); - } - - Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/ - load8(address, addressTempRegister); - return branchTest8(cond, addressTempRegister, mask); - } - - Jump jump() - { - return Jump(makeJump()); - } - - void jump(RegisterID target) - { - m_assembler.bx(target); - } - - // Address is a memory location containing the address to jump to - void jump(Address address) - { - load32(address, dataTempRegister); - m_assembler.bx(dataTempRegister); - } - - - // Arithmetic control flow operations: - // - // This set of conditional branch operations branch based - // on the result of an arithmetic operation. The operation - // is performed as normal, storing the result. - // - // * jz operations branch if the result is zero. - // * jo operations branch if the (signed) arithmetic - // operation caused an overflow to occur. - - Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - m_assembler.add_S(dest, dest, src); - return Jump(makeBranch(cond)); - } - - Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.add_S(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.add_S(dest, dest, dataTempRegister); - } - return Jump(makeBranch(cond)); - } - - Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT(cond == Overflow); - m_assembler.smull(dest, dataTempRegister, dest, src); - m_assembler.asr(addressTempRegister, dest, 31); - return branch32(NotEqual, addressTempRegister, dataTempRegister); - } - - Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) - { - ASSERT(cond == Overflow); - move(imm, dataTempRegister); - m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); - m_assembler.asr(addressTempRegister, dest, 31); - return branch32(NotEqual, addressTempRegister, dataTempRegister); - } - - Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - m_assembler.sub_S(dest, dest, src); - return Jump(makeBranch(cond)); - } - - Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.sub_S(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.sub_S(dest, dest, dataTempRegister); - } - return Jump(makeBranch(cond)); - } - - - // Miscellaneous operations: - - void breakpoint() - { - m_assembler.bkpt(); - } - - Call nearCall() - { - moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear); - } - - Call call() - { - moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return Call(m_assembler.blx(dataTempRegister), Call::Linkable); - } - - Call call(RegisterID target) - { - return Call(m_assembler.blx(target), Call::None); - } - - Call call(Address address) - { - load32(address, dataTempRegister); - return Call(m_assembler.blx(dataTempRegister), Call::None); - } - - void ret() - { - m_assembler.bx(linkRegister); - } - - void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - m_assembler.cmp(left, right); - m_assembler.it(armV7Condition(cond), false); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); - } - - void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - compare32(left, right); - m_assembler.it(armV7Condition(cond), false); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); - } - - // FIXME: - // The mask should be optional... paerhaps the argument order should be - // dest-src, operations always have a dest? ... possibly not true, considering - // asm ops like test, or pseudo ops like pop(). - void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - load32(address, dataTempRegister); - test32(dataTempRegister, mask); - m_assembler.it(armV7Condition(cond), false); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); - } - - void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - load8(address, dataTempRegister); - test32(dataTempRegister, mask); - m_assembler.it(armV7Condition(cond), false); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); - } - - DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst) - { - moveFixedWidthEncoding(imm, dst); - return DataLabel32(this); - } - - DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst) - { - moveFixedWidthEncoding(Imm32(imm), dst); - return DataLabelPtr(this); - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - dataLabel = moveWithPatch(initialRightValue, dataTempRegister); - return branch32(cond, left, dataTempRegister); - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - load32(left, addressTempRegister); - dataLabel = moveWithPatch(initialRightValue, dataTempRegister); - return branch32(cond, addressTempRegister, dataTempRegister); - } - - DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) - { - DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister); - store32(dataTempRegister, address); - return label; - } - DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(ImmPtr(0), address); } - - - Call tailRecursiveCall() - { - // Like a normal call, but don't link. - moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return Call(m_assembler.bx(dataTempRegister), Call::Linkable); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - oldJump.link(this); - return tailRecursiveCall(); - } - - -protected: - ARMv7Assembler::JmpSrc makeJump() - { - moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return m_assembler.bx(dataTempRegister); - } - - ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond) - { - m_assembler.it(cond, true, true); - moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return m_assembler.bx(dataTempRegister); - } - ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); } - ARMv7Assembler::JmpSrc makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); } - - ArmAddress setupArmAddress(BaseIndex address) - { - if (address.offset) { - ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset); - if (imm.isValid()) - m_assembler.add(addressTempRegister, address.base, imm); - else { - move(Imm32(address.offset), addressTempRegister); - m_assembler.add(addressTempRegister, addressTempRegister, address.base); - } - - return ArmAddress(addressTempRegister, address.index, address.scale); - } else - return ArmAddress(address.base, address.index, address.scale); - } - - ArmAddress setupArmAddress(Address address) - { - if ((address.offset >= -0xff) && (address.offset <= 0xfff)) - return ArmAddress(address.base, address.offset); - - move(Imm32(address.offset), addressTempRegister); - return ArmAddress(address.base, addressTempRegister); - } - - ArmAddress setupArmAddress(ImplicitAddress address) - { - if ((address.offset >= -0xff) && (address.offset <= 0xfff)) - return ArmAddress(address.base, address.offset); - - move(Imm32(address.offset), addressTempRegister); - return ArmAddress(address.base, addressTempRegister); - } - - RegisterID makeBaseIndexBase(BaseIndex address) - { - if (!address.offset) - return address.base; - - ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset); - if (imm.isValid()) - m_assembler.add(addressTempRegister, address.base, imm); - else { - move(Imm32(address.offset), addressTempRegister); - m_assembler.add(addressTempRegister, addressTempRegister, address.base); - } - - return addressTempRegister; - } - - void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst) - { - uint32_t value = imm.m_value; - m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff)); - m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16)); - } - - ARMv7Assembler::Condition armV7Condition(Condition cond) - { - return static_cast(cond); - } - - ARMv7Assembler::Condition armV7Condition(DoubleCondition cond) - { - return static_cast(cond); - } - -private: - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - ARMv7Assembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } }; } // namespace JSC diff --git a/js/src/assembler/assembler/MacroAssemblerCodeRef.h b/js/src/assembler/assembler/MacroAssemblerCodeRef.h deleted file mode 100644 index b6f17ebc68e..00000000000 --- a/js/src/assembler/assembler/MacroAssemblerCodeRef.h +++ /dev/null @@ -1,229 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef assembler_assembler_MacroAssemblerCodeRef_h -#define assembler_assembler_MacroAssemblerCodeRef_h - -#include "assembler/wtf/Assertions.h" -#include "assembler/wtf/Platform.h" -#include "assembler/jit/ExecutableAllocator.h" - -#if ENABLE_ASSEMBLER - -#include "jsutil.h" - -// ASSERT_VALID_CODE_POINTER checks that ptr is a non-null pointer, and that it is a valid -// instruction address on the platform (for example, check any alignment requirements). -#if WTF_CPU_ARM_THUMB2 -// ARM/thumb instructions must be 16-bit aligned, but all code pointers to be loaded -// into the processor are decorated with the bottom bit set, indicating that this is -// thumb code (as oposed to 32-bit traditional ARM). The first test checks for both -// decorated and undectorated null, and the second test ensures that the pointer is -// decorated. -#define ASSERT_VALID_CODE_POINTER(ptr) \ - ASSERT(reinterpret_cast(ptr) & ~1); \ - ASSERT(reinterpret_cast(ptr) & 1) -#define ASSERT_VALID_CODE_OFFSET(offset) \ - ASSERT(!(offset & 1)) // Must be multiple of 2. -#else -#define ASSERT_VALID_CODE_POINTER(ptr) \ - ASSERT(ptr) -#define ASSERT_VALID_CODE_OFFSET(offset) // Anything goes! -#endif - -namespace JSC { - -// FunctionPtr: -// -// FunctionPtr should be used to wrap pointers to C/C++ functions in JSC -// (particularly, the stub functions). -class FunctionPtr { -public: - FunctionPtr() - : m_value(0) - { - } - - template - explicit FunctionPtr(FunctionType* value) -#if WTF_COMPILER_RVCT - // RVTC compiler needs C-style cast as it fails with the following error - // Error: #694: reinterpret_cast cannot cast away const or other type qualifiers - : m_value((void*)(value)) -#else - : m_value(reinterpret_cast(value)) -#endif - { - ASSERT_VALID_CODE_POINTER(m_value); - } - - void* value() const { return m_value; } - void* executableAddress() const { return m_value; } - - -private: - void* m_value; -}; - -// ReturnAddressPtr: -// -// ReturnAddressPtr should be used to wrap return addresses generated by processor -// 'call' instructions exectued in JIT code. We use return addresses to look up -// exception and optimization information, and to repatch the call instruction -// that is the source of the return address. -class ReturnAddressPtr { -public: - ReturnAddressPtr() - : m_value(0) - { - } - - explicit ReturnAddressPtr(void* value) - : m_value(value) - { - ASSERT_VALID_CODE_POINTER(m_value); - } - - explicit ReturnAddressPtr(FunctionPtr function) - : m_value(function.value()) - { - ASSERT_VALID_CODE_POINTER(m_value); - } - - void* value() const { return m_value; } - -private: - void* m_value; -}; - -// MacroAssemblerCodePtr: -// -// MacroAssemblerCodePtr should be used to wrap pointers to JIT generated code. -class MacroAssemblerCodePtr { -public: - MacroAssemblerCodePtr() - : m_value(0) - { - } - - explicit MacroAssemblerCodePtr(void* value) -#if WTF_CPU_ARM_THUMB2 - // Decorate the pointer as a thumb code pointer. - : m_value(reinterpret_cast(value) + 1) -#else - : m_value(value) -#endif - { - ASSERT_VALID_CODE_POINTER(m_value); - } - - explicit MacroAssemblerCodePtr(ReturnAddressPtr ra) - : m_value(ra.value()) - { - ASSERT_VALID_CODE_POINTER(m_value); - } - - void* executableAddress() const { - return m_value; - } -#if WTF_CPU_ARM_THUMB2 - // To use this pointer as a data address remove the decoration. - void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return reinterpret_cast(m_value) - 1; } -#else - void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return m_value; } -#endif - - bool operator!() const - { - return !m_value; - } - - ptrdiff_t operator -(const MacroAssemblerCodePtr &other) const - { - JS_ASSERT(m_value); - return reinterpret_cast(m_value) - - reinterpret_cast(other.m_value); - } - -private: - void* m_value; -}; - -// MacroAssemblerCodeRef: -// -// A reference to a section of JIT generated code. A CodeRef consists of a -// pointer to the code, and a ref pointer to the pool from within which it -// was allocated. -class MacroAssemblerCodeRef { -public: - MacroAssemblerCodeRef() - : m_executablePool(NULL), - m_allocSize(0) - { - } - - MacroAssemblerCodeRef(void* code, ExecutablePool* executablePool, size_t allocSize) - : m_code(code) - , m_executablePool(executablePool) - , m_allocSize(allocSize) - { - } - - // Release the code memory in this code ref. - void release() - { - if (!m_executablePool) - return; - - JS_POISON(m_code.executableAddress(), JS_SWEPT_CODE_PATTERN, m_allocSize); - - m_code = MacroAssemblerCodePtr(); - - // MacroAssemblerCodeRef is only used by Yarr. - m_executablePool->release(m_allocSize, REGEXP_CODE); - m_executablePool = nullptr; - } - - MacroAssemblerCodePtr code() const { - return m_code; - } - size_t allocSize() const { - return m_allocSize; - } - - MacroAssemblerCodePtr m_code; - ExecutablePool* m_executablePool; - size_t m_allocSize; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif /* assembler_assembler_MacroAssemblerCodeRef_h */ diff --git a/js/src/assembler/assembler/MacroAssemblerMIPS.h b/js/src/assembler/assembler/MacroAssemblerMIPS.h index 46dde83e19c..aa368c91bfa 100644 --- a/js/src/assembler/assembler/MacroAssemblerMIPS.h +++ b/js/src/assembler/assembler/MacroAssemblerMIPS.h @@ -29,1376 +29,12 @@ #if ENABLE(ASSEMBLER) && CPU(MIPS) -#include "assembler/assembler/AbstractMacroAssembler.h" -#include "assembler/assembler/MIPSAssembler.h" +#include "assembler/wtf/Platform.h" namespace JSC { -class MacroAssemblerMIPS : public AbstractMacroAssembler { +class MacroAssemblerMIPS { public: - typedef MIPSRegisters::FPRegisterID FPRegisterID; - - MacroAssemblerMIPS() - : m_fixedWidth(false) - { - } - - static const Scale ScalePtr = TimesFour; - static const unsigned int TotalRegisters = 24; // Count from $0 to $23 - // to leave the bitmask for - // 8 FP registers. - - // For storing immediate number - static const RegisterID immTempRegister = MIPSRegisters::t0; - // For storing data loaded from the memory - static const RegisterID dataTempRegister = MIPSRegisters::t1; - // For storing address base - static const RegisterID addrTempRegister = MIPSRegisters::t2; - // For storing compare result - static const RegisterID cmpTempRegister = MIPSRegisters::t3; - // For storing data loaded from the memory - static const RegisterID dataTemp2Register = MIPSRegisters::t4; - - // FP temp register - static const FPRegisterID fpTempRegister = MIPSRegisters::f16; - - enum Condition { - Equal, - NotEqual, - Above, - AboveOrEqual, - Below, - BelowOrEqual, - GreaterThan, - GreaterThanOrEqual, - LessThan, - LessThanOrEqual, - Overflow, - Signed, - Zero, - NonZero - }; - - enum DoubleCondition { - DoubleEqual, - DoubleNotEqual, - DoubleGreaterThan, - DoubleGreaterThanOrEqual, - DoubleLessThan, - DoubleLessThanOrEqual, - DoubleEqualOrUnordered, - DoubleNotEqualOrUnordered, - DoubleGreaterThanOrUnordered, - DoubleGreaterThanOrEqualOrUnordered, - DoubleLessThanOrUnordered, - DoubleLessThanOrEqualOrUnordered - }; - - static const RegisterID stackPointerRegister = MIPSRegisters::sp; - static const RegisterID returnAddressRegister = MIPSRegisters::ra; - - // Integer arithmetic operations: - // - // Operations are typically two operand - operation(source, srcDst) - // For many operations the source may be an Imm32, the srcDst operand - // may often be a memory location (explictly described using an Address - // object). - - void lea(Address address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.addiu(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - addiu dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.addiu(dest, addrTempRegister, address.offset); - } - } - - void lea(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - addiu dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.addiu(dest, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - addiu dest, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.addiu(dest, addrTempRegister, address.offset); - } - } - - void add32(RegisterID src, RegisterID dest) - { - m_assembler.addu(dest, dest, src); - } - - void add32(TrustedImm32 imm, RegisterID dest) - { - add32(imm, dest, dest); - } - - void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) - { - if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767 - && !m_fixedWidth) { - /* - addiu dest, src, imm - */ - m_assembler.addiu(dest, src, imm.m_value); - } else { - /* - li immTemp, imm - addu dest, src, immTemp - */ - move(imm, immTempRegister); - m_assembler.addu(dest, src, immTempRegister); - } - } - - void add32(TrustedImm32 imm, Address address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - lw dataTemp, offset(base) - li immTemp, imm - addu dataTemp, dataTemp, immTemp - sw dataTemp, offset(base) - */ - m_assembler.lw(dataTempRegister, address.base, address.offset); - if (!imm.m_isPointer - && imm.m_value >= -32768 && imm.m_value <= 32767 - && !m_fixedWidth) - m_assembler.addiu(dataTempRegister, dataTempRegister, - imm.m_value); - else { - move(imm, immTempRegister); - m_assembler.addu(dataTempRegister, dataTempRegister, - immTempRegister); - } - m_assembler.sw(dataTempRegister, address.base, address.offset); - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lw dataTemp, (offset & 0xffff)(addrTemp) - li immtemp, imm - addu dataTemp, dataTemp, immTemp - sw dataTemp, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dataTempRegister, addrTempRegister, address.offset); - - if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth) - m_assembler.addiu(dataTempRegister, dataTempRegister, - imm.m_value); - else { - move(imm, immTempRegister); - m_assembler.addu(dataTempRegister, dataTempRegister, - immTempRegister); - } - m_assembler.sw(dataTempRegister, addrTempRegister, address.offset); - } - } - - void add32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - add32(dataTempRegister, dest); - } - - void add32(RegisterID src, Address dest) - { - if (dest.offset >= -32768 && dest.offset <= 32767 && !m_fixedWidth) { - /* - lw dataTemp, offset(base) - addu dataTemp, dataTemp, src - sw dataTemp, offset(base) - */ - m_assembler.lw(dataTempRegister, dest.base, dest.offset); - m_assembler.addu(dataTempRegister, dataTempRegister, src); - m_assembler.sw(dataTempRegister, dest.base, dest.offset); - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lw dataTemp, (offset & 0xffff)(addrTemp) - addu dataTemp, dataTemp, src - sw dataTemp, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (dest.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, dest.base); - m_assembler.lw(dataTempRegister, addrTempRegister, dest.offset); - m_assembler.addu(dataTempRegister, dataTempRegister, src); - m_assembler.sw(dataTempRegister, addrTempRegister, dest.offset); - } - } - - void add32(TrustedImm32 imm, AbsoluteAddress address) - { - /* - li addrTemp, address - li immTemp, imm - lw dataTemp, 0(addrTemp) - addu dataTemp, dataTemp, immTemp - sw dataTemp, 0(addrTemp) - */ - move(ImmPtr(address.m_ptr), addrTempRegister); - m_assembler.lw(dataTempRegister, addrTempRegister, 0); - if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767 - && !m_fixedWidth) - m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value); - else { - move(imm, immTempRegister); - m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister); - } - m_assembler.sw(dataTempRegister, addrTempRegister, 0); - } - - // If src is (0x7FF7FFFF<<1), we will convert it to (0x7FF80000<<1). - void setShiftedCanonicalNaN(RegisterID src, RegisterID dest) - { - /* - li dataTemp, (0x7FF80000<<1) - li immTemp, (0x7FF7FFFF<<1) - xor immTemp, immTemp, src - move dest, src - movz dest, dataTemp, immTemp - */ - move(TrustedImm32(0x7FF80000 << 1), dataTempRegister); - move(TrustedImm32(0x7FF7FFFF << 1), immTempRegister); - xor32(src, immTempRegister); - move(src, dest); - m_assembler.movz(dest, dataTempRegister, immTempRegister); - } - - void and32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - m_assembler.andInsn(dest, dest, dataTempRegister); - } - - void and32(RegisterID src, RegisterID dest) - { - m_assembler.andInsn(dest, dest, src); - } - - void and32(TrustedImm32 imm, RegisterID dest) - { - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - move(MIPSRegisters::zero, dest); - else if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535 - && !m_fixedWidth) - m_assembler.andi(dest, dest, imm.m_value); - else { - /* - li immTemp, imm - and dest, dest, immTemp - */ - move(imm, immTempRegister); - m_assembler.andInsn(dest, dest, immTempRegister); - } - } - - void lshift32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.sll(dest, dest, imm.m_value); - } - - void lshift32(RegisterID shiftAmount, RegisterID dest) - { - m_assembler.sllv(dest, dest, shiftAmount); - } - - void mul32(RegisterID src, RegisterID dest) - { - m_assembler.mul(dest, dest, src); - } - - void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest) - { - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - move(MIPSRegisters::zero, dest); - else if (!imm.m_isPointer && imm.m_value == 1 && !m_fixedWidth) - move(src, dest); - else { - /* - li dataTemp, imm - mul dest, src, dataTemp - */ - move(imm, dataTempRegister); - m_assembler.mul(dest, src, dataTempRegister); - } - } - - void neg32(RegisterID srcDest) - { - m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest); - } - - void not32(RegisterID srcDest) - { - m_assembler.nor(srcDest, srcDest, MIPSRegisters::zero); - } - - void or32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - m_assembler.orInsn(dest, dest, dataTempRegister); - } - - void or32(RegisterID src, RegisterID dest) - { - m_assembler.orInsn(dest, dest, src); - } - - void or32(TrustedImm32 imm, RegisterID dest) - { - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - return; - - if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535 - && !m_fixedWidth) { - m_assembler.ori(dest, dest, imm.m_value); - return; - } - - /* - li dataTemp, imm - or dest, dest, dataTemp - */ - move(imm, dataTempRegister); - m_assembler.orInsn(dest, dest, dataTempRegister); - } - - void rshift32(RegisterID shiftAmount, RegisterID dest) - { - m_assembler.srav(dest, dest, shiftAmount); - } - - void rshift32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.sra(dest, dest, imm.m_value); - } - - void urshift32(RegisterID shiftAmount, RegisterID dest) - { - m_assembler.srlv(dest, dest, shiftAmount); - } - - void urshift32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.srl(dest, dest, imm.m_value); - } - - void sub32(RegisterID src, RegisterID dest) - { - m_assembler.subu(dest, dest, src); - } - - void sub32(TrustedImm32 imm, RegisterID dest) - { - if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768 - && !m_fixedWidth) { - /* - addiu dest, src, imm - */ - m_assembler.addiu(dest, dest, -imm.m_value); - } else { - /* - li immTemp, imm - subu dest, src, immTemp - */ - move(imm, immTempRegister); - m_assembler.subu(dest, dest, immTempRegister); - } - } - - void sub32(TrustedImm32 imm, Address address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - lw dataTemp, offset(base) - li immTemp, imm - subu dataTemp, dataTemp, immTemp - sw dataTemp, offset(base) - */ - m_assembler.lw(dataTempRegister, address.base, address.offset); - if (!imm.m_isPointer - && imm.m_value >= -32767 && imm.m_value <= 32768 - && !m_fixedWidth) - m_assembler.addiu(dataTempRegister, dataTempRegister, - -imm.m_value); - else { - move(imm, immTempRegister); - m_assembler.subu(dataTempRegister, dataTempRegister, - immTempRegister); - } - m_assembler.sw(dataTempRegister, address.base, address.offset); - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lw dataTemp, (offset & 0xffff)(addrTemp) - li immtemp, imm - subu dataTemp, dataTemp, immTemp - sw dataTemp, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dataTempRegister, addrTempRegister, address.offset); - - if (!imm.m_isPointer - && imm.m_value >= -32767 && imm.m_value <= 32768 - && !m_fixedWidth) - m_assembler.addiu(dataTempRegister, dataTempRegister, - -imm.m_value); - else { - move(imm, immTempRegister); - m_assembler.subu(dataTempRegister, dataTempRegister, - immTempRegister); - } - m_assembler.sw(dataTempRegister, addrTempRegister, address.offset); - } - } - - void sub32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - sub32(dataTempRegister, dest); - } - - void sub32(TrustedImm32 imm, AbsoluteAddress address) - { - /* - li addrTemp, address - li immTemp, imm - lw dataTemp, 0(addrTemp) - subu dataTemp, dataTemp, immTemp - sw dataTemp, 0(addrTemp) - */ - move(ImmPtr(address.m_ptr), addrTempRegister); - m_assembler.lw(dataTempRegister, addrTempRegister, 0); - - if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768 - && !m_fixedWidth) { - m_assembler.addiu(dataTempRegister, dataTempRegister, - -imm.m_value); - } else { - move(imm, immTempRegister); - m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister); - } - m_assembler.sw(dataTempRegister, addrTempRegister, 0); - } - - void xor32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - m_assembler.xorInsn(dest, dest, dataTempRegister); - } - - void xor32(RegisterID src, RegisterID dest) - { - m_assembler.xorInsn(dest, dest, src); - } - - void xor32(TrustedImm32 imm, RegisterID dest) - { - /* - li immTemp, imm - xor dest, dest, immTemp - */ - move(imm, immTempRegister); - m_assembler.xorInsn(dest, dest, immTempRegister); - } - - void load16SignExtend(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.lh(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lh dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lh(dest, addrTempRegister, address.offset); - } - } - - void load16ZeroExtend(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.lhu(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lhu dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lhu(dest, addrTempRegister, address.offset); - } - } - - void load16SignExtend(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lh dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lh(dest, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - lh dest, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.lh(dest, addrTempRegister, address.offset); - } - } - - void load16ZeroExtend(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lhu dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lhu(dest, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - lhu dest, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.lhu(dest, addrTempRegister, address.offset); - } - } - - void load8(BaseIndex address, RegisterID dest) - { - load8ZeroExtend(address, dest); - } - - void load8SignExtend(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.lb(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lb dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lb(dest, addrTempRegister, address.offset); - } - } - - void load8ZeroExtend(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.lbu(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lbu dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lbu(dest, addrTempRegister, address.offset); - } - } - - void load8SignExtend(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lb dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lb(dest, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - lb dest, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.lb(dest, addrTempRegister, address.offset); - } - } - - void load8ZeroExtend(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lbu dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lbu(dest, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - lbu dest, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.lbu(dest, addrTempRegister, address.offset); - } - } - - void load16Unaligned(BaseIndex address, RegisterID dest) - { - load16(address, dest); - } - - void negDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.negd(dest, src); - } - - void absDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.absd(dest, src); - } - - void sqrtDouble(FPRegisterID src, FPRegisterID dst) - { - m_assembler.sqrtd(dst, src); - } - - // Memory access operations: - // - // Loads are of the form load(address, destination) and stores of the form - // store(source, address). The source for a store may be an Imm32. Address - // operand objects to loads and store will be implicitly constructed if a - // register is passed. - - /* Need to use zero-extened load byte for load8. */ - void load8(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.lbu(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lbu dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lbu(dest, addrTempRegister, address.offset); - } - } - - void load32(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.lw(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lw dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dest, addrTempRegister, address.offset); - } - } - - void load32(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lw dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dest, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - lw dest, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.lw(dest, addrTempRegister, address.offset); - } - } - - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32764 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - (Big-Endian) - lwl dest, address.offset(addrTemp) - lwr dest, address.offset+3(addrTemp) - (Little-Endian) - lwl dest, address.offset+3(addrTemp) - lwr dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); -#if CPU(BIG_ENDIAN) - m_assembler.lwl(dest, addrTempRegister, address.offset); - m_assembler.lwr(dest, addrTempRegister, address.offset + 3); -#else - m_assembler.lwl(dest, addrTempRegister, address.offset + 3); - m_assembler.lwr(dest, addrTempRegister, address.offset); - -#endif - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, address.offset >> 16 - ori immTemp, immTemp, address.offset & 0xffff - addu addrTemp, addrTemp, immTemp - (Big-Endian) - lw dest, 0(addrTemp) - lw dest, 3(addrTemp) - (Little-Endian) - lw dest, 3(addrTemp) - lw dest, 0(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, address.offset >> 16); - m_assembler.ori(immTempRegister, immTempRegister, address.offset); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); -#if CPU(BIG_ENDIAN) - m_assembler.lwl(dest, addrTempRegister, 0); - m_assembler.lwr(dest, addrTempRegister, 3); -#else - m_assembler.lwl(dest, addrTempRegister, 3); - m_assembler.lwr(dest, addrTempRegister, 0); -#endif - } - } - - void load32(const void* address, RegisterID dest) - { - /* - li addrTemp, address - lw dest, 0(addrTemp) - */ - move(ImmPtr(address), addrTempRegister); - m_assembler.lw(dest, addrTempRegister, 0); - } - - DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) - { - m_fixedWidth = true; - /* - lui addrTemp, address.offset >> 16 - ori addrTemp, addrTemp, address.offset & 0xffff - addu addrTemp, addrTemp, address.base - lw dest, 0(addrTemp) - */ - DataLabel32 dataLabel(this); - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dest, addrTempRegister, 0); - m_fixedWidth = false; - return dataLabel; - } - - void load64WithPatch(Address address, RegisterID tag, RegisterID payload, int tag_offset, int payload_offset) - { - m_fixedWidth = true; - /* - lui addrTemp, address.offset >> 16 - ori addrTemp, addrTemp, address.offset & 0xffff - addu addrTemp, addrTemp, address.base - lw tag, tag_offset(addrTemp) - lw payload, payload_offset(addrTemp) - */ - Label label(this); - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(tag, addrTempRegister, tag_offset); - m_assembler.lw(payload, addrTempRegister, payload_offset); - m_fixedWidth = false; - } - - void store64WithPatch(Address address, RegisterID tag, RegisterID payload, int tag_offset, int payload_offset) - { - m_fixedWidth = true; - /* - lui addrTemp, address.offset >> 16 - ori addrTemp, addrTemp, address.offset & 0xffff - addu addrTemp, addrTemp, address.base - sw tag, tag_offset(addrTemp) - sw payload, payload_offset(addrTemp) - */ - Label label(this); - move(Imm32(address.offset), addrTempRegister); - m_fixedWidth = false; - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sw(tag, addrTempRegister, tag_offset); - m_assembler.sw(payload, addrTempRegister, payload_offset); - } - - void store64WithPatch(Address address, Imm32 tag, RegisterID payload, int tag_offset, int payload_offset) - { - m_fixedWidth = true; - /* - lui addrTemp, address.offset >> 16 - ori addrTemp, addrTemp, address.offset & 0xffff - addu addrTemp, addrTemp, address.base - li immTemp, tag - sw immTemp, tag_offset(addrTemp) - sw payload, payload_offset(addrTemp) - */ - Label label(this); - move(Imm32(address.offset), addrTempRegister); - m_fixedWidth = false; - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - move(tag, immTempRegister); - m_assembler.sw(immTempRegister, addrTempRegister, tag_offset); - m_assembler.sw(payload, addrTempRegister, payload_offset); - } - - void store64WithPatch(Address address, Imm32 tag, Imm32 payload, int tag_offset, int payload_offset) - { - m_fixedWidth = true; - /* - lui addrTemp, address.offset >> 16 - ori addrTemp, addrTemp, address.offset & 0xffff - addu addrTemp, addrTemp, address.base - li immTemp, tag - sw immTemp, tag_offset(addrTemp) - li immTemp, payload - sw immTemp, payload_offset(addrTemp) - */ - Label label(this); - move(Imm32(address.offset), addrTempRegister); - m_fixedWidth = false; - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - move(tag, immTempRegister); - m_assembler.sw(immTempRegister, addrTempRegister, tag_offset); - move(payload, immTempRegister); - m_assembler.sw(immTempRegister, addrTempRegister, payload_offset); - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - m_fixedWidth = true; - /* - lui addrTemp, address.offset >> 16 - ori addrTemp, addrTemp, address.offset & 0xffff - addu addrTemp, addrTemp, address.base - lw dest, 0(addrTemp) - */ - Label label(this); - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dest, addrTempRegister, 0); - m_fixedWidth = false; - return label; - } - - /* Need to use zero-extened load half-word for load16. */ - void load16(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.lhu(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lhu dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lhu(dest, addrTempRegister, address.offset); - } - } - - /* Need to use zero-extened load half-word for load16. */ - void load16(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lhu dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lhu(dest, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - lhu dest, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.lhu(dest, addrTempRegister, address.offset); - } - } - - DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) - { - m_fixedWidth = true; - /* - lui addrTemp, address.offset >> 16 - ori addrTemp, addrTemp, address.offset & 0xffff - addu addrTemp, addrTemp, address.base - sw src, 0(addrTemp) - */ - DataLabel32 dataLabel(this); - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sw(src, addrTempRegister, 0); - m_fixedWidth = false; - return dataLabel; - } - - void store8(RegisterID src, ImplicitAddress address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.sb(src, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - sb src, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sb(src, addrTempRegister, address.offset); - } - } - - void store8(RegisterID src, BaseIndex address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - sb src, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sb(src, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - sb src, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.sb(src, addrTempRegister, address.offset); - } - } - - void store8(TrustedImm32 imm, BaseIndex address) - { - if (!imm.m_isPointer && !imm.m_value) - store8(MIPSRegisters::zero, address); - else { - move(imm, immTempRegister); - store8(immTempRegister, address); - } - } - - void store8(TrustedImm32 imm, ImplicitAddress address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - if (!imm.m_isPointer && !imm.m_value) - m_assembler.sb(MIPSRegisters::zero, address.base, - address.offset); - else { - move(imm, immTempRegister); - m_assembler.sb(immTempRegister, address.base, address.offset); - } - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - sb immTemp, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - m_assembler.sb(MIPSRegisters::zero, addrTempRegister, - address.offset); - else { - move(imm, immTempRegister); - m_assembler.sb(immTempRegister, addrTempRegister, - address.offset); - } - } - } - - void store8(RegisterID src, void* address) - { - /* - li addrTemp, address - sb src, 0(addrTemp) - */ - move(ImmPtr(address), addrTempRegister); - m_assembler.sb(src, addrTempRegister, 0); - } - - void store8(TrustedImm32 imm, void* address) - { - /* - li immTemp, imm - li addrTemp, address - sb src, 0(addrTemp) - */ - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) { - move(ImmPtr(address), addrTempRegister); - m_assembler.sb(MIPSRegisters::zero, addrTempRegister, 0); - } else { - move(imm, immTempRegister); - move(ImmPtr(address), addrTempRegister); - m_assembler.sb(immTempRegister, addrTempRegister, 0); - } - } - - void store16(RegisterID src, ImplicitAddress address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.sh(src, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - sh src, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sh(src, addrTempRegister, address.offset); - } - } - - void store16(RegisterID src, BaseIndex address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - sh src, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sh(src, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - sh src, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.sh(src, addrTempRegister, address.offset); - } - } - - void store16(TrustedImm32 imm, BaseIndex address) - { - if (!imm.m_isPointer && !imm.m_value) - store16(MIPSRegisters::zero, address); - else { - move(imm, immTempRegister); - store16(immTempRegister, address); - } - } - - void store16(TrustedImm32 imm, ImplicitAddress address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - if (!imm.m_isPointer && !imm.m_value) - m_assembler.sh(MIPSRegisters::zero, address.base, - address.offset); - else { - move(imm, immTempRegister); - m_assembler.sh(immTempRegister, address.base, address.offset); - } - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - sh immTemp, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - m_assembler.sh(MIPSRegisters::zero, addrTempRegister, - address.offset); - else { - move(imm, immTempRegister); - m_assembler.sh(immTempRegister, addrTempRegister, - address.offset); - } - } - } - - void store16(RegisterID src, void* address) - { - /* - li addrTemp, address - sh src, 0(addrTemp) - */ - move(ImmPtr(address), addrTempRegister); - m_assembler.sh(src, addrTempRegister, 0); - } - - void store16(TrustedImm32 imm, void* address) - { - /* - li immTemp, imm - li addrTemp, address - sh src, 0(addrTemp) - */ - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) { - move(ImmPtr(address), addrTempRegister); - m_assembler.sh(MIPSRegisters::zero, addrTempRegister, 0); - } else { - move(imm, immTempRegister); - move(ImmPtr(address), addrTempRegister); - m_assembler.sh(immTempRegister, addrTempRegister, 0); - } - } - - void store32(RegisterID src, ImplicitAddress address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.sw(src, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - sw src, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sw(src, addrTempRegister, address.offset); - } - } - - void store32(RegisterID src, BaseIndex address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - sw src, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sw(src, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - sw src, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.sw(src, addrTempRegister, address.offset); - } - } - - void store32(TrustedImm32 imm, BaseIndex address) - { - if (!imm.m_isPointer && !imm.m_value) - store32(MIPSRegisters::zero, address); - else { - move(imm, immTempRegister); - store32(immTempRegister, address); - } - } - - void store32(TrustedImm32 imm, ImplicitAddress address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - if (!imm.m_isPointer && !imm.m_value) - m_assembler.sw(MIPSRegisters::zero, address.base, - address.offset); - else { - move(imm, immTempRegister); - m_assembler.sw(immTempRegister, address.base, address.offset); - } - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - sw immTemp, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - m_assembler.sw(MIPSRegisters::zero, addrTempRegister, - address.offset); - else { - move(imm, immTempRegister); - m_assembler.sw(immTempRegister, addrTempRegister, - address.offset); - } - } - } - - void store32(RegisterID src, void* address) - { - /* - li addrTemp, address - sw src, 0(addrTemp) - */ - move(ImmPtr(address), addrTempRegister); - m_assembler.sw(src, addrTempRegister, 0); - } - - void store32(TrustedImm32 imm, void* address) - { - /* - li immTemp, imm - li addrTemp, address - sw src, 0(addrTemp) - */ - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) { - move(ImmPtr(address), addrTempRegister); - m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0); - } else { - move(imm, immTempRegister); - move(ImmPtr(address), addrTempRegister); - m_assembler.sw(immTempRegister, addrTempRegister, 0); - } - } - - // Floating-point operations: - static bool supportsFloatingPoint() { #if WTF_MIPS_DOUBLE_FLOAT @@ -1407,1390 +43,6 @@ public: return false; #endif } - - static bool supportsFloatingPointTruncate() - { -#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2) - return true; -#else - return false; -#endif - } - - static bool supportsFloatingPointSqrt() - { -#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2) - return true; -#else - return false; -#endif - } - - // Stack manipulation operations: - // - // The ABI is assumed to provide a stack abstraction to memory, - // containing machine word sized units of data. Push and pop - // operations add and remove a single register sized unit of data - // to or from the stack. Peek and poke operations read or write - // values on the stack, without moving the current stack position. - - void pop(RegisterID dest) - { - m_assembler.lw(dest, MIPSRegisters::sp, 0); - m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4); - } - - void push(RegisterID src) - { - m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4); - m_assembler.sw(src, MIPSRegisters::sp, 0); - } - - void push(Address address) - { - load32(address, dataTempRegister); - push(dataTempRegister); - } - - void push(TrustedImm32 imm) - { - move(imm, immTempRegister); - push(immTempRegister); - } - - // Register move operations: - // - // Move values in registers. - - void move(TrustedImm32 imm, RegisterID dest) - { - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - move(MIPSRegisters::zero, dest); - else if (imm.m_isPointer || m_fixedWidth) { - m_assembler.lui(dest, imm.m_value >> 16); - m_assembler.ori(dest, dest, imm.m_value); - } else - m_assembler.li(dest, imm.m_value); - } - - void move(RegisterID src, RegisterID dest) - { - if (src != dest || m_fixedWidth) - m_assembler.move(dest, src); - } - - void move(TrustedImmPtr imm, RegisterID dest) - { - move(Imm32(imm), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - move(reg1, immTempRegister); - move(reg2, reg1); - move(immTempRegister, reg2); - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest || m_fixedWidth) - move(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest || m_fixedWidth) - move(src, dest); - } - - // Forwards / external control flow operations: - // - // This set of jump and conditional branch operations return a Jump - // object which may linked at a later point, allow forwards jump, - // or jumps that will require external linkage (after the code has been - // relocated). - // - // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge - // respecitvely, for unsigned comparisons the names b, a, be, and ae are - // used (representing the names 'below' and 'above'). - // - // Operands to the comparision are provided in the expected order, e.g. - // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when - // treated as a signed 32bit value, is less than or equal to 5. - // - // jz and jnz test whether the first operand is equal to zero, and take - // an optional second operand of a mask under which to perform the test. - - Jump branch8(Condition cond, Address left, TrustedImm32 right) - { - // Make sure the immediate value is unsigned 8 bits. - ASSERT(!(right.m_value & 0xFFFFFF00)); - load8(left, dataTempRegister); - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branch32(Condition cond, RegisterID left, RegisterID right) - { - if (cond == Equal || cond == Zero) - return branchEqual(left, right); - if (cond == NotEqual || cond == NonZero) - return branchNotEqual(left, right); - if (cond == Above) { - m_assembler.sltu(cmpTempRegister, right, left); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == AboveOrEqual) { - m_assembler.sltu(cmpTempRegister, left, right); - return branchEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Below) { - m_assembler.sltu(cmpTempRegister, left, right); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == BelowOrEqual) { - m_assembler.sltu(cmpTempRegister, right, left); - return branchEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == GreaterThan) { - m_assembler.slt(cmpTempRegister, right, left); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == GreaterThanOrEqual) { - m_assembler.slt(cmpTempRegister, left, right); - return branchEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == LessThan) { - m_assembler.slt(cmpTempRegister, left, right); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == LessThanOrEqual) { - m_assembler.slt(cmpTempRegister, right, left); - return branchEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Overflow) { - /* - xor cmpTemp, left, right - bgez No_overflow, cmpTemp # same sign bit -> no overflow - nop - subu cmpTemp, left, right - xor cmpTemp, cmpTemp, left - bgez No_overflow, cmpTemp # same sign bit -> no overflow - nop - b Overflow - nop - nop - nop - nop - nop - No_overflow: - */ - m_assembler.xorInsn(cmpTempRegister, left, right); - m_assembler.bgez(cmpTempRegister, 11); - m_assembler.nop(); - m_assembler.subu(cmpTempRegister, left, right); - m_assembler.xorInsn(cmpTempRegister, cmpTempRegister, left); - m_assembler.bgez(cmpTempRegister, 7); - m_assembler.nop(); - return jump(); - } - if (cond == Signed) { - m_assembler.subu(cmpTempRegister, left, right); - // Check if the result is negative. - m_assembler.slt(cmpTempRegister, cmpTempRegister, - MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - ASSERT(0); - - return Jump(); - } - - Jump branch32(Condition cond, RegisterID left, TrustedImm32 right) - { - move(right, immTempRegister); - return branch32(cond, left, immTempRegister); - } - - Jump branch32(Condition cond, RegisterID left, Address right) - { - load32(right, dataTempRegister); - return branch32(cond, left, dataTempRegister); - } - - Jump branch32(Condition cond, Address left, RegisterID right) - { - load32(left, dataTempRegister); - return branch32(cond, dataTempRegister, right); - } - - Jump branch32(Condition cond, Address left, TrustedImm32 right) - { - load32(left, dataTempRegister); - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right) - { - load32(left, dataTempRegister); - // Be careful that the previous load32() uses immTempRegister. - // So, we need to put move() after load32(). - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right) - { - load32WithUnalignedHalfWords(left, dataTempRegister); - // Be careful that the previous load32WithUnalignedHalfWords() - // uses immTempRegister. - // So, we need to put move() after load32WithUnalignedHalfWords(). - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) - { - load32(left.m_ptr, dataTempRegister); - return branch32(cond, dataTempRegister, right); - } - - Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right) - { - load32(left.m_ptr, dataTempRegister); - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branch16(Condition cond, BaseIndex left, RegisterID right) - { - load16(left, dataTempRegister); - return branch32(cond, dataTempRegister, right); - } - - Jump branch16(Condition cond, BaseIndex left, TrustedImm32 right) - { - ASSERT(!(right.m_value & 0xFFFF0000)); - load16(left, dataTempRegister); - // Be careful that the previous load16() uses immTempRegister. - // So, we need to put move() after load16(). - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) - { - ASSERT((cond == Zero) || (cond == NonZero)); - m_assembler.andInsn(cmpTempRegister, reg, mask); - if (cond == Zero) - return branchEqual(cmpTempRegister, MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - - Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - if (mask.m_value == -1 && !m_fixedWidth) { - if (cond == Zero) - return branchEqual(reg, MIPSRegisters::zero); - return branchNotEqual(reg, MIPSRegisters::zero); - } - move(mask, immTempRegister); - return branchTest32(cond, reg, immTempRegister); - } - - Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - load32(address, dataTempRegister); - return branchTest32(cond, dataTempRegister, mask); - } - - Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - load32(address, dataTempRegister); - return branchTest32(cond, dataTempRegister, mask); - } - - Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - load8(address, dataTempRegister); - return branchTest32(cond, dataTempRegister, mask); - } - - Jump jump() - { - return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero); - } - - void jump(RegisterID target) - { - m_assembler.jr(target); - m_assembler.nop(); - } - - void jump(Address address) - { - m_fixedWidth = true; - load32(address, MIPSRegisters::t9); - m_assembler.jr(MIPSRegisters::t9); - m_assembler.nop(); - m_fixedWidth = false; - } - - void jump(BaseIndex address) - { - load32(address, MIPSRegisters::t9); - m_assembler.jr(MIPSRegisters::t9); - m_assembler.nop(); - } - - // Arithmetic control flow operations: - // - // This set of conditional branch operations branch based - // on the result of an arithmetic operation. The operation - // is performed as normal, storing the result. - // - // * jz operations branch if the result is zero. - // * jo operations branch if the (signed) arithmetic - // operation caused an overflow to occur. - - Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Overflow) { - /* - move dest, dataTemp - xor cmpTemp, dataTemp, src - bltz cmpTemp, No_overflow # diff sign bit -> no overflow - addu dest, dataTemp, src - xor cmpTemp, dest, dataTemp - bgez cmpTemp, No_overflow # same sign big -> no overflow - nop - b Overflow - nop - nop - nop - nop - nop - No_overflow: - */ - move(dest, dataTempRegister); - m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src); - m_assembler.bltz(cmpTempRegister, 10); - m_assembler.addu(dest, dataTempRegister, src); - m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister); - m_assembler.bgez(cmpTempRegister, 7); - m_assembler.nop(); - return jump(); - } - if (cond == Signed) { - add32(src, dest); - // Check if dest is negative. - m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Zero) { - add32(src, dest); - return branchEqual(dest, MIPSRegisters::zero); - } - if (cond == NonZero) { - add32(src, dest); - return branchNotEqual(dest, MIPSRegisters::zero); - } - ASSERT(0); - return Jump(); - } - - Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) - { - move(imm, immTempRegister); - return branchAdd32(cond, immTempRegister, dest); - } - - Jump branchAdd32(Condition cond, Address src, RegisterID dest) - { - load32(src, immTempRegister); - return branchAdd32(cond, immTempRegister, dest); - } - - Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Overflow) { - /* - mult src, dest - mfhi dataTemp - mflo dest - sra addrTemp, dest, 31 - beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow - nop - b Overflow - nop - nop - nop - nop - nop - No_overflow: - */ - m_assembler.mult(src, dest); - m_assembler.mfhi(dataTempRegister); - m_assembler.mflo(dest); - m_assembler.sra(addrTempRegister, dest, 31); - m_assembler.beq(dataTempRegister, addrTempRegister, 7); - m_assembler.nop(); - return jump(); - } - if (cond == Signed) { - mul32(src, dest); - // Check if dest is negative. - m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Zero) { - mul32(src, dest); - return branchEqual(dest, MIPSRegisters::zero); - } - if (cond == NonZero) { - mul32(src, dest); - return branchNotEqual(dest, MIPSRegisters::zero); - } - ASSERT(0); - return Jump(); - } - - Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) - { - move(imm, immTempRegister); - move(src, dest); - return branchMul32(cond, immTempRegister, dest); - } - - Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Overflow) { - /* - move dest, dataTemp - xor cmpTemp, dataTemp, src - bgez cmpTemp, No_overflow # same sign bit -> no overflow - subu dest, dataTemp, src - xor cmpTemp, dest, dataTemp - bgez cmpTemp, No_overflow # same sign bit -> no overflow - nop - b Overflow - nop - nop - nop - nop - nop - No_overflow: - */ - move(dest, dataTempRegister); - m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src); - m_assembler.bgez(cmpTempRegister, 10); - m_assembler.subu(dest, dataTempRegister, src); - m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister); - m_assembler.bgez(cmpTempRegister, 7); - m_assembler.nop(); - return jump(); - } - if (cond == Signed) { - sub32(src, dest); - // Check if dest is negative. - m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Zero) { - sub32(src, dest); - return branchEqual(dest, MIPSRegisters::zero); - } - if (cond == NonZero) { - sub32(src, dest); - return branchNotEqual(dest, MIPSRegisters::zero); - } - ASSERT(0); - return Jump(); - } - - Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) - { - move(imm, immTempRegister); - return branchSub32(cond, immTempRegister, dest); - } - - Jump branchSub32(Condition cond, Address src, RegisterID dest) - { - load32(src, immTempRegister); - return branchSub32(cond, immTempRegister, dest); - } - - Jump branchSub32(Condition cond, Imm32 imm, Address dest) - { - // Save the original value at dest to dataTemp2Register - load32(dest, dataTemp2Register); - - // Calculate the result and save it to dest - sub32(imm, dest); - - return branchSub32(cond, imm, dataTemp2Register); - } - - Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Signed) { - or32(src, dest); - // Check if dest is negative. - m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Zero) { - or32(src, dest); - return branchEqual(dest, MIPSRegisters::zero); - } - if (cond == NonZero) { - or32(src, dest); - return branchNotEqual(dest, MIPSRegisters::zero); - } - ASSERT(0); - return Jump(); - } - - // Miscellaneous operations: - - void breakpoint() - { - m_assembler.bkpt(); - } - - Call nearCall() - { - /* We need two words for relaxation. */ - m_assembler.nop(); - m_assembler.nop(); - m_assembler.jal(); - m_assembler.nop(); - return Call(m_assembler.newJmpSrc(), Call::LinkableNear); - } - - Call call() - { - m_assembler.lui(MIPSRegisters::t9, 0); - m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0); - m_assembler.jalr(MIPSRegisters::t9); - m_assembler.nop(); - return Call(m_assembler.newJmpSrc(), Call::Linkable); - } - - Call call(RegisterID target) - { - m_assembler.jalr(target); - m_assembler.nop(); - return Call(m_assembler.newJmpSrc(), Call::None); - } - - Call call(Address address) - { - m_fixedWidth = true; - load32(address, MIPSRegisters::t9); - m_assembler.jalr(MIPSRegisters::t9); - m_assembler.nop(); - m_fixedWidth = false; - return Call(m_assembler.newJmpSrc(), Call::None); - } - - void ret() - { - m_assembler.jr(MIPSRegisters::ra); - m_assembler.nop(); - } - - void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - set32(cond, left, right, dest); - } - - void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - move(right, immTempRegister); - set32(cond, left, immTempRegister, dest); - } - - void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - if (cond == Equal || cond == Zero) { - m_assembler.xorInsn(dest, left, right); - m_assembler.sltiu(dest, dest, 1); - } else if (cond == NotEqual || cond == NonZero) { - m_assembler.xorInsn(dest, left, right); - m_assembler.sltu(dest, MIPSRegisters::zero, dest); - } else if (cond == Above) - m_assembler.sltu(dest, right, left); - else if (cond == AboveOrEqual) { - m_assembler.sltu(dest, left, right); - m_assembler.xori(dest, dest, 1); - } else if (cond == Below) - m_assembler.sltu(dest, left, right); - else if (cond == BelowOrEqual) { - m_assembler.sltu(dest, right, left); - m_assembler.xori(dest, dest, 1); - } else if (cond == GreaterThan) - m_assembler.slt(dest, right, left); - else if (cond == GreaterThanOrEqual) { - m_assembler.slt(dest, left, right); - m_assembler.xori(dest, dest, 1); - } else if (cond == LessThan) - m_assembler.slt(dest, left, right); - else if (cond == LessThanOrEqual) { - m_assembler.slt(dest, right, left); - m_assembler.xori(dest, dest, 1); - } else if (cond == Overflow) { - /* - xor cmpTemp, left, right - bgez Done, cmpTemp # same sign bit -> no overflow - move dest, 0 - subu cmpTemp, left, right - xor cmpTemp, cmpTemp, left # diff sign bit -> overflow - slt dest, cmpTemp, 0 - Done: - */ - m_assembler.xorInsn(cmpTempRegister, left, right); - m_assembler.bgez(cmpTempRegister, 4); - m_assembler.move(dest, MIPSRegisters::zero); - m_assembler.subu(cmpTempRegister, left, right); - m_assembler.xorInsn(cmpTempRegister, cmpTempRegister, left); - m_assembler.slt(dest, cmpTempRegister, MIPSRegisters::zero); - } else if (cond == Signed) { - m_assembler.subu(dest, left, right); - // Check if the result is negative. - m_assembler.slt(dest, dest, MIPSRegisters::zero); - } - } - - void set32(Condition cond, Address left, Imm32 right, RegisterID dest) - { - load32(left, dataTempRegister); - move(right, immTempRegister); - set32(cond, dataTempRegister, immTempRegister, dest); - } - - void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - move(right, immTempRegister); - set32(cond, left, immTempRegister, dest); - } - - void set32(Condition cond, Address left, RegisterID right, RegisterID dest) - { - load32(left, immTempRegister); - set32(cond, immTempRegister, right, dest); - } - - void set32(Condition cond, RegisterID left, Address right, RegisterID dest) - { - load32(right, immTempRegister); - set32(cond, left, immTempRegister, dest); - } - - void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - ASSERT((cond == Zero) || (cond == NonZero)); - load8(address, dataTempRegister); - if (mask.m_value == -1 && !m_fixedWidth) { - if (cond == Zero) - m_assembler.sltiu(dest, dataTempRegister, 1); - else - m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister); - } else { - move(mask, immTempRegister); - m_assembler.andInsn(cmpTempRegister, dataTempRegister, - immTempRegister); - if (cond == Zero) - m_assembler.sltiu(dest, cmpTempRegister, 1); - else - m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister); - } - } - - void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - ASSERT((cond == Zero) || (cond == NonZero)); - load32(address, dataTempRegister); - if (mask.m_value == -1 && !m_fixedWidth) { - if (cond == Zero) - m_assembler.sltiu(dest, dataTempRegister, 1); - else - m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister); - } else { - move(mask, immTempRegister); - m_assembler.andInsn(cmpTempRegister, dataTempRegister, - immTempRegister); - if (cond == Zero) - m_assembler.sltiu(dest, cmpTempRegister, 1); - else - m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister); - } - } - - DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest) - { - m_fixedWidth = true; - DataLabel32 label(this); - move(imm, dest); - m_fixedWidth = false; - return label; - } - - DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) - { - m_fixedWidth = true; - DataLabelPtr label(this); - move(initialValue, dest); - m_fixedWidth = false; - return label; - } - - Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32& dataLabel) - { - m_fixedWidth = true; - dataLabel = moveWithPatch(right, immTempRegister); - Jump temp = branch32(cond, left, immTempRegister); - m_fixedWidth = false; - return temp; - } - - Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right) - { - m_fixedWidth = true; - move(right, immTempRegister); - Jump temp = branch32(cond, left, immTempRegister); - m_fixedWidth = false; - return temp; - } - - Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32& dataLabel) - { - m_fixedWidth = true; - load32(left, dataTempRegister); - dataLabel = moveWithPatch(right, immTempRegister); - Jump temp = branch32(cond, dataTempRegister, immTempRegister); - m_fixedWidth = false; - return temp; - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - m_fixedWidth = true; - dataLabel = moveWithPatch(initialRightValue, immTempRegister); - Jump temp = branch32(cond, left, immTempRegister); - m_fixedWidth = false; - return temp; - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - m_fixedWidth = true; - load32(left, dataTempRegister); - dataLabel = moveWithPatch(initialRightValue, immTempRegister); - Jump temp = branch32(cond, dataTempRegister, immTempRegister); - m_fixedWidth = false; - return temp; - } - - DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) - { - m_fixedWidth = true; - DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister); - store32(dataTempRegister, address); - m_fixedWidth = false; - return dataLabel; - } - - DataLabelPtr storePtrWithPatch(ImplicitAddress address) - { - return storePtrWithPatch(ImmPtr(0), address); - } - - Call tailRecursiveCall() - { - // Like a normal call, but don't update the returned address register - m_fixedWidth = true; - move(Imm32(0), MIPSRegisters::t9); - m_assembler.jr(MIPSRegisters::t9); - m_assembler.nop(); - m_fixedWidth = false; - return Call(m_assembler.newJmpSrc(), Call::Linkable); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - oldJump.link(this); - return tailRecursiveCall(); - } - - void moveDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.movd(dest, src); - } - - void loadFloat(ImplicitAddress address, FPRegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - m_assembler.lwc1(dest, address.base, address.offset); - m_assembler.cvtds(dest, dest); - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lwc1 dest, (offset & 0xffff)(addrTemp) - cvt.d.s dest, dest - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lwc1(dest, addrTempRegister, address.offset); - m_assembler.cvtds(dest, dest); - } - } - - void loadFloat(BaseIndex address, FPRegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lwc1 dest, address.offset(addrTemp) - cvt.d.s dest, dest - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lwc1(dest, addrTempRegister, address.offset); - m_assembler.cvtds(dest, dest); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - lwc1 dest, (address.offset & 0xffff)(addrTemp) - cvt.d.s dest, dest - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.lwc1(dest, addrTempRegister, address.offset); - m_assembler.cvtds(dest, dest); - } - } - - DataLabelPtr loadFloat(const void* address, FPRegisterID dest) - { - DataLabelPtr label = moveWithPatch(ImmPtr(address), addrTempRegister); - /* - lwc1 dest, 0(addrTemp) - cvt.d.s dest, dest - */ - m_assembler.lwc1(dest, addrTempRegister, 0); - m_assembler.cvtds(dest, dest); - return label; - } - - void loadDouble(ImplicitAddress address, FPRegisterID dest) - { -#if WTF_MIPS_ISA(1) - /* - li addrTemp, address.offset - addu addrTemp, addrTemp, base - lwc1 dest, 0(addrTemp) - lwc1 dest+1, 4(addrTemp) - */ - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lwc1(dest, addrTempRegister, 0); - m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4); -#else - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - m_assembler.ldc1(dest, address.base, address.offset); - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - ldc1 dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.ldc1(dest, addrTempRegister, address.offset); - } -#endif - } - - void loadDouble(BaseIndex address, FPRegisterID dest) - { -#if WTF_MIPS_ISA(1) - if (address.offset >= -32768 && address.offset <= 32763 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lwc1 dest, address.offset(addrTemp) - lwc1 dest+1, address.offset+4(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lwc1(dest, addrTempRegister, address.offset); - m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, address.offset + 4); - } else { - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - li immTemp, address.offset - addu addrTemp, addrTemp, immTemp - lwc1 dest, 0(addrTemp) - lwc1 dest+1, 4(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.li(immTempRegister, address.offset); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.lwc1(dest, addrTempRegister, 0); - m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4); -#else - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - ldc1 dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.ldc1(dest, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - ldc1 dest, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.ldc1(dest, addrTempRegister, address.offset); - } -#endif - } - - DataLabelPtr loadDouble(const void* address, FPRegisterID dest) - { - DataLabelPtr label = moveWithPatch(ImmPtr(address), addrTempRegister); -#if WTF_MIPS_ISA(1) - /* - lwc1 dest, 0(addrTemp) - lwc1 dest+1, 4(addrTemp) - */ - m_assembler.lwc1(dest, addrTempRegister, 0); - m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4); -#else - /* - ldc1 dest, 0(addrTemp) - */ - m_assembler.ldc1(dest, addrTempRegister, 0); -#endif - return label; - } - - void storeFloat(FPRegisterID src, BaseIndex address) - { - lea(address, addrTempRegister); - m_assembler.swc1(src, addrTempRegister, 0); - } - - void storeFloat(FPRegisterID src, ImplicitAddress address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.swc1(src, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - swc1 src, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.swc1(src, addrTempRegister, address.offset); - } - } - - void storeFloat(ImmDouble imm, Address address) - { - union { - float f; - uint32_t u32; - } u; - u.f = imm.u.d; - store32(Imm32(u.u32), address); - } - - void storeFloat(ImmDouble imm, BaseIndex address) - { - union { - float f; - uint32_t u32; - } u; - u.f = imm.u.d; - store32(Imm32(u.u32), address); - } - - void storeDouble(FPRegisterID src, BaseIndex address) - { - lea(address, addrTempRegister); -#if WTF_MIPS_ISA(1) - m_assembler.swc1(src, addrTempRegister, 0); - m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4); -#else - m_assembler.sdc1(src, addrTempRegister, 0); -#endif - } - - void storeDouble(FPRegisterID src, ImplicitAddress address) - { -#if WTF_MIPS_ISA(1) - /* - li addrTemp, address.offset - addu addrTemp, addrTemp, base - swc1 dest, 0(addrTemp) - swc1 dest+1, 4(addrTemp) - */ - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.swc1(src, addrTempRegister, 0); - m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4); -#else - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.sdc1(src, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - sdc1 src, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sdc1(src, addrTempRegister, address.offset); - } -#endif - } - - void storeDouble(ImmDouble imm, Address address) - { -#if CPU(BIG_ENDIAN) - store32(Imm32(imm.u.s.msb), address); - store32(Imm32(imm.u.s.lsb), Address(address.base, address.offset + 4)); -#else - store32(Imm32(imm.u.s.lsb), address); - store32(Imm32(imm.u.s.msb), Address(address.base, address.offset + 4)); -#endif - } - - void storeDouble(ImmDouble imm, BaseIndex address) - { -#if CPU(BIG_ENDIAN) - store32(Imm32(imm.u.s.msb), address); - store32(Imm32(imm.u.s.lsb), - BaseIndex(address.base, address.index, address.scale, address.offset + 4)); -#else - store32(Imm32(imm.u.s.lsb), address); - store32(Imm32(imm.u.s.msb), - BaseIndex(address.base, address.index, address.scale, address.offset + 4)); -#endif - } - - void addDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.addd(dest, dest, src); - } - - void addDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - m_assembler.addd(dest, dest, fpTempRegister); - } - - void subDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.subd(dest, dest, src); - } - - void subDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - m_assembler.subd(dest, dest, fpTempRegister); - } - - void mulDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.muld(dest, dest, src); - } - - void mulDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - m_assembler.muld(dest, dest, fpTempRegister); - } - - void divDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.divd(dest, dest, src); - } - - void convertUInt32ToDouble(RegisterID src, FPRegisterID dest) - { - /* - mtc1 src, fpTemp - bgez src, OK // Test the sign bit - cvt.d.w dest, fpTemp - - // Store 0x41F0000000000000 to the fpTemp. - // Then, add fpTemp to dest to compenstate the negative value. - mtc1 zero, fpTemp - lui dataTemp, 0x41F0 - mtc1 dataTemp, fpTemp + 1 - add.d dest, dest, fpTemp - OK: - */ - m_assembler.mtc1(src, fpTempRegister); - m_assembler.bgez(src, 5); - m_assembler.cvtdw(dest, fpTempRegister); - - m_assembler.mtc1(MIPSRegisters::zero, fpTempRegister); - m_assembler.lui(dataTempRegister, 0x41F0); -#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64 - m_assembler.mthc1(dataTempRegister, fpTempRegister); -#else - m_assembler.mtc1(dataTempRegister, FPRegisterID(fpTempRegister + 1)); -#endif - m_assembler.addd(dest, dest, fpTempRegister); - } - - void convertInt32ToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.mtc1(src, fpTempRegister); - m_assembler.cvtdw(dest, fpTempRegister); - } - - void convertInt32ToDouble(Address src, FPRegisterID dest) - { - load32(src, dataTempRegister); - m_assembler.mtc1(dataTempRegister, fpTempRegister); - m_assembler.cvtdw(dest, fpTempRegister); - } - - void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) - { - load32(src.m_ptr, dataTempRegister); - m_assembler.mtc1(dataTempRegister, fpTempRegister); - m_assembler.cvtdw(dest, fpTempRegister); - } - - void insertRelaxationWords() - { - /* We need four words for relaxation. */ - m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops; - m_assembler.nop(); - m_assembler.nop(); - m_assembler.nop(); - } - - Jump branchTrue() - { - m_assembler.appendJump(); - m_assembler.bc1t(); - m_assembler.nop(); - insertRelaxationWords(); - return Jump(m_assembler.newJmpSrc()); - } - - Jump branchFalse() - { - m_assembler.appendJump(); - m_assembler.bc1f(); - m_assembler.nop(); - insertRelaxationWords(); - return Jump(m_assembler.newJmpSrc()); - } - - Jump branchEqual(RegisterID rs, RegisterID rt) - { - m_assembler.appendJump(); - m_assembler.beq(rs, rt, 0); - m_assembler.nop(); - insertRelaxationWords(); - return Jump(m_assembler.newJmpSrc()); - } - - Jump branchNotEqual(RegisterID rs, RegisterID rt) - { - m_assembler.appendJump(); - m_assembler.bne(rs, rt, 0); - m_assembler.nop(); - insertRelaxationWords(); - return Jump(m_assembler.newJmpSrc()); - } - - void fastStoreDouble(FPRegisterID src, RegisterID lo, RegisterID hi) - { -#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64 - m_assembler.mfc1(lo, src); - m_assembler.mfhc1(hi, src); -#else - m_assembler.mfc1(lo, src); - m_assembler.mfc1(hi, FPRegisterID(src + 1)); -#endif - } - - void fastLoadDouble(RegisterID lo, RegisterID hi, FPRegisterID fpReg) - { -#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64 - m_assembler.mtc1(lo, fpReg); - m_assembler.mthc1(hi, fpReg); -#else - m_assembler.mtc1(lo, fpReg); - m_assembler.mtc1(hi, FPRegisterID(fpReg + 1)); -#endif - } - - void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest) - { - m_assembler.cvtsd(dest, src); - } - - Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) - { - if (cond == DoubleEqual) { - m_assembler.ceqd(left, right); - return branchTrue(); - } - if (cond == DoubleNotEqual) { - m_assembler.cueqd(left, right); - return branchFalse(); // false - } - if (cond == DoubleGreaterThan) { - m_assembler.cngtd(left, right); - return branchFalse(); // false - } - if (cond == DoubleGreaterThanOrEqual) { - m_assembler.cnged(left, right); - return branchFalse(); // false - } - if (cond == DoubleLessThan) { - m_assembler.cltd(left, right); - return branchTrue(); - } - if (cond == DoubleLessThanOrEqual) { - m_assembler.cled(left, right); - return branchTrue(); - } - if (cond == DoubleEqualOrUnordered) { - m_assembler.cueqd(left, right); - return branchTrue(); - } - if (cond == DoubleNotEqualOrUnordered) { - m_assembler.ceqd(left, right); - return branchFalse(); // false - } - if (cond == DoubleGreaterThanOrUnordered) { - m_assembler.coled(left, right); - return branchFalse(); // false - } - if (cond == DoubleGreaterThanOrEqualOrUnordered) { - m_assembler.coltd(left, right); - return branchFalse(); // false - } - if (cond == DoubleLessThanOrUnordered) { - m_assembler.cultd(left, right); - return branchTrue(); - } - if (cond == DoubleLessThanOrEqualOrUnordered) { - m_assembler.culed(left, right); - return branchTrue(); - } - ASSERT(0); - - return Jump(); - } - - // Truncates 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, INT_MAX 0x7fffffff). - Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) - { - m_assembler.truncwd(fpTempRegister, src); - m_assembler.mfc1(dest, fpTempRegister); - return branch32(Equal, dest, Imm32(0x7fffffff)); - } - - // Convert 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, 0). - void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) - { - m_assembler.cvtwd(fpTempRegister, src); - m_assembler.mfc1(dest, fpTempRegister); - - // If the result is zero, it might have been -0.0, and the double comparison won't catch this! - failureCases.append(branch32(Equal, dest, MIPSRegisters::zero)); - - // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. - convertInt32ToDouble(dest, fpTemp); - failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src)); - } - - void zeroDouble(FPRegisterID dest) - { -#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64 - m_assembler.mtc1(MIPSRegisters::zero, dest); - m_assembler.mthc1(MIPSRegisters::zero, dest); -#else - m_assembler.mtc1(MIPSRegisters::zero, dest); - m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(dest + 1)); -#endif - } - -private: - // If m_fixedWidth is true, we will generate a fixed number of instructions. - // Otherwise, we can emit any number of instructions. - bool m_fixedWidth; - - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - MIPSAssembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - }; } diff --git a/js/src/assembler/assembler/MacroAssemblerSparc.h b/js/src/assembler/assembler/MacroAssemblerSparc.h index 6639a1da55b..10929a71d4d 100644 --- a/js/src/assembler/assembler/MacroAssemblerSparc.h +++ b/js/src/assembler/assembler/MacroAssemblerSparc.h @@ -11,1451 +11,15 @@ #if ENABLE_ASSEMBLER && WTF_CPU_SPARC -#include "assembler/assembler/SparcAssembler.h" -#include "assembler/assembler/AbstractMacroAssembler.h" - namespace JSC { - class MacroAssemblerSparc : public AbstractMacroAssembler { - public: - enum Condition { - Equal = SparcAssembler::ConditionE, - NotEqual = SparcAssembler::ConditionNE, - Above = SparcAssembler::ConditionGU, - AboveOrEqual = SparcAssembler::ConditionCC, - Below = SparcAssembler::ConditionCS, - BelowOrEqual = SparcAssembler::ConditionLEU, - GreaterThan = SparcAssembler::ConditionG, - GreaterThanOrEqual = SparcAssembler::ConditionGE, - LessThan = SparcAssembler::ConditionL, - LessThanOrEqual = SparcAssembler::ConditionLE, - Overflow = SparcAssembler::ConditionVS, - Signed = SparcAssembler::ConditionNEG, - Zero = SparcAssembler::ConditionE, - NonZero = SparcAssembler::ConditionNE - }; - - enum DoubleCondition { - // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. - DoubleEqual = SparcAssembler::DoubleConditionE, - DoubleNotEqual = SparcAssembler::DoubleConditionNE, - DoubleGreaterThan = SparcAssembler::DoubleConditionG, - DoubleGreaterThanOrEqual = SparcAssembler::DoubleConditionGE, - DoubleLessThan = SparcAssembler::DoubleConditionL, - DoubleLessThanOrEqual = SparcAssembler::DoubleConditionLE, - // If either operand is NaN, these conditions always evaluate to true. - DoubleEqualOrUnordered = SparcAssembler::DoubleConditionUE, - DoubleNotEqualOrUnordered = SparcAssembler::DoubleConditionNE, - DoubleGreaterThanOrUnordered = SparcAssembler::DoubleConditionUG, - DoubleGreaterThanOrEqualOrUnordered = SparcAssembler::DoubleConditionUGE, - DoubleLessThanOrUnordered = SparcAssembler::DoubleConditionUL, - DoubleLessThanOrEqualOrUnordered = SparcAssembler::DoubleConditionULE - }; - - static const RegisterID stackPointerRegister = SparcRegisters::sp; - - static const Scale ScalePtr = TimesFour; - static const unsigned int TotalRegisters = 24; - - void add32(RegisterID src, RegisterID dest) - { - m_assembler.addcc_r(dest, src, dest); - } - - void add32(TrustedImm32 imm, Address address) - { - load32(address, SparcRegisters::g2); - add32(imm, SparcRegisters::g2); - store32(SparcRegisters::g2, address); - } - - void add32(TrustedImm32 imm, RegisterID dest) - { - if (m_assembler.isimm13(imm.m_value)) - m_assembler.addcc_imm(dest, imm.m_value, dest); - else { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3); - m_assembler.addcc_r(dest, SparcRegisters::g3, dest); - } - } - - void add32(Address src, RegisterID dest) - { - load32(src, SparcRegisters::g2); - m_assembler.addcc_r(dest, SparcRegisters::g2, dest); - } - - void and32(Address src, RegisterID dest) - { - load32(src, SparcRegisters::g2); - m_assembler.andcc_r(dest, SparcRegisters::g2, dest); - } - - void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) - { - if (m_assembler.isimm13(imm.m_value)) - m_assembler.addcc_imm(src, imm.m_value, dest); - else { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3); - m_assembler.addcc_r(src, SparcRegisters::g3, dest); - } - } - - void and32(RegisterID src, RegisterID dest) - { - m_assembler.andcc_r(dest, src, dest); - } - - void and32(Imm32 imm, RegisterID dest) - { - if (m_assembler.isimm13(imm.m_value)) - m_assembler.andcc_imm(dest, imm.m_value, dest); - else { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3); - m_assembler.andcc_r(dest, SparcRegisters::g3, dest); - } - } - - - void lshift32(RegisterID shift_amount, RegisterID dest) - { - m_assembler.sll_r(dest, shift_amount, dest); - } - - void lshift32(Imm32 imm, RegisterID dest) - { - // No need to check if imm.m_value. - // The last 5 bit of imm.m_value will be used anyway. - m_assembler.sll_imm(dest, imm.m_value, dest); - } - - void mul32(RegisterID src, RegisterID dest) - { - m_assembler.smulcc_r(dest, src, dest); - } - - void mul32(Imm32 imm, RegisterID src, RegisterID dest) - { - if (m_assembler.isimm13(imm.m_value)) - m_assembler.smulcc_imm(dest, imm.m_value, dest); - else { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3); - m_assembler.smulcc_r(SparcRegisters::g3, dest, dest); - } - } - - void neg32(RegisterID srcDest) - { - m_assembler.subcc_r(SparcRegisters::g0, srcDest, srcDest); - } - - void not32(RegisterID dest) - { - m_assembler.xnorcc_r(dest, SparcRegisters::g0, dest); - } - - void or32(RegisterID src, RegisterID dest) - { - m_assembler.orcc_r(dest, src, dest); - } - - void or32(TrustedImm32 imm, RegisterID dest) - { - if (m_assembler.isimm13(imm.m_value)) - m_assembler.orcc_imm(dest, imm.m_value, dest); - else { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3); - m_assembler.or_r(SparcRegisters::g3, dest, dest); - } - } - - - void or32(Address address, RegisterID dest) - { - load32(address, SparcRegisters::g2); - or32(SparcRegisters::g2, dest); - } - - void rshift32(RegisterID shift_amount, RegisterID dest) - { - m_assembler.sra_r(dest, shift_amount, dest); - } - - void rshift32(Imm32 imm, RegisterID dest) - { - // No need to check if imm.m_value. - // The last 5 bit of imm.m_value will be used anyway. - m_assembler.sra_imm(dest, imm.m_value, dest); - } - - void urshift32(RegisterID shift_amount, RegisterID dest) - { - m_assembler.srl_r(dest, shift_amount, dest); - } - - void urshift32(Imm32 imm, RegisterID dest) - { - // No need to check if imm.m_value. - // The last 5 bit of imm.m_value will be used anyway. - m_assembler.srl_imm(dest, imm.m_value, dest); - } - - void sub32(RegisterID src, RegisterID dest) - { - m_assembler.subcc_r(dest, src, dest); - } - - void sub32(TrustedImm32 imm, RegisterID dest) - { - if (m_assembler.isimm13(imm.m_value)) - m_assembler.subcc_imm(dest, imm.m_value, dest); - else { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3); - m_assembler.subcc_r(dest, SparcRegisters::g3, dest); - } - } - - void sub32(TrustedImm32 imm, Address address) - { - load32(address, SparcRegisters::g2); - sub32(imm, SparcRegisters::g2); - store32(SparcRegisters::g2, address); - } - - void sub32(Address src, RegisterID dest) - { - load32(src, SparcRegisters::g2); - sub32(SparcRegisters::g2, dest); - } - - void xor32(RegisterID src, RegisterID dest) - { - m_assembler.xorcc_r(src, dest, dest); - } - - void xor32(TrustedImm32 imm, RegisterID dest) - { - if (m_assembler.isimm13(imm.m_value)) - m_assembler.xorcc_imm(dest, imm.m_value, dest); - else { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3); - m_assembler.xorcc_r(dest, SparcRegisters::g3, dest); - } - } - - void xor32(Address src, RegisterID dest) - { - load32(src, SparcRegisters::g2); - xor32(SparcRegisters::g2, dest); - } - - void load8(ImplicitAddress address, RegisterID dest) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.ldub_imm(address.base, address.offset, dest); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.ldub_r(address.base, SparcRegisters::g3, dest); - } - } - - void load32(ImplicitAddress address, RegisterID dest) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.lduw_imm(address.base, address.offset, dest); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.lduw_r(address.base, SparcRegisters::g3, dest); - } - } - - void load32(BaseIndex address, RegisterID dest) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.lduw_r(address.base, SparcRegisters::g2, dest); - } - - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset+3), SparcRegisters::g2); - m_assembler.ldub_r(address.base, SparcRegisters::g2, dest); - m_assembler.subcc_imm(SparcRegisters::g2, 1, SparcRegisters::g2); - m_assembler.ldub_r(address.base, SparcRegisters::g2, SparcRegisters::g3); - m_assembler.sll_imm(SparcRegisters::g3, 8, SparcRegisters::g3); - m_assembler.or_r(SparcRegisters::g3, dest, dest); - m_assembler.subcc_imm(SparcRegisters::g2, 1, SparcRegisters::g2); - m_assembler.ldub_r(address.base, SparcRegisters::g2, SparcRegisters::g3); - m_assembler.sll_imm(SparcRegisters::g3, 16, SparcRegisters::g3); - m_assembler.or_r(SparcRegisters::g3, dest, dest); - m_assembler.subcc_imm(SparcRegisters::g2, 1, SparcRegisters::g2); - m_assembler.ldub_r(address.base, SparcRegisters::g2, SparcRegisters::g3); - m_assembler.sll_imm(SparcRegisters::g3, 24, SparcRegisters::g3); - m_assembler.or_r(SparcRegisters::g3, dest, dest); - } - - DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) - { - DataLabel32 dataLabel(this); - m_assembler.move_nocheck(0, SparcRegisters::g3); - m_assembler.lduw_r(address.base, SparcRegisters::g3, dest); - return dataLabel; - } - - DataLabel32 load64WithAddressOffsetPatch(Address address, RegisterID hi, RegisterID lo) - { - DataLabel32 dataLabel(this); - m_assembler.move_nocheck(0, SparcRegisters::g3); - m_assembler.add_imm(SparcRegisters::g3, 4, SparcRegisters::g2); - m_assembler.lduw_r(address.base, SparcRegisters::g3, hi); - m_assembler.lduw_r(address.base, SparcRegisters::g2, lo); - return dataLabel; - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - Label label(this); - load32(address, dest); - return label; - } - - void load16(BaseIndex address, RegisterID dest) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.lduh_r(address.base, SparcRegisters::g2, dest); - } - - void load16(ImplicitAddress address, RegisterID dest) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.lduh_imm(address.base, address.offset, dest); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.lduh_r(address.base, SparcRegisters::g3, dest); - } - } - - void store8(RegisterID src, ImplicitAddress address) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.stb_imm(src, address.base, address.offset); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.stb_r(src, address.base, SparcRegisters::g3); - } - } - - void store8(RegisterID src, BaseIndex address) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.stb_r(src, address.base, SparcRegisters::g2); - } - - void store8(Imm32 imm, ImplicitAddress address) - { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2); - store8(SparcRegisters::g2, address); - } - - void store8(Imm32 imm, BaseIndex address) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - move(imm, SparcRegisters::g3); - m_assembler.stb_r(SparcRegisters::g3, SparcRegisters::g2, address.base); - } - - void store16(RegisterID src, ImplicitAddress address) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.sth_imm(src, address.base, address.offset); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.sth_r(src, address.base, SparcRegisters::g3); - } - } - - void store16(RegisterID src, BaseIndex address) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.sth_r(src, address.base, SparcRegisters::g2); - } - - void store16(Imm32 imm, ImplicitAddress address) - { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2); - store16(SparcRegisters::g2, address); - } - - void store16(Imm32 imm, BaseIndex address) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - move(imm, SparcRegisters::g3); - m_assembler.sth_r(SparcRegisters::g3, SparcRegisters::g2, address.base); - } - - void load8ZeroExtend(BaseIndex address, RegisterID dest) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.ldub_r(address.base, SparcRegisters::g2, dest); - } - - void load8ZeroExtend(Address address, RegisterID dest) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.ldub_imm(address.base, address.offset, dest); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.ldub_r(address.base, SparcRegisters::g3, dest); - } - } - - void load8SignExtend(BaseIndex address, RegisterID dest) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.ldsb_r(address.base, SparcRegisters::g2, dest); - } - - void load8SignExtend(Address address, RegisterID dest) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.ldsb_imm(address.base, address.offset, dest); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.ldsb_r(address.base, SparcRegisters::g3, dest); - } - } - - void load16SignExtend(BaseIndex address, RegisterID dest) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.ldsh_r(address.base, SparcRegisters::g2, dest); - } - - void load16SignExtend(Address address, RegisterID dest) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.ldsh_imm(address.base, address.offset, dest); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.ldsh_r(address.base, SparcRegisters::g3, dest); - } - } - - DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) - { - DataLabel32 dataLabel(this); - // Since this is for patch, we don't check is offset is imm13. - m_assembler.move_nocheck(0, SparcRegisters::g3); - m_assembler.stw_r(src, address.base, SparcRegisters::g3); - return dataLabel; - } - - - DataLabel32 store64WithAddressOffsetPatch(RegisterID hi, RegisterID lo, Address address) - { - DataLabel32 dataLabel(this); - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.add_r(SparcRegisters::g3, address.base, SparcRegisters::g3); - m_assembler.stw_imm(lo, SparcRegisters::g3, 4); - m_assembler.stw_imm(hi, SparcRegisters::g3, 0); - return dataLabel; - } - - DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, RegisterID lo, Address address) - { - DataLabel32 dataLabel(this); - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.add_r(SparcRegisters::g3, address.base, SparcRegisters::g3); - m_assembler.stw_imm(lo, SparcRegisters::g3, 4); - move(hi, SparcRegisters::g2); - m_assembler.stw_imm(SparcRegisters::g2, SparcRegisters::g3, 0); - - return dataLabel; - } - - DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, Imm32 lo, Address address) - { - DataLabel32 dataLabel(this); - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.add_r(SparcRegisters::g3, address.base, SparcRegisters::g3); - move(lo, SparcRegisters::g2); - m_assembler.stw_imm(SparcRegisters::g2, SparcRegisters::g3, 4); - move(hi, SparcRegisters::g2); - m_assembler.stw_imm(SparcRegisters::g2, SparcRegisters::g3, 0); - - return dataLabel; - } - - - void store32(RegisterID src, ImplicitAddress address) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.stw_imm(src, address.base, address.offset); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.stw_r(src, address.base, SparcRegisters::g3); - } - } - - void store32(RegisterID src, BaseIndex address) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.stw_r(src, address.base, SparcRegisters::g2); - } - - void store32(TrustedImm32 imm, BaseIndex address) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - move(imm, SparcRegisters::g3); - m_assembler.stw_r(SparcRegisters::g3, SparcRegisters::g2, address.base); - } - - void store32(TrustedImm32 imm, ImplicitAddress address) - { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2); - store32(SparcRegisters::g2, address); - } - - void store32(RegisterID src, void* address) - { - m_assembler.move_nocheck((int)address, SparcRegisters::g3); - m_assembler.stw_r(src, SparcRegisters::g0, SparcRegisters::g3); - } - - void store32(TrustedImm32 imm, void* address) - { - move(imm, SparcRegisters::g2); - store32(SparcRegisters::g2, address); - } - - void pop(RegisterID dest) - { - m_assembler.lduw_imm(SparcRegisters::sp, 0x68, dest); - m_assembler.addcc_imm(SparcRegisters::sp, 4, SparcRegisters::sp); - } - - void push(RegisterID src) - { - m_assembler.subcc_imm(SparcRegisters::sp, 4, SparcRegisters::sp); - m_assembler.stw_imm(src, SparcRegisters::sp, 0x68); - } - - void push(Address address) - { - load32(address, SparcRegisters::g2); - push(SparcRegisters::g2); - } - - void push(Imm32 imm) - { - move(imm, SparcRegisters::g2); - push(SparcRegisters::g2); - } - - void move(TrustedImm32 imm, RegisterID dest) - { - if (m_assembler.isimm13(imm.m_value)) - m_assembler.or_imm(SparcRegisters::g0, imm.m_value, dest); - else - m_assembler.move_nocheck(imm.m_value, dest); - } - - void move(RegisterID src, RegisterID dest) - { - m_assembler.or_r(src, SparcRegisters::g0, dest); - } - - void move(TrustedImmPtr imm, RegisterID dest) - { - move(Imm32(imm), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - m_assembler.or_r(reg1, SparcRegisters::g0, SparcRegisters::g3); - m_assembler.or_r(reg2, SparcRegisters::g0, reg1); - m_assembler.or_r(SparcRegisters::g3, SparcRegisters::g0, reg2); - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest) - move(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest) - move(src, dest); - } - - Jump branch8(Condition cond, Address left, Imm32 right) - { - load8(left, SparcRegisters::g2); - return branch32(cond, SparcRegisters::g2, right); - } - - Jump branch32_force32(Condition cond, RegisterID left, TrustedImm32 right) - { - m_assembler.move_nocheck(right.m_value, SparcRegisters::g3); - m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right) - { - m_assembler.move_nocheck(right.m_value, SparcRegisters::g2); - return branch32(cond, left, SparcRegisters::g2); - } - - Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel) - { - // Always use move_nocheck, since the value is to be patched. - dataLabel = DataLabel32(this); - m_assembler.move_nocheck(right.m_value, SparcRegisters::g3); - m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branch32(Condition cond, RegisterID left, RegisterID right) - { - m_assembler.subcc_r(left, right, SparcRegisters::g0); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branch32(Condition cond, RegisterID left, TrustedImm32 right) - { - if (m_assembler.isimm13(right.m_value)) - m_assembler.subcc_imm(left, right.m_value, SparcRegisters::g0); - else { - m_assembler.move_nocheck(right.m_value, SparcRegisters::g3); - m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0); - } - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branch32(Condition cond, RegisterID left, Address right) - { - load32(right, SparcRegisters::g2); - return branch32(cond, left, SparcRegisters::g2); - } - - Jump branch32(Condition cond, Address left, RegisterID right) - { - load32(left, SparcRegisters::g2); - return branch32(cond, SparcRegisters::g2, right); - } - - Jump branch32(Condition cond, Address left, TrustedImm32 right) - { - load32(left, SparcRegisters::g2); - return branch32(cond, SparcRegisters::g2, right); - } - - Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right) - { - - load32(left, SparcRegisters::g2); - return branch32(cond, SparcRegisters::g2, right); - } - - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right) - { - load32WithUnalignedHalfWords(left, SparcRegisters::g4); - return branch32(cond, SparcRegisters::g4, right); - } - - Jump branch16(Condition cond, BaseIndex left, RegisterID right) - { - (void)(cond); - (void)(left); - (void)(right); - ASSERT_NOT_REACHED(); - return jump(); - } - - Jump branch16(Condition cond, BaseIndex left, Imm32 right) - { - load16(left, SparcRegisters::g3); - move(right, SparcRegisters::g2); - m_assembler.subcc_r(SparcRegisters::g3, SparcRegisters::g2, SparcRegisters::g0); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - load8(address, SparcRegisters::g2); - return branchTest32(cond, SparcRegisters::g2, mask); - } - - Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) - { - m_assembler.andcc_r(reg, mask, SparcRegisters::g0); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - if (m_assembler.isimm13(mask.m_value)) - m_assembler.andcc_imm(reg, mask.m_value, SparcRegisters::g0); - else { - m_assembler.move_nocheck(mask.m_value, SparcRegisters::g3); - m_assembler.andcc_r(reg, SparcRegisters::g3, SparcRegisters::g0); - } - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - load32(address, SparcRegisters::g2); - return branchTest32(cond, SparcRegisters::g2, mask); - } - - Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - // FIXME. branchTest32 only used by PolyIC. - // PolyIC is not enabled for sparc now. - ASSERT(0); - return jump(); - } - - Jump jump() - { - return Jump(m_assembler.jmp()); - } - - void jump(RegisterID target) - { - m_assembler.jmpl_r(SparcRegisters::g0, target, SparcRegisters::g0); - m_assembler.nop(); - } - - void jump(Address address) - { - load32(address, SparcRegisters::g2); - m_assembler.jmpl_r(SparcRegisters::g2, SparcRegisters::g0, SparcRegisters::g0); - m_assembler.nop(); - } - - void jump(BaseIndex address) - { - load32(address, SparcRegisters::g2); - m_assembler.jmpl_r(SparcRegisters::g2, SparcRegisters::g0, SparcRegisters::g0); - m_assembler.nop(); - } - - Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - m_assembler.addcc_r(src, dest, dest); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (m_assembler.isimm13(imm.m_value)) - m_assembler.addcc_imm(dest, imm.m_value, dest); - else { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3); - m_assembler.addcc_r(dest, SparcRegisters::g3, dest); - } - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchAdd32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - load32(src, SparcRegisters::g2); - return branchAdd32(cond, SparcRegisters::g2, dest); - } - - void mull32(RegisterID src1, RegisterID src2, RegisterID dest) - { - m_assembler.smulcc_r(src1, src2, dest); - } - - Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - m_assembler.smulcc_r(src, dest, dest); - if (cond == Overflow) { - m_assembler.rdy(SparcRegisters::g2); - m_assembler.sra_imm(dest, 31, SparcRegisters::g3); - m_assembler.subcc_r(SparcRegisters::g2, SparcRegisters::g3, SparcRegisters::g2); - cond = NotEqual; - } - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (m_assembler.isimm13(imm.m_value)) - m_assembler.smulcc_imm(src, imm.m_value, dest); - else { - m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3); - m_assembler.smulcc_r(src, SparcRegisters::g3, dest); - } - if (cond == Overflow) { - m_assembler.rdy(SparcRegisters::g2); - m_assembler.sra_imm(dest, 31, SparcRegisters::g3); - m_assembler.subcc_r(SparcRegisters::g2, SparcRegisters::g3, SparcRegisters::g2); - cond = NotEqual; - } - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchMul32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - load32(src, SparcRegisters::g2); - return branchMul32(cond, SparcRegisters::g2, dest); - } - - Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - m_assembler.subcc_r(dest, src, dest); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(imm, dest); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchSub32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - load32(src, SparcRegisters::g2); - return branchSub32(cond, SparcRegisters::g2, dest); - } - - Jump branchSub32(Condition cond, Imm32 imm, Address dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(imm, dest); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchNeg32(Condition cond, RegisterID srcDest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - neg32(srcDest); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); - m_assembler.orcc_r(src, dest, dest); - return Jump(m_assembler.branch(SparcCondition(cond))); - } - - void breakpoint() - { - m_assembler.ta_imm(8); - } - - Call nearCall() - { - return Call(m_assembler.call(), Call::LinkableNear); - } - - Call call(RegisterID target) - { - m_assembler.jmpl_r(target, SparcRegisters::g0, SparcRegisters::o7); - m_assembler.nop(); - JmpSrc jmpSrc; - return Call(jmpSrc, Call::None); - } - - void call(Address address) - { - if (m_assembler.isimm13(address.offset)) { - m_assembler.jmpl_imm(address.base, address.offset, SparcRegisters::o7); - m_assembler.nop(); - } else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.jmpl_r(address.base, SparcRegisters::g3, SparcRegisters::o7); - m_assembler.nop(); - } - } - - void ret() - { - m_assembler.jmpl_imm(SparcRegisters::i7, 8, SparcRegisters::g0); - m_assembler.nop(); - } - - void ret_and_restore() - { - m_assembler.jmpl_imm(SparcRegisters::i7, 8, SparcRegisters::g0); - m_assembler.restore_r(SparcRegisters::g0, SparcRegisters::g0, SparcRegisters::g0); - } - - void save(Imm32 size) - { - if (m_assembler.isimm13(size.m_value)) { - m_assembler.save_imm(SparcRegisters::sp, size.m_value, SparcRegisters::sp); - } else { - m_assembler.move_nocheck(size.m_value, SparcRegisters::g3); - m_assembler.save_r(SparcRegisters::sp, SparcRegisters::g3, SparcRegisters::sp); - } - } - - void set32(Condition cond, Address left, RegisterID right, RegisterID dest) - { - load32(left, SparcRegisters::g2); - set32(cond, SparcRegisters::g2, right, dest); - } - - void set32(Condition cond, RegisterID left, Address right, RegisterID dest) - { - load32(right, SparcRegisters::g2); - set32(cond, left, SparcRegisters::g2, dest); - } - - void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - m_assembler.subcc_r(left, right, SparcRegisters::g0); - m_assembler.or_imm(SparcRegisters::g0, 0, dest); - m_assembler.movcc_imm(1, dest, SparcCondition(cond)); - } - - void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - if (m_assembler.isimm13(right.m_value)) - m_assembler.subcc_imm(left, right.m_value, SparcRegisters::g0); - else { - m_assembler.move_nocheck(right.m_value, SparcRegisters::g3); - m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0); - } - m_assembler.or_imm(SparcRegisters::g0, 0, dest); - m_assembler.movcc_imm(1, dest, SparcCondition(cond)); - } - - void set32(Condition cond, Address left, Imm32 right, RegisterID dest) - { - load32(left, SparcRegisters::g2); - set32(cond, SparcRegisters::g2, right, dest); - } - - void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - // Sparc does not have byte register. - set32(cond, left, right, dest); - } - - void set8(Condition cond, Address left, RegisterID right, RegisterID dest) - { - // Sparc doesn't have byte registers - load32(left, SparcRegisters::g2); - set32(cond, SparcRegisters::g2, right, dest); - } - - void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - // Sparc does not have byte register. - set32(cond, left, right, dest); - } - - void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - load32(address, SparcRegisters::g2); - if (m_assembler.isimm13(mask.m_value)) - m_assembler.andcc_imm(SparcRegisters::g2, mask.m_value, SparcRegisters::g0); - else { - m_assembler.move_nocheck(mask.m_value, SparcRegisters::g3); - m_assembler.andcc_r(SparcRegisters::g3, SparcRegisters::g2, SparcRegisters::g0); - } - m_assembler.or_imm(SparcRegisters::g0, 0, dest); - m_assembler.movcc_imm(1, dest, SparcCondition(cond)); - } - - void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - // Sparc does not have byte register. - setTest32(cond, address, mask, dest); - } - - void lea(Address address, RegisterID dest) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.add_imm(address.base, address.offset, dest); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.add_r(address.base, SparcRegisters::g3, dest); - } - } - - void lea(BaseIndex address, RegisterID dest) - { - // lea only used by PolyIC. - // PolyIC is not enabled for sparc now. - ASSERT(0); - } - - void add32(Imm32 imm, AbsoluteAddress address) - { - load32(address.m_ptr, SparcRegisters::g2); - add32(imm, SparcRegisters::g2); - store32(SparcRegisters::g2, address.m_ptr); - } - - void sub32(TrustedImm32 imm, AbsoluteAddress address) - { - load32(address.m_ptr, SparcRegisters::g2); - sub32(imm, SparcRegisters::g2); - store32(SparcRegisters::g2, address.m_ptr); - } - - void load32(const void* address, RegisterID dest) - { - m_assembler.move_nocheck((int)address, SparcRegisters::g3); - m_assembler.lduw_r(SparcRegisters::g3, SparcRegisters::g0, dest); - } - - Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) - { - load32(left.m_ptr, SparcRegisters::g2); - return branch32(cond, SparcRegisters::g2, right); - } - - Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right) - { - load32(left.m_ptr, SparcRegisters::g2); - return branch32(cond, SparcRegisters::g2, right); - } - - Call call() - { - m_assembler.rdpc(SparcRegisters::g2); - m_assembler.add_imm(SparcRegisters::g2, 32, SparcRegisters::g2); - m_assembler.stw_imm(SparcRegisters::g2, SparcRegisters::fp, -8); - Call cl = Call(m_assembler.call(), Call::Linkable); - m_assembler.lduw_imm(SparcRegisters::fp, -8, SparcRegisters::g2); - m_assembler.jmpl_imm(SparcRegisters::g2, 0, SparcRegisters::g0); - m_assembler.nop(); - return cl; - } - - Call tailRecursiveCall() - { - return Call::fromTailJump(jump()); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - return Call::fromTailJump(oldJump); - } - - DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) - { - DataLabelPtr dataLabel(this); - Imm32 imm = Imm32(initialValue); - m_assembler.move_nocheck(imm.m_value, dest); - return dataLabel; - } - - DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest) - { - DataLabel32 dataLabel(this); - m_assembler.move_nocheck(initialValue.m_value, dest); - return dataLabel; - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - dataLabel = moveWithPatch(initialRightValue, SparcRegisters::g2); - Jump jump = branch32(cond, left, SparcRegisters::g2); - return jump; - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - load32(left, SparcRegisters::g2); - dataLabel = moveWithPatch(initialRightValue, SparcRegisters::g3); - Jump jump = branch32(cond, SparcRegisters::g3, SparcRegisters::g2); - return jump; - } - - DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) - { - DataLabelPtr dataLabel = moveWithPatch(initialValue, SparcRegisters::g2); - store32(SparcRegisters::g2, address); - return dataLabel; - } - - DataLabelPtr storePtrWithPatch(ImplicitAddress address) - { - return storePtrWithPatch(ImmPtr(0), address); - } - - // Floating point operators - static bool supportsFloatingPoint() - { - return true; - } - - static bool supportsFloatingPointTruncate() - { - return true; - } - - static bool supportsFloatingPointSqrt() - { - return true; - } - - void moveDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fmovd_r(src, dest); - } - - void loadFloat(BaseIndex address, FPRegisterID dest) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.ldf_r(address.base, SparcRegisters::g2, dest); - m_assembler.fstod_r(dest, dest); - } - - void loadFloat(ImplicitAddress address, FPRegisterID dest) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.ldf_imm(address.base, address.offset, dest); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.ldf_r(address.base, SparcRegisters::g3, dest); - } - m_assembler.fstod_r(dest, dest); - } - - void loadFloat(const void* address, FPRegisterID dest) - { - m_assembler.move_nocheck((int)address, SparcRegisters::g3); - m_assembler.ldf_r(SparcRegisters::g3, SparcRegisters::g0, dest); - m_assembler.fstod_r(dest, dest); - } - - void loadDouble(BaseIndex address, FPRegisterID dest) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.ldf_r(address.base, SparcRegisters::g2, dest); - m_assembler.add_imm(SparcRegisters::g2, 4, SparcRegisters::g2); - m_assembler.ldf_r(address.base, SparcRegisters::g2, dest + 1); - } - - void loadDouble(ImplicitAddress address, FPRegisterID dest) - { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.ldf_r(address.base, SparcRegisters::g3, dest); - m_assembler.add_imm(SparcRegisters::g3, 4, SparcRegisters::g3); - m_assembler.ldf_r(address.base, SparcRegisters::g3, dest + 1); - } - - DataLabelPtr loadDouble(const void* address, FPRegisterID dest) - { - DataLabelPtr dataLabel(this); - m_assembler.move_nocheck((int)address, SparcRegisters::g3); - m_assembler.ldf_imm(SparcRegisters::g3, 0, dest); - m_assembler.ldf_imm(SparcRegisters::g3, 4, dest + 1); - return dataLabel; - } - - void storeFloat(FPRegisterID src, BaseIndex address) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.stf_r(src, address.base, SparcRegisters::g2); - } - - void storeFloat(FPRegisterID src, ImplicitAddress address) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.stf_imm(src, address.base, address.offset); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.stf_r(src, address.base, SparcRegisters::g3); - } - } - - void storeFloat(ImmDouble imm, Address address) - { - union { - float f; - uint32_t u32; - } u; - u.f = imm.u.d; - store32(Imm32(u.u32), address); - } - - void storeFloat(ImmDouble imm, BaseIndex address) - { - union { - float f; - uint32_t u32; - } u; - u.f = imm.u.d; - store32(Imm32(u.u32), address); - } - - void storeDouble(FPRegisterID src, BaseIndex address) - { - m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); - add32(Imm32(address.offset), SparcRegisters::g2); - m_assembler.stf_r(src, address.base, SparcRegisters::g2); - m_assembler.add_imm(SparcRegisters::g2, 4, SparcRegisters::g2); - m_assembler.stf_r(src + 1, address.base, SparcRegisters::g2); - } - - void storeDouble(FPRegisterID src, ImplicitAddress address) - { - if (m_assembler.isimm13(address.offset + 4)) { - m_assembler.stf_imm(src, address.base, address.offset); - m_assembler.stf_imm(src + 1, address.base, address.offset + 4); - } else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.stf_r(src, address.base, SparcRegisters::g3); - m_assembler.add_imm(SparcRegisters::g3, 4, SparcRegisters::g3); - m_assembler.stf_r(src + 1, address.base, SparcRegisters::g3); - } - } - - void storeDouble(ImmDouble imm, Address address) - { - store32(Imm32(imm.u.s.msb), address); - store32(Imm32(imm.u.s.lsb), Address(address.base, address.offset + 4)); - } - - void storeDouble(ImmDouble imm, BaseIndex address) - { - store32(Imm32(imm.u.s.msb), address); - store32(Imm32(imm.u.s.lsb), - BaseIndex(address.base, address.index, address.scale, address.offset + 4)); - } - - void addDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.faddd_r(src, dest, dest); - } - - void addDouble(Address src, FPRegisterID dest) - { - loadDouble(src, SparcRegisters::f30); - m_assembler.faddd_r(SparcRegisters::f30, dest, dest); - } - - void divDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fdivd_r(dest, src, dest); - } - - void divDouble(Address src, FPRegisterID dest) - { - loadDouble(src, SparcRegisters::f30); - m_assembler.fdivd_r(dest, SparcRegisters::f30, dest); - } - - void subDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fsubd_r(dest, src, dest); - } - - void subDouble(Address src, FPRegisterID dest) - { - loadDouble(src, SparcRegisters::f30); - m_assembler.fsubd_r(dest, SparcRegisters::f30, dest); - } - - void mulDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fmuld_r(src, dest, dest); - } - - void mulDouble(Address src, FPRegisterID dest) - { - loadDouble(src, SparcRegisters::f30); - m_assembler.fmuld_r(SparcRegisters::f30, dest, dest); - } - - void absDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fabsd_r(src, dest); - } - - void sqrtDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fsqrtd_r(src, dest); - } - - void negDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fnegd_r(src, dest); - } - - void convertUInt32ToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.move_nocheck(0x43300000, SparcRegisters::g1); - m_assembler.stw_imm(SparcRegisters::g1, SparcRegisters::sp, 0x60); - m_assembler.stw_imm(src, SparcRegisters::sp, 0x64); - m_assembler.ldf_imm(SparcRegisters::sp, 0x60, SparcRegisters::f30); - m_assembler.ldf_imm(SparcRegisters::sp, 0x64, SparcRegisters::f31); - m_assembler.stw_imm(SparcRegisters::g0, SparcRegisters::sp, 0x64); - m_assembler.ldf_imm(SparcRegisters::sp, 0x60, dest); - m_assembler.ldf_imm(SparcRegisters::sp, 0x64, dest + 1); - m_assembler.fsubd_r(SparcRegisters::f30, dest, dest); - m_assembler.fabss_r(dest, dest); - } - - void convertInt32ToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.stw_imm(src, SparcRegisters::sp, 0x60); - m_assembler.ldf_imm(SparcRegisters::sp, 0x60, dest); - m_assembler.fitod_r(dest, dest); - } - - void convertInt32ToDouble(Address address, FPRegisterID dest) - { - if (m_assembler.isimm13(address.offset)) - m_assembler.ldf_imm(address.base, address.offset, dest); - else { - m_assembler.move_nocheck(address.offset, SparcRegisters::g3); - m_assembler.ldf_r(address.base, SparcRegisters::g3, dest); - } - m_assembler.fitod_r(dest, dest); - } - - void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) - { - m_assembler.move_nocheck((int)src.m_ptr, SparcRegisters::g3); - m_assembler.ldf_r(SparcRegisters::g3, SparcRegisters::g0, dest); - m_assembler.fitod_r(dest, dest); - } - - void fastLoadDouble(RegisterID lo, RegisterID hi, FPRegisterID fpReg) - { - m_assembler.stw_imm(lo, SparcRegisters::sp, 0x64); - m_assembler.stw_imm(hi, SparcRegisters::sp, 0x60); - m_assembler.ldf_imm(SparcRegisters::sp, 0x60, fpReg); - m_assembler.ldf_imm(SparcRegisters::sp, 0x64, fpReg + 1); - } - - void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest) - { - m_assembler.fdtos_r(src, dest); - } - - void breakDoubleTo32(FPRegisterID srcDest, RegisterID typeReg, RegisterID dataReg) { - // We don't assume stack is aligned to 8. - // Always using stf, ldf instead of stdf, lddf. - m_assembler.stf_imm(srcDest, SparcRegisters::sp, 0x60); - m_assembler.stf_imm(srcDest + 1, SparcRegisters::sp, 0x64); - m_assembler.lduw_imm(SparcRegisters::sp, 0x60, typeReg); - m_assembler.lduw_imm(SparcRegisters::sp, 0x64, dataReg); - } - - Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) - { - m_assembler.fcmpd_r(left, right); - return Jump(m_assembler.fbranch(SparcDoubleCondition(cond))); - } - - // Truncates 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, INT_MIN). - Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) - { - m_assembler.fdtoi_r(src, SparcRegisters::f30); - m_assembler.stf_imm(SparcRegisters::f30, SparcRegisters::sp, 0x60); - m_assembler.lduw_imm(SparcRegisters::sp, 0x60, dest); - - m_assembler.or_r(SparcRegisters::g0, SparcRegisters::g0, SparcRegisters::g2); - m_assembler.move_nocheck(0x80000000, SparcRegisters::g3); - m_assembler.subcc_r(SparcRegisters::g3, dest, SparcRegisters::g0); - m_assembler.movcc_imm(1, SparcRegisters::g2, SparcCondition(Equal)); - m_assembler.move_nocheck(0x7fffffff, SparcRegisters::g3); - m_assembler.subcc_r(SparcRegisters::g3, dest, SparcRegisters::g0); - m_assembler.movcc_imm(1, SparcRegisters::g2, SparcCondition(Equal)); - - return branch32(Equal, SparcRegisters::g2, Imm32(1)); - } - - // Convert 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, 0). - void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) - { - m_assembler.fdtoi_r(src, SparcRegisters::f30); - m_assembler.stf_imm(SparcRegisters::f30, SparcRegisters::sp, 0x60); - m_assembler.lduw_imm(SparcRegisters::sp, 0x60, dest); - - // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. - m_assembler.fitod_r(SparcRegisters::f30, SparcRegisters::f30); - failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, SparcRegisters::f30)); - - // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0 - failureCases.append(branchTest32(Zero, dest)); - } - - void zeroDouble(FPRegisterID srcDest) - { - fastLoadDouble(SparcRegisters::g0, SparcRegisters::g0, srcDest); - } - - protected: - SparcAssembler::Condition SparcCondition(Condition cond) - { - return static_cast(cond); - } - - SparcAssembler::DoubleCondition SparcDoubleCondition(DoubleCondition cond) - { - return static_cast(cond); - } - - private: - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - SparcAssembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - SparcAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - SparcAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - }; +class MacroAssemblerSparc { +public: + static bool supportsFloatingPoint() { return true; } +}; } - #endif // ENABLE(ASSEMBLER) && CPU(SPARC) #endif /* assembler_assembler_MacroAssemblerSparc_h */ diff --git a/js/src/assembler/assembler/MacroAssemblerX86.h b/js/src/assembler/assembler/MacroAssemblerX86.h index f1159ed2a41..14df66716ec 100644 --- a/js/src/assembler/assembler/MacroAssemblerX86.h +++ b/js/src/assembler/assembler/MacroAssemblerX86.h @@ -40,216 +40,7 @@ namespace JSC { class MacroAssemblerX86 : public MacroAssemblerX86Common { public: - MacroAssemblerX86() - { } - - static const Scale ScalePtr = TimesFour; - static const unsigned int TotalRegisters = 8; - - using MacroAssemblerX86Common::add32; - using MacroAssemblerX86Common::and32; - using MacroAssemblerX86Common::sub32; - using MacroAssemblerX86Common::or32; - using MacroAssemblerX86Common::load32; - using MacroAssemblerX86Common::store32; - using MacroAssemblerX86Common::branch32; - using MacroAssemblerX86Common::call; - using MacroAssemblerX86Common::loadDouble; - using MacroAssemblerX86Common::storeDouble; - using MacroAssemblerX86Common::convertInt32ToDouble; - - void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) - { - m_assembler.leal_mr(imm.m_value, src, dest); - } - - void lea(Address address, RegisterID dest) - { - m_assembler.leal_mr(address.offset, address.base, dest); - } - - void lea(BaseIndex address, RegisterID dest) - { - m_assembler.leal_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void add32(Imm32 imm, AbsoluteAddress address) - { - m_assembler.addl_im(imm.m_value, address.m_ptr); - } - - void addWithCarry32(Imm32 imm, AbsoluteAddress address) - { - m_assembler.adcl_im(imm.m_value, address.m_ptr); - } - - void and32(Imm32 imm, AbsoluteAddress address) - { - m_assembler.andl_im(imm.m_value, address.m_ptr); - } - - void or32(TrustedImm32 imm, AbsoluteAddress address) - { - m_assembler.orl_im(imm.m_value, address.m_ptr); - } - - void sub32(TrustedImm32 imm, AbsoluteAddress address) - { - m_assembler.subl_im(imm.m_value, address.m_ptr); - } - - void load32(void* address, RegisterID dest) - { - m_assembler.movl_mr(address, dest); - } - - void storeDouble(ImmDouble imm, Address address) - { - store32(Imm32(imm.u.s.lsb), address); - store32(Imm32(imm.u.s.msb), Address(address.base, address.offset + 4)); - } - - void storeDouble(ImmDouble imm, BaseIndex address) - { - store32(Imm32(imm.u.s.lsb), address); - store32(Imm32(imm.u.s.msb), - BaseIndex(address.base, address.index, address.scale, address.offset + 4)); - } - - DataLabelPtr loadDouble(const void* address, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.movsd_mr(address, dest); - return DataLabelPtr(this); - } - - void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) - { - m_assembler.cvtsi2sd_mr(src.m_ptr, dest); - } - - void convertUInt32ToDouble(RegisterID srcDest, FPRegisterID dest) - { - // Trick is from nanojit/Nativei386.cpp, asm_ui2d. - static const double NegativeOne = 2147483648.0; - - // src is [0, 2^32-1] - sub32(Imm32(0x80000000), srcDest); - - // Now src is [-2^31, 2^31-1] - int range, but not the same value. - zeroDouble(dest); - convertInt32ToDouble(srcDest, dest); - - // dest is now a double with the int range. - // correct the double value by adding (0x80000000). - move(ImmPtr(&NegativeOne), srcDest); - addDouble(Address(srcDest), dest); - } - - void store32(TrustedImm32 imm, void* address) - { - m_assembler.movl_i32m(imm.m_value, address); - } - - void store32(RegisterID src, void* address) - { - m_assembler.movl_rm(src, address); - } - - Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) - { - m_assembler.cmpl_rm(right, left.m_ptr); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right) - { - m_assembler.cmpl_im(right.m_value, left.m_ptr); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Call call() - { - return Call(m_assembler.call(), Call::Linkable); - } - - Call tailRecursiveCall() - { - return Call::fromTailJump(jump()); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - return Call::fromTailJump(oldJump); - } - - - DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) - { - m_assembler.movl_i32r(initialValue.asIntptr(), dest); - return DataLabelPtr(this); - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - m_assembler.cmpl_ir_force32(initialRightValue.asIntptr(), left); - dataLabel = DataLabelPtr(this); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - m_assembler.cmpl_im_force32(initialRightValue.asIntptr(), left.offset, left.base); - dataLabel = DataLabelPtr(this); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) - { - m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base); - return DataLabelPtr(this); - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - Label label(this); - load32(address, dest); - return label; - } - - void pushAllRegs() - { - m_assembler.pusha(); - } - - void popAllRegs() - { - m_assembler.popa(); - } - static bool supportsFloatingPoint() { return isSSE2Present(); } - // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() - static bool supportsFloatingPointTruncate() { return isSSE2Present(); } - static bool supportsFloatingPointSqrt() { return isSSE2Present(); } - -private: - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - X86Assembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } }; } // namespace JSC diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.h b/js/src/assembler/assembler/MacroAssemblerX86Common.h index 6b6078bf49c..da75678b391 100644 --- a/js/src/assembler/assembler/MacroAssemblerX86Common.h +++ b/js/src/assembler/assembler/MacroAssemblerX86Common.h @@ -35,1229 +35,11 @@ #if ENABLE_ASSEMBLER #include "assembler/assembler/X86Assembler.h" -#include "assembler/assembler/AbstractMacroAssembler.h" namespace JSC { -class MacroAssemblerX86Common : public AbstractMacroAssembler { - static const int DoubleConditionBitInvert = 0x10; - static const int DoubleConditionBitSpecial = 0x20; - static const int DoubleConditionBits = DoubleConditionBitInvert | DoubleConditionBitSpecial; - -protected: -#if WTF_CPU_X86_64 - static const X86Registers::RegisterID scratchRegister = X86Registers::r11; -#endif - +class MacroAssemblerX86Common { public: - - enum Condition { - Equal = X86Assembler::ConditionE, - NotEqual = X86Assembler::ConditionNE, - Above = X86Assembler::ConditionA, - AboveOrEqual = X86Assembler::ConditionAE, - Below = X86Assembler::ConditionB, - BelowOrEqual = X86Assembler::ConditionBE, - GreaterThan = X86Assembler::ConditionG, - GreaterThanOrEqual = X86Assembler::ConditionGE, - LessThan = X86Assembler::ConditionL, - LessThanOrEqual = X86Assembler::ConditionLE, - Overflow = X86Assembler::ConditionO, - Signed = X86Assembler::ConditionS, - Zero = X86Assembler::ConditionE, - NonZero = X86Assembler::ConditionNE - }; - - enum DoubleCondition { - // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. - DoubleEqual = X86Assembler::ConditionE | DoubleConditionBitSpecial, - DoubleNotEqual = X86Assembler::ConditionNE, - DoubleGreaterThan = X86Assembler::ConditionA, - DoubleGreaterThanOrEqual = X86Assembler::ConditionAE, - DoubleLessThan = X86Assembler::ConditionA | DoubleConditionBitInvert, - DoubleLessThanOrEqual = X86Assembler::ConditionAE | DoubleConditionBitInvert, - // If either operand is NaN, these conditions always evaluate to true. - DoubleEqualOrUnordered = X86Assembler::ConditionE, - DoubleNotEqualOrUnordered = X86Assembler::ConditionNE | DoubleConditionBitSpecial, - DoubleGreaterThanOrUnordered = X86Assembler::ConditionB | DoubleConditionBitInvert, - DoubleGreaterThanOrEqualOrUnordered = X86Assembler::ConditionBE | DoubleConditionBitInvert, - DoubleLessThanOrUnordered = X86Assembler::ConditionB, - DoubleLessThanOrEqualOrUnordered = X86Assembler::ConditionBE - }; - static void staticAsserts() { - COMPILE_ASSERT( - !((X86Assembler::ConditionE | X86Assembler::ConditionNE | X86Assembler::ConditionA | X86Assembler::ConditionAE | X86Assembler::ConditionB | X86Assembler::ConditionBE) & DoubleConditionBits), - DoubleConditionBits_should_not_interfere_with_X86Assembler_Condition_codes); - } - - static const RegisterID stackPointerRegister = X86Registers::esp; - - static inline bool CanUse8Bit(RegisterID reg) { - return !!((1 << reg) & ~((1 << X86Registers::esp) | - (1 << X86Registers::edi) | - (1 << X86Registers::esi) | - (1 << X86Registers::ebp))); - } - - // Integer arithmetic operations: - // - // Operations are typically two operand - operation(source, srcDst) - // For many operations the source may be an Imm32, the srcDst operand - // may often be a memory location (explictly described using an Address - // object). - - void add32(RegisterID src, RegisterID dest) - { - m_assembler.addl_rr(src, dest); - } - - void add32(TrustedImm32 imm, Address address) - { - m_assembler.addl_im(imm.m_value, address.offset, address.base); - } - - void add32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.addl_ir(imm.m_value, dest); - } - - void add32(Address src, RegisterID dest) - { - m_assembler.addl_mr(src.offset, src.base, dest); - } - - void add32(RegisterID src, Address dest) - { - m_assembler.addl_rm(src, dest.offset, dest.base); - } - - void and32(RegisterID src, RegisterID dest) - { - m_assembler.andl_rr(src, dest); - } - - void and32(Imm32 imm, RegisterID dest) - { - m_assembler.andl_ir(imm.m_value, dest); - } - - void and32(RegisterID src, Address dest) - { - m_assembler.andl_rm(src, dest.offset, dest.base); - } - - void and32(Address src, RegisterID dest) - { - m_assembler.andl_mr(src.offset, src.base, dest); - } - - void and32(Imm32 imm, Address address) - { - m_assembler.andl_im(imm.m_value, address.offset, address.base); - } - - void lshift32(Imm32 imm, RegisterID dest) - { - m_assembler.shll_i8r(imm.m_value, dest); - } - - void lshift32(RegisterID shift_amount, RegisterID dest) - { - // On x86 we can only shift by ecx; if asked to shift by another register we'll - // need rejig the shift amount into ecx first, and restore the registers afterwards. - if (shift_amount != X86Registers::ecx) { - swap(shift_amount, X86Registers::ecx); - - // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx" - if (dest == shift_amount) - m_assembler.shll_CLr(X86Registers::ecx); - // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx" - else if (dest == X86Registers::ecx) - m_assembler.shll_CLr(shift_amount); - // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx" - else - m_assembler.shll_CLr(dest); - - swap(shift_amount, X86Registers::ecx); - } else - m_assembler.shll_CLr(dest); - } - - void mul32(RegisterID src, RegisterID dest) - { - m_assembler.imull_rr(src, dest); - } - - void mul32(Address src, RegisterID dest) - { - m_assembler.imull_mr(src.offset, src.base, dest); - } - - void mul32(Imm32 imm, RegisterID src, RegisterID dest) - { - m_assembler.imull_i32r(src, imm.m_value, dest); - } - - void idiv(RegisterID reg) - { - m_assembler.cdq(); - m_assembler.idivl_r(reg); - } - - void neg32(RegisterID srcDest) - { - m_assembler.negl_r(srcDest); - } - - void neg32(Address srcDest) - { - m_assembler.negl_m(srcDest.offset, srcDest.base); - } - - void not32(RegisterID srcDest) - { - m_assembler.notl_r(srcDest); - } - - void not32(Address srcDest) - { - m_assembler.notl_m(srcDest.offset, srcDest.base); - } - - void or32(RegisterID src, RegisterID dest) - { - m_assembler.orl_rr(src, dest); - } - - void or32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.orl_ir(imm.m_value, dest); - } - - void or32(RegisterID src, Address dest) - { - m_assembler.orl_rm(src, dest.offset, dest.base); - } - - void or32(Address src, RegisterID dest) - { - m_assembler.orl_mr(src.offset, src.base, dest); - } - - void or32(TrustedImm32 imm, Address address) - { - m_assembler.orl_im(imm.m_value, address.offset, address.base); - } - - void rshift32(RegisterID shift_amount, RegisterID dest) - { - // On x86 we can only shift by ecx; if asked to shift by another register we'll - // need rejig the shift amount into ecx first, and restore the registers afterwards. - if (shift_amount != X86Registers::ecx) { - swap(shift_amount, X86Registers::ecx); - - // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx" - if (dest == shift_amount) - m_assembler.sarl_CLr(X86Registers::ecx); - // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx" - else if (dest == X86Registers::ecx) - m_assembler.sarl_CLr(shift_amount); - // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx" - else - m_assembler.sarl_CLr(dest); - - swap(shift_amount, X86Registers::ecx); - } else - m_assembler.sarl_CLr(dest); - } - - void rshift32(Imm32 imm, RegisterID dest) - { - m_assembler.sarl_i8r(imm.m_value, dest); - } - - void urshift32(RegisterID shift_amount, RegisterID dest) - { - // On x86 we can only shift by ecx; if asked to shift by another register we'll - // need rejig the shift amount into ecx first, and restore the registers afterwards. - if (shift_amount != X86Registers::ecx) { - swap(shift_amount, X86Registers::ecx); - - // E.g. transform "shrl %eax, %eax" -> "xchgl %eax, %ecx; shrl %ecx, %ecx; xchgl %eax, %ecx" - if (dest == shift_amount) - m_assembler.shrl_CLr(X86Registers::ecx); - // E.g. transform "shrl %eax, %ecx" -> "xchgl %eax, %ecx; shrl %ecx, %eax; xchgl %eax, %ecx" - else if (dest == X86Registers::ecx) - m_assembler.shrl_CLr(shift_amount); - // E.g. transform "shrl %eax, %ebx" -> "xchgl %eax, %ecx; shrl %ecx, %ebx; xchgl %eax, %ecx" - else - m_assembler.shrl_CLr(dest); - - swap(shift_amount, X86Registers::ecx); - } else - m_assembler.shrl_CLr(dest); - } - - void urshift32(Imm32 imm, RegisterID dest) - { - m_assembler.shrl_i8r(imm.m_value, dest); - } - - void sub32(RegisterID src, RegisterID dest) - { - m_assembler.subl_rr(src, dest); - } - - void sub32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.subl_ir(imm.m_value, dest); - } - - void sub32(TrustedImm32 imm, Address address) - { - m_assembler.subl_im(imm.m_value, address.offset, address.base); - } - - void sub32(Address src, RegisterID dest) - { - m_assembler.subl_mr(src.offset, src.base, dest); - } - - void sub32(RegisterID src, Address dest) - { - m_assembler.subl_rm(src, dest.offset, dest.base); - } - - - void xor32(RegisterID src, RegisterID dest) - { - m_assembler.xorl_rr(src, dest); - } - - void xor32(TrustedImm32 imm, Address dest) - { - m_assembler.xorl_im(imm.m_value, dest.offset, dest.base); - } - - void xor32(TrustedImm32 imm, RegisterID dest) - { - m_assembler.xorl_ir(imm.m_value, dest); - } - - void xor32(RegisterID src, Address dest) - { - m_assembler.xorl_rm(src, dest.offset, dest.base); - } - - void xor32(Address src, RegisterID dest) - { - m_assembler.xorl_mr(src.offset, src.base, dest); - } - - void sqrtDouble(FPRegisterID src, FPRegisterID dst) - { - m_assembler.sqrtsd_rr(src, dst); - } - - // Memory access operations: - // - // Loads are of the form load(address, destination) and stores of the form - // store(source, address). The source for a store may be an Imm32. Address - // operand objects to loads and store will be implicitly constructed if a - // register is passed. - - void load32(ImplicitAddress address, RegisterID dest) - { - m_assembler.movl_mr(address.offset, address.base, dest); - } - - void load32(BaseIndex address, RegisterID dest) - { - m_assembler.movl_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) - { - load32(address, dest); - } - - DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) - { - m_assembler.movl_mr_disp32(address.offset, address.base, dest); - return DataLabel32(this); - } - - void store8(RegisterID src, Address address) - { - m_assembler.movb_rm(src, address.offset, address.base); - } - - void store8(RegisterID src, BaseIndex address) - { - m_assembler.movb_rm(src, address.offset, address.base, address.index, address.scale); - } - - void store16(RegisterID src, Address address) - { - m_assembler.movw_rm(src, address.offset, address.base); - } - - void store16(RegisterID src, BaseIndex address) - { - m_assembler.movw_rm(src, address.offset, address.base, address.index, address.scale); - } - - void load8(BaseIndex address, RegisterID dest) - { - load8ZeroExtend(address, dest); - } - - void load8ZeroExtend(BaseIndex address, RegisterID dest) - { - m_assembler.movzbl_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void load8ZeroExtend(Address address, RegisterID dest) - { - m_assembler.movzbl_mr(address.offset, address.base, dest); - } - - void load8SignExtend(BaseIndex address, RegisterID dest) - { - m_assembler.movsbl_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void load8SignExtend(Address address, RegisterID dest) - { - m_assembler.movsbl_mr(address.offset, address.base, dest); - } - - void load16SignExtend(BaseIndex address, RegisterID dest) - { - m_assembler.movswl_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void load16SignExtend(Address address, RegisterID dest) - { - m_assembler.movswl_mr(address.offset, address.base, dest); - } - - void load16(BaseIndex address, RegisterID dest) - { - m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void load16(Address address, RegisterID dest) - { - m_assembler.movzwl_mr(address.offset, address.base, dest); - } - - void load16Unaligned(BaseIndex address, RegisterID dest) - { - load16(address, dest); - } - - DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) - { - m_assembler.movl_rm_disp32(src, address.offset, address.base); - return DataLabel32(this); - } - - void store32(RegisterID src, ImplicitAddress address) - { - m_assembler.movl_rm(src, address.offset, address.base); - } - - void store32(RegisterID src, BaseIndex address) - { - m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale); - } - - void store32(TrustedImm32 imm, BaseIndex address) - { - m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale); - } - - void store16(Imm32 imm, BaseIndex address) - { - m_assembler.movw_i16m(imm.m_value, address.offset, address.base, address.index, address.scale); - } - - void store8(Imm32 imm, BaseIndex address) - { - m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale); - } - - void store32(TrustedImm32 imm, ImplicitAddress address) - { - m_assembler.movl_i32m(imm.m_value, address.offset, address.base); - } - - void store16(Imm32 imm, ImplicitAddress address) - { - m_assembler.movw_i16m(imm.m_value, address.offset, address.base); - } - - void store8(Imm32 imm, ImplicitAddress address) - { - m_assembler.movb_i8m(imm.m_value, address.offset, address.base); - } - - - // Floating-point operation: - // - // Presently only supports SSE, not x87 floating point. - - void moveDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.movsd_rr(src, dest); - } - - void loadFloat(ImplicitAddress address, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.movss_mr(address.offset, address.base, dest); - m_assembler.cvtss2sd_rr(dest, dest); - } - - void loadFloat(BaseIndex address, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.movss_mr(address.offset, address.base, address.index, address.scale, dest); - m_assembler.cvtss2sd_rr(dest, dest); - } - - void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.cvtsd2ss_rr(src, dest); - } - - void loadDouble(ImplicitAddress address, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.movsd_mr(address.offset, address.base, dest); - } - - void loadDouble(BaseIndex address, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.movsd_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void storeFloat(ImmDouble imm, Address address) - { - union { - float f; - uint32_t u32; - } u; - u.f = imm.u.d; - store32(Imm32(u.u32), address); - } - - void storeFloat(ImmDouble imm, BaseIndex address) - { - union { - float f; - uint32_t u32; - } u; - u.f = imm.u.d; - store32(Imm32(u.u32), address); - } - - void storeDouble(FPRegisterID src, ImplicitAddress address) - { - ASSERT(isSSE2Present()); - m_assembler.movsd_rm(src, address.offset, address.base); - } - - void storeFloat(FPRegisterID src, ImplicitAddress address) - { - ASSERT(isSSE2Present()); - m_assembler.movss_rm(src, address.offset, address.base); - } - - void storeDouble(FPRegisterID src, BaseIndex address) - { - ASSERT(isSSE2Present()); - m_assembler.movsd_rm(src, address.offset, address.base, address.index, address.scale); - } - - void storeFloat(FPRegisterID src, BaseIndex address) - { - ASSERT(isSSE2Present()); - m_assembler.movss_rm(src, address.offset, address.base, address.index, address.scale); - } - - void addDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.addsd_rr(src, dest); - } - - void addDouble(Address src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.addsd_mr(src.offset, src.base, dest); - } - - void divDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.divsd_rr(src, dest); - } - - void divDouble(Address src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.divsd_mr(src.offset, src.base, dest); - } - - void subDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.subsd_rr(src, dest); - } - - void subDouble(Address src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.subsd_mr(src.offset, src.base, dest); - } - - void mulDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.mulsd_rr(src, dest); - } - - void mulDouble(Address src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.mulsd_mr(src.offset, src.base, dest); - } - - void xorDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.xorpd_rr(src, dest); - } - - void andDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.andpd_rr(src, dest); - } - - void absDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - /* Compile abs(x) as x & -x. */ - zeroDouble(dest); - subDouble(src, dest); - andDouble(src, dest); - } - - void convertInt32ToDouble(RegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.cvtsi2sd_rr(src, dest); - } - - void convertInt32ToDouble(Address src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.cvtsi2sd_mr(src.offset, src.base, dest); - } - - Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) - { - ASSERT(isSSE2Present()); - - if (cond & DoubleConditionBitInvert) - m_assembler.ucomisd_rr(left, right); - else - m_assembler.ucomisd_rr(right, left); - - if (cond == DoubleEqual) { - Jump isUnordered(m_assembler.jp()); - Jump result = Jump(m_assembler.je()); - isUnordered.link(this); - return result; - } else if (cond == DoubleNotEqualOrUnordered) { - Jump isUnordered(m_assembler.jp()); - Jump isEqual(m_assembler.je()); - isUnordered.link(this); - Jump result = jump(); - isEqual.link(this); - return result; - } - - ASSERT(!(cond & DoubleConditionBitSpecial)); - return Jump(m_assembler.jCC(static_cast(cond & ~DoubleConditionBits))); - } - - // Truncates 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, INT_MIN). - Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.cvttsd2si_rr(src, dest); - return branch32(Equal, dest, Imm32(0x80000000)); - } - - // Convert 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, 0). - void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) - { - ASSERT(isSSE2Present()); - ASSERT(src != fpTemp); - m_assembler.cvttsd2si_rr(src, dest); - - // If the result is zero, it might have been -0.0, and the double comparison won't catch this! - failureCases.append(branchTest32(Zero, dest)); - - // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. - convertInt32ToDouble(dest, fpTemp); - m_assembler.ucomisd_rr(fpTemp, src); - failureCases.append(Jump(m_assembler.jp())); - failureCases.append(Jump(m_assembler.jne())); - } - - void zeroDouble(FPRegisterID srcDest) - { - ASSERT(isSSE2Present()); - m_assembler.xorpd_rr(srcDest, srcDest); - } - - - // Stack manipulation operations: - // - // The ABI is assumed to provide a stack abstraction to memory, - // containing machine word sized units of data. Push and pop - // operations add and remove a single register sized unit of data - // to or from the stack. Peek and poke operations read or write - // values on the stack, without moving the current stack position. - - void pop(RegisterID dest) - { - m_assembler.pop_r(dest); - } - - void push(RegisterID src) - { - m_assembler.push_r(src); - } - - void push(Address address) - { - m_assembler.push_m(address.offset, address.base); - } - - void push(Imm32 imm) - { - m_assembler.push_i32(imm.m_value); - } - - - // Register move operations: - // - // Move values in registers. - - void move(TrustedImm32 imm, RegisterID dest) - { - // Note: on 64-bit the Imm32 value is zero extended into the register, it - // may be useful to have a separate version that sign extends the value? - if (!imm.m_value) - m_assembler.xorl_rr(dest, dest); - else - m_assembler.movl_i32r(imm.m_value, dest); - } - -#if WTF_CPU_X86_64 - void move(RegisterID src, RegisterID dest) - { - // Note: on 64-bit this is is a full register move; perhaps it would be - // useful to have separate move32 & movePtr, with move32 zero extending? - if (src != dest) - m_assembler.movq_rr(src, dest); - } - - void move(TrustedImmPtr imm, RegisterID dest) - { - m_assembler.movq_i64r(imm.asIntptr(), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - // XCHG is extremely slow. Don't use XCHG. - if (reg1 != reg2) { - m_assembler.movq_rr(reg1, scratchRegister); - m_assembler.movq_rr(reg2, reg1); - m_assembler.movq_rr(scratchRegister, reg2); - } - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - m_assembler.movsxd_rr(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - m_assembler.movl_rr(src, dest); - } -#else - void move(RegisterID src, RegisterID dest) - { - if (src != dest) - m_assembler.movl_rr(src, dest); - } - - void move(TrustedImmPtr imm, RegisterID dest) - { - m_assembler.movl_i32r(imm.asIntptr(), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - if (reg1 != reg2) - m_assembler.xchgl_rr(reg1, reg2); - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - move(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - move(src, dest); - } -#endif - - - // Forwards / external control flow operations: - // - // This set of jump and conditional branch operations return a Jump - // object which may linked at a later point, allow forwards jump, - // or jumps that will require external linkage (after the code has been - // relocated). - // - // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge - // respecitvely, for unsigned comparisons the names b, a, be, and ae are - // used (representing the names 'below' and 'above'). - // - // Operands to the comparision are provided in the expected order, e.g. - // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when - // treated as a signed 32bit value, is less than or equal to 5. - // - // jz and jnz test whether the first operand is equal to zero, and take - // an optional second operand of a mask under which to perform the test. - -public: - Jump branch8(Condition cond, Address left, Imm32 right) - { - m_assembler.cmpb_im(right.m_value, left.offset, left.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, RegisterID left, RegisterID right) - { - m_assembler.cmpl_rr(right, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, RegisterID left, TrustedImm32 right) - { - if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) - m_assembler.testl_rr(left, left); - else - m_assembler.cmpl_ir(right.m_value, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - // Branch based on a 32-bit comparison, forcing the size of the - // immediate operand to 32 bits in the native code stream to ensure that - // the length of code emitted by this instruction is consistent. - Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right) - { - m_assembler.cmpl_ir_force32(right.m_value, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - // Branch and record a label after the comparison. - Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel) - { - // Always use cmpl, since the value is to be patched. - m_assembler.cmpl_ir_force32(right.m_value, left); - dataLabel = DataLabel32(this); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel) - { - m_assembler.cmpl_im_force32(right.m_value, left.offset, left.base); - dataLabel = DataLabel32(this); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, RegisterID left, Address right) - { - m_assembler.cmpl_mr(right.offset, right.base, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, Address left, RegisterID right) - { - m_assembler.cmpl_rm(right, left.offset, left.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, Address left, TrustedImm32 right) - { - m_assembler.cmpl_im(right.m_value, left.offset, left.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right) - { - m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right) - { - return branch32(cond, left, right); - } - - Jump branch16(Condition cond, BaseIndex left, RegisterID right) - { - m_assembler.cmpw_rm(right, left.offset, left.base, left.index, left.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch16(Condition cond, BaseIndex left, Imm32 right) - { - ASSERT(!(right.m_value & 0xFFFF0000)); - - m_assembler.cmpw_im(right.m_value, left.offset, left.base, left.index, left.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) - { - ASSERT((cond == Zero) || (cond == NonZero)); - m_assembler.testl_rr(reg, mask); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - // if we are only interested in the low seven bits, this can be tested with a testb - if (mask.m_value == -1) - m_assembler.testl_rr(reg, reg); - else if (CanUse8Bit(reg) && (mask.m_value & ~0x7f) == 0) - m_assembler.testb_i8r(mask.m_value, reg); - else - m_assembler.testl_i32r(mask.m_value, reg); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - if (mask.m_value == -1) - m_assembler.cmpl_im(0, address.offset, address.base); - else - m_assembler.testl_i32m(mask.m_value, address.offset, address.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - if (mask.m_value == -1) - m_assembler.cmpl_im(0, address.offset, address.base, address.index, address.scale); - else - m_assembler.testl_i32m(mask.m_value, address.offset, address.base, address.index, address.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - if (mask.m_value == -1) - m_assembler.cmpb_im(0, address.offset, address.base); - else - m_assembler.testb_im(mask.m_value, address.offset, address.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest8(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - if (mask.m_value == -1) - m_assembler.cmpb_im(0, address.offset, address.base, address.index, address.scale); - else - m_assembler.testb_im(mask.m_value, address.offset, address.base, address.index, address.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump jump() - { - return Jump(m_assembler.jmp()); - } - - void jump(RegisterID target) - { - m_assembler.jmp_r(target); - } - - // Address is a memory location containing the address to jump to - void jump(Address address) - { - m_assembler.jmp_m(address.offset, address.base); - } - - void jump(BaseIndex address) - { - m_assembler.jmp_m(address.offset, address.base, address.index, address.scale); - } - - // Arithmetic control flow operations: - // - // This set of conditional branch operations branch based - // on the result of an arithmetic operation. The operation - // is performed as normal, storing the result. - // - // * jz operations branch if the result is zero. - // * jo operations branch if the (signed) arithmetic - // operation caused an overflow to occur. - - Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - add32(imm, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchAdd32(Condition cond, Imm32 src, Address dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchAdd32(Condition cond, RegisterID src, Address dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchAdd32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT(cond == Overflow); - mul32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchMul32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - mul32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) - { - ASSERT(cond == Overflow); - mul32(imm, src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(imm, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSub32(Condition cond, Imm32 imm, Address dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - sub32(imm, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSub32(Condition cond, RegisterID src, Address dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - sub32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSub32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - sub32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchNeg32(Condition cond, RegisterID srcDest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - neg32(srcDest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); - or32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - - // Miscellaneous operations: - - void breakpoint() - { - m_assembler.int3(); - } - - Call nearCall() - { - return Call(m_assembler.call(), Call::LinkableNear); - } - - Call call(RegisterID target) - { - return Call(m_assembler.call(target), Call::None); - } - - void call(Address address) - { - m_assembler.call_m(address.offset, address.base); - } - - void ret() - { - m_assembler.ret(); - } - - void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - m_assembler.cmpl_rr(right, left); - m_assembler.setCC_r(x86Condition(cond), dest); - } - - void set8(Condition cond, Address left, RegisterID right, RegisterID dest) - { - m_assembler.cmpl_mr(left.offset, left.base, right); - m_assembler.setCC_r(x86Condition(cond), dest); - } - - void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) - m_assembler.testl_rr(left, left); - else - m_assembler.cmpl_ir(right.m_value, left); - m_assembler.setCC_r(x86Condition(cond), dest); - } - - void set32(Condition cond, Address left, RegisterID right, RegisterID dest) - { - m_assembler.cmpl_rm(right, left.offset, left.base); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - void set32(Condition cond, RegisterID left, Address right, RegisterID dest) - { - m_assembler.cmpl_mr(right.offset, right.base, left); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - m_assembler.cmpl_rr(right, left); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - void set32(Condition cond, Address left, Imm32 right, RegisterID dest) - { - m_assembler.cmpl_im(right.m_value, left.offset, left.base); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) - m_assembler.testl_rr(left, left); - else - m_assembler.cmpl_ir(right.m_value, left); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - // FIXME: - // The mask should be optional... paerhaps the argument order should be - // dest-src, operations always have a dest? ... possibly not true, considering - // asm ops like test, or pseudo ops like pop(). - - void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - if (mask.m_value == -1) - m_assembler.cmpb_im(0, address.offset, address.base); - else - m_assembler.testb_im(mask.m_value, address.offset, address.base); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - if (mask.m_value == -1) - m_assembler.cmpl_im(0, address.offset, address.base); - else - m_assembler.testl_i32m(mask.m_value, address.offset, address.base); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - // As the SSE's were introduced in order, the presence of a later SSE implies // the presence of an earlier SSE. For example, SSE4_2 support implies SSE2 support. enum SSECheckState { @@ -1282,15 +64,7 @@ public: return s_sseCheckState; } -protected: - X86Assembler::Condition x86Condition(Condition cond) - { - return static_cast(cond); - } - private: - friend class MacroAssemblerX86; - static SSECheckState s_sseCheckState; static void setSSECheckState(); diff --git a/js/src/assembler/assembler/MacroAssemblerX86_64.h b/js/src/assembler/assembler/MacroAssemblerX86_64.h index be53bd2660a..3f4352c73bf 100644 --- a/js/src/assembler/assembler/MacroAssemblerX86_64.h +++ b/js/src/assembler/assembler/MacroAssemblerX86_64.h @@ -30,571 +30,17 @@ #ifndef assembler_assembler_MacroAssemblerX86_64_h #define assembler_assembler_MacroAssemblerX86_64_h -#include "mozilla/DebugOnly.h" - #include "assembler/wtf/Platform.h" #if ENABLE_ASSEMBLER && WTF_CPU_X86_64 #include "assembler/assembler/MacroAssemblerX86Common.h" -#define REPTACH_OFFSET_CALL_R11 3 - namespace JSC { class MacroAssemblerX86_64 : public MacroAssemblerX86Common { -protected: - static const intptr_t MinInt32 = 0xFFFFFFFF80000000; - static const intptr_t MaxInt32 = 0x000000007FFFFFFF; - public: - static const Scale ScalePtr = TimesEight; - static const unsigned int TotalRegisters = 16; - - using MacroAssemblerX86Common::add32; - using MacroAssemblerX86Common::and32; - using MacroAssemblerX86Common::or32; - using MacroAssemblerX86Common::sub32; - using MacroAssemblerX86Common::load32; - using MacroAssemblerX86Common::store32; - using MacroAssemblerX86Common::call; - using MacroAssemblerX86Common::loadDouble; - using MacroAssemblerX86Common::storeDouble; - using MacroAssemblerX86Common::convertInt32ToDouble; - - void add32(TrustedImm32 imm, AbsoluteAddress address) - { - move(ImmPtr(address.m_ptr), scratchRegister); - add32(imm, Address(scratchRegister)); - } - - void and32(Imm32 imm, AbsoluteAddress address) - { - move(ImmPtr(address.m_ptr), scratchRegister); - and32(imm, Address(scratchRegister)); - } - - void or32(TrustedImm32 imm, AbsoluteAddress address) - { - move(ImmPtr(address.m_ptr), scratchRegister); - or32(imm, Address(scratchRegister)); - } - - void sub32(TrustedImm32 imm, AbsoluteAddress address) - { - move(ImmPtr(address.m_ptr), scratchRegister); - sub32(imm, Address(scratchRegister)); - } - - void load32(const void* address, RegisterID dest) - { - if (dest == X86Registers::eax) - m_assembler.movl_mEAX(address); - else { - move(ImmPtr(address), scratchRegister); - load32(ImplicitAddress(scratchRegister), dest); - } - } - - DataLabelPtr loadDouble(const void* address, FPRegisterID dest) - { - DataLabelPtr label = moveWithPatch(ImmPtr(address), scratchRegister); - loadDouble(ImplicitAddress(scratchRegister), dest); - return label; - } - - void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) - { - move(Imm32(*static_cast(src.m_ptr)), scratchRegister); - m_assembler.cvtsi2sd_rr(scratchRegister, dest); - } - - void convertUInt32ToDouble(RegisterID srcDest, FPRegisterID dest) - { - zeroExtend32ToPtr(srcDest, srcDest); - zeroDouble(dest); // break dependency chains - m_assembler.cvtsq2sd_rr(srcDest, dest); - } - - void store32(TrustedImm32 imm, void* address) - { - move(X86Registers::eax, scratchRegister); - move(imm, X86Registers::eax); - m_assembler.movl_EAXm(address); - move(scratchRegister, X86Registers::eax); - } - - Call call() - { - mozilla::DebugOnly label = moveWithPatch(ImmPtr(0), scratchRegister); - Call result = Call(m_assembler.call(scratchRegister), Call::Linkable); - ASSERT(differenceBetween(label, result) == REPTACH_OFFSET_CALL_R11); - return result; - } - - Call tailRecursiveCall() - { - mozilla::DebugOnly label = moveWithPatch(ImmPtr(0), scratchRegister); - Jump newJump = Jump(m_assembler.jmp_r(scratchRegister)); - ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11); - return Call::fromTailJump(newJump); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - oldJump.link(this); - mozilla::DebugOnly label = moveWithPatch(ImmPtr(0), scratchRegister); - Jump newJump = Jump(m_assembler.jmp_r(scratchRegister)); - ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11); - return Call::fromTailJump(newJump); - } - - - void addPtr(RegisterID src, RegisterID dest) - { - m_assembler.addq_rr(src, dest); - } - - void lea(BaseIndex address, RegisterID dest) - { - m_assembler.leaq_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void lea(Address address, RegisterID dest) - { - m_assembler.leaq_mr(address.offset, address.base, dest); - } - - void addPtr(Imm32 imm, RegisterID srcDest) - { - m_assembler.addq_ir(imm.m_value, srcDest); - } - - void addPtr(ImmPtr imm, RegisterID dest) - { - move(imm, scratchRegister); - m_assembler.addq_rr(scratchRegister, dest); - } - - void addPtr(Imm32 imm, RegisterID src, RegisterID dest) - { - m_assembler.leaq_mr(imm.m_value, src, dest); - } - - void addPtr(Imm32 imm, Address address) - { - m_assembler.addq_im(imm.m_value, address.offset, address.base); - } - - void addPtr(Imm32 imm, AbsoluteAddress address) - { - move(ImmPtr(address.m_ptr), scratchRegister); - addPtr(imm, Address(scratchRegister)); - } - - void andPtr(RegisterID src, RegisterID dest) - { - m_assembler.andq_rr(src, dest); - } - - void andPtr(Address src, RegisterID dest) - { - m_assembler.andq_mr(src.offset, src.base, dest); - } - - void andPtr(Imm32 imm, RegisterID srcDest) - { - m_assembler.andq_ir(imm.m_value, srcDest); - } - - void andPtr(ImmPtr imm, RegisterID srcDest) - { - intptr_t value = intptr_t(imm.m_value); - - // 32-bit immediates in 64-bit ALU ops are sign-extended. - if (value >= MinInt32 && value <= MaxInt32) { - andPtr(Imm32(int(value)), srcDest); - } else { - move(imm, scratchRegister); - m_assembler.andq_rr(scratchRegister, srcDest); - } - } - - void negPtr(RegisterID srcDest) - { - m_assembler.negq_r(srcDest); - } - - void notPtr(RegisterID srcDest) - { - m_assembler.notq_r(srcDest); - } - - void orPtr(Address src, RegisterID dest) - { - m_assembler.orq_mr(src.offset, src.base, dest); - } - - void orPtr(RegisterID src, RegisterID dest) - { - m_assembler.orq_rr(src, dest); - } - - void orPtr(ImmPtr imm, RegisterID dest) - { - move(imm, scratchRegister); - m_assembler.orq_rr(scratchRegister, dest); - } - - void orPtr(Imm32 imm, RegisterID dest) - { - m_assembler.orq_ir(imm.m_value, dest); - } - - void subPtr(RegisterID src, RegisterID dest) - { - m_assembler.subq_rr(src, dest); - } - - void subPtr(Imm32 imm, RegisterID dest) - { - m_assembler.subq_ir(imm.m_value, dest); - } - - void subPtr(ImmPtr imm, RegisterID dest) - { - move(imm, scratchRegister); - m_assembler.subq_rr(scratchRegister, dest); - } - - void xorPtr(RegisterID src, RegisterID dest) - { - m_assembler.xorq_rr(src, dest); - } - - void xorPtr(Imm32 imm, RegisterID srcDest) - { - m_assembler.xorq_ir(imm.m_value, srcDest); - } - - void rshiftPtr(Imm32 imm, RegisterID srcDest) - { - m_assembler.sarq_i8r(imm.m_value, srcDest); - } - - void lshiftPtr(Imm32 imm, RegisterID srcDest) - { - m_assembler.shlq_i8r(imm.m_value, srcDest); - } - - void loadPtr(ImplicitAddress address, RegisterID dest) - { - m_assembler.movq_mr(address.offset, address.base, dest); - } - - void loadPtr(BaseIndex address, RegisterID dest) - { - m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void loadPtr(const void* address, RegisterID dest) - { - if (dest == X86Registers::eax) - m_assembler.movq_mEAX(address); - else { - move(ImmPtr(address), scratchRegister); - loadPtr(ImplicitAddress(scratchRegister), dest); - } - } - - DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest) - { - m_assembler.movq_mr_disp32(address.offset, address.base, dest); - return DataLabel32(this); - } - - void storePtr(RegisterID src, ImplicitAddress address) - { - m_assembler.movq_rm(src, address.offset, address.base); - } - - void storePtr(TrustedImmPtr imm, BaseIndex address) - { - intptr_t value = intptr_t(imm.m_value); - - // 32-bit immediates in 64-bit stores will be zero-extended, so check - // if the value can fit in such a store. - if (value >= 0 && value < intptr_t(0x7FFFFFFF)) { - m_assembler.movq_i32m(int32_t(value), address.offset, address.base, address.index, - address.scale); - } else { - move(imm, scratchRegister); - storePtr(scratchRegister, address); - } - } - - void storePtr(RegisterID src, BaseIndex address) - { - m_assembler.movq_rm(src, address.offset, address.base, address.index, address.scale); - } - - void storePtr(RegisterID src, void* address) - { - if (src == X86Registers::eax) - m_assembler.movq_EAXm(address); - else { - move(ImmPtr(address), scratchRegister); - storePtr(src, ImplicitAddress(scratchRegister)); - } - } - - void storePtr(TrustedImmPtr imm, ImplicitAddress address) - { - intptr_t value = intptr_t(imm.m_value); - - // 32-bit immediates in 64-bit stores will be zero-extended, so check - // if the value can fit in such a store. - if (value >= 0 && value < intptr_t(0x7FFFFFFF)) { - m_assembler.movq_i32m(int32_t(value), address.offset, address.base); - } else { - move(imm, scratchRegister); - storePtr(scratchRegister, address); - } - } - - DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address) - { - m_assembler.movq_rm_disp32(src, address.offset, address.base); - return DataLabel32(this); - } - - void move32(RegisterID src, RegisterID dest) - { - // upper 32bit will be 0 - m_assembler.movl_rr(src, dest); - } - - void movePtrToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.movq_rr(src, dest); - } - - void moveDoubleToPtr(FPRegisterID src, RegisterID dest) - { - m_assembler.movq_rr(src, dest); - } - - void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) - m_assembler.testq_rr(left, left); - else - m_assembler.cmpq_ir(right.m_value, left); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - void setPtr(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - m_assembler.cmpq_rr(right, left); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - void setPtr(Condition cond, RegisterID left, ImmPtr right, RegisterID dest) - { - move(right, scratchRegister); - setPtr(cond, left, scratchRegister, dest); - } - - Jump branchPtr(Condition cond, RegisterID left, RegisterID right) - { - m_assembler.cmpq_rr(right, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchPtr(Condition cond, RegisterID left, Imm32 right) - { - m_assembler.cmpq_ir(right.m_value, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchPtr(Condition cond, RegisterID left, ImmPtr right) - { - move(right, scratchRegister); - return branchPtr(cond, left, scratchRegister); - } - - Jump branchPtr(Condition cond, RegisterID left, Address right) - { - m_assembler.cmpq_mr(right.offset, right.base, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right) - { - move(ImmPtr(left.m_ptr), scratchRegister); - return branchPtr(cond, Address(scratchRegister), right); - } - - Jump branchPtr(Condition cond, AbsoluteAddress left, ImmPtr right, RegisterID scratch) - { - move(ImmPtr(left.m_ptr), scratch); - return branchPtr(cond, Address(scratch), right); - } - - Jump branchPtr(Condition cond, Address left, RegisterID right) - { - m_assembler.cmpq_rm(right, left.offset, left.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchPtr(Condition cond, Address left, ImmPtr right) - { - move(right, scratchRegister); - return branchPtr(cond, left, scratchRegister); - } - - Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask) - { - m_assembler.testq_rr(reg, mask); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - // if we are only interested in the low seven bits, this can be tested with a testb - if (mask.m_value == -1) - m_assembler.testq_rr(reg, reg); - else if ((mask.m_value & ~0x7f) == 0) - m_assembler.testb_i8r(mask.m_value, reg); - else - m_assembler.testq_i32r(mask.m_value, reg); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - if (mask.m_value == -1) - m_assembler.cmpq_im(0, address.offset, address.base); - else - m_assembler.testq_i32m(mask.m_value, address.offset, address.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - if (mask.m_value == -1) - m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale); - else - m_assembler.testq_i32m(mask.m_value, address.offset, address.base, address.index, address.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - - Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - addPtr(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - subPtr(imm, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) - { - m_assembler.movq_i64r(initialValue.asIntptr(), dest); - return DataLabelPtr(this); - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - dataLabel = moveWithPatch(initialRightValue, scratchRegister); - return branchPtr(cond, left, scratchRegister); - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - dataLabel = moveWithPatch(initialRightValue, scratchRegister); - return branchPtr(cond, left, scratchRegister); - } - - DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) - { - DataLabelPtr label = moveWithPatch(initialValue, scratchRegister); - storePtr(scratchRegister, address); - return label; - } - - using MacroAssemblerX86Common::branchTest8; - Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1)) - { - ImmPtr addr(reinterpret_cast(address.offset)); - MacroAssemblerX86Common::move(addr, scratchRegister); - return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask); - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - Label label(this); - loadPtr(address, dest); - return label; - } - - void pushAllRegs() - { - for (int i = X86Registers::eax; i <= X86Registers::r15; i++) - m_assembler.push_r((RegisterID)i); - } - - void popAllRegs() - { - for (int i = X86Registers::r15; i >= X86Registers::eax; i--) - m_assembler.pop_r((RegisterID)i); - } - - void storeDouble(ImmDouble imm, Address address) - { - storePtr(ImmPtr(reinterpret_cast(imm.u.u64)), address); - } - - void storeDouble(ImmDouble imm, BaseIndex address) - { - storePtr(ImmPtr(reinterpret_cast(imm.u.u64)), address); - } - static bool supportsFloatingPoint() { return true; } - // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() - static bool supportsFloatingPointTruncate() { return true; } - static bool supportsFloatingPointSqrt() { return true; } - -private: - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - if (!call.isFlagSet(Call::Near)) - X86Assembler::linkPointer(code, X86Assembler::labelFor(call.m_jmp, -REPTACH_OFFSET_CALL_R11), function.value()); - else - X86Assembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress()); - } - }; } // namespace JSC diff --git a/js/src/assembler/assembler/RepatchBuffer.h b/js/src/assembler/assembler/RepatchBuffer.h deleted file mode 100644 index b1d686021d0..00000000000 --- a/js/src/assembler/assembler/RepatchBuffer.h +++ /dev/null @@ -1,163 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef assembler_assembler_RepatchBuffer_h -#define assembler_assembler_RepatchBuffer_h - -#include "assembler/wtf/Platform.h" - -#if ENABLE_ASSEMBLER - -#include "assembler/assembler/MacroAssembler.h" -#include "assembler/moco/MocoStubs.h" //MOCO - -namespace JSC { - -// RepatchBuffer: -// -// This class is used to modify code after code generation has been completed, -// and after the code has potentially already been executed. This mechanism is -// used to apply optimizations to the code. -// -class RepatchBuffer { - typedef MacroAssemblerCodePtr CodePtr; - -public: - RepatchBuffer(const MacroAssemblerCodeRef &ref) - { - m_start = ref.m_code.executableAddress(); - m_size = ref.m_size; - mprot = true; - - if (mprot) - ExecutableAllocator::makeWritable(m_start, m_size); - } - - RepatchBuffer(const JITCode &code) - { - m_start = code.start(); - m_size = code.size(); - mprot = true; - - if (mprot) - ExecutableAllocator::makeWritable(m_start, m_size); - } - - ~RepatchBuffer() - { - if (mprot) - ExecutableAllocator::makeExecutable(m_start, m_size); - } - - void relink(CodeLocationJump jump, CodeLocationLabel destination) - { - MacroAssembler::repatchJump(jump, destination); - } - - bool canRelink(CodeLocationJump jump, CodeLocationLabel destination) - { - return MacroAssembler::canRepatchJump(jump, destination); - } - - void relink(CodeLocationCall call, CodeLocationLabel destination) - { - MacroAssembler::repatchCall(call, destination); - } - - void relink(CodeLocationCall call, FunctionPtr destination) - { - MacroAssembler::repatchCall(call, destination); - } - - void relink(CodeLocationNearCall nearCall, CodePtr destination) - { - MacroAssembler::repatchNearCall(nearCall, CodeLocationLabel(destination)); - } - - void relink(CodeLocationNearCall nearCall, CodeLocationLabel destination) - { - MacroAssembler::repatchNearCall(nearCall, destination); - } - - void repatch(CodeLocationDataLabel32 dataLabel32, int32_t value) - { - MacroAssembler::repatchInt32(dataLabel32, value); - } - - void repatch(CodeLocationDataLabelPtr dataLabelPtr, const void* value) - { - MacroAssembler::repatchPointer(dataLabelPtr, (void*) value); - } - - void repatchLoadPtrToLEA(CodeLocationInstruction instruction) - { - MacroAssembler::repatchLoadPtrToLEA(instruction); - } - - void repatchLEAToLoadPtr(CodeLocationInstruction instruction) - { - MacroAssembler::repatchLEAToLoadPtr(instruction); - } - - void relinkCallerToTrampoline(ReturnAddressPtr returnAddress, CodeLocationLabel label) - { - relink(CodeLocationCall(CodePtr(returnAddress)), label); - } - - void relinkCallerToTrampoline(ReturnAddressPtr returnAddress, CodePtr newCalleeFunction) - { - relinkCallerToTrampoline(returnAddress, CodeLocationLabel(newCalleeFunction)); - } - - void relinkCallerToFunction(ReturnAddressPtr returnAddress, FunctionPtr function) - { - relink(CodeLocationCall(CodePtr(returnAddress)), function); - } - - void relinkNearCallerToTrampoline(ReturnAddressPtr returnAddress, CodeLocationLabel label) - { - relink(CodeLocationNearCall(CodePtr(returnAddress)), label); - } - - void relinkNearCallerToTrampoline(ReturnAddressPtr returnAddress, CodePtr newCalleeFunction) - { - relinkNearCallerToTrampoline(returnAddress, CodeLocationLabel(newCalleeFunction)); - } - -protected: - void* m_start; - size_t m_size; - bool mprot; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif /* assembler_assembler_RepatchBuffer_h */ diff --git a/js/src/assembler/assembler/SparcAssembler.h b/js/src/assembler/assembler/SparcAssembler.h deleted file mode 100644 index 0864613a2c6..00000000000 --- a/js/src/assembler/assembler/SparcAssembler.h +++ /dev/null @@ -1,1217 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef assembler_assembler_SparcAssembler_h -#define assembler_assembler_SparcAssembler_h - -#include "assembler/wtf/Platform.h" - -// Some debug code uses s(n)printf for instruction logging. -#include - -#if ENABLE_ASSEMBLER && WTF_CPU_SPARC - -#include "assembler/assembler/AssemblerBufferWithConstantPool.h" -#include "assembler/wtf/Assertions.h" - -#define IPFX " %s" -#define ISPFX " " -#ifdef JS_METHODJIT_SPEW -# define MAYBE_PAD (isOOLPath ? "> " : "") -#else -# define MAYBE_PAD "" -#endif - -namespace JSC { - - typedef uint32_t SparcWord; - - namespace SparcRegisters { - typedef enum { - g0 = 0, // g0 is always 0 - g1 = 1, // g1 is a scratch register for v8 - g2 = 2, - g3 = 3, - g4 = 4, - g5 = 5, // Reserved for system - g6 = 6, // Reserved for system - g7 = 7, // Reserved for system - - o0 = 8, - o1 = 9, - o2 = 10, - o3 = 11, - o4 = 12, - o5 = 13, - o6 = 14, // SP - o7 = 15, - - l0 = 16, - l1 = 17, - l2 = 18, - l3 = 19, - l4 = 20, - l5 = 21, - l6 = 22, - l7 = 23, - - i0 = 24, - i1 = 25, - i2 = 26, - i3 = 27, - i4 = 28, - i5 = 29, - i6 = 30, // FP - i7 = 31, - - sp = o6, - fp = i6 - } RegisterID; - - typedef enum { - f0 = 0, - f1 = 1, - f2 = 2, - f3 = 3, - f4 = 4, - f5 = 5, - f6 = 6, - f7 = 7, - f8 = 8, - f9 = 9, - f10 = 10, - f11 = 11, - f12 = 12, - f13 = 13, - f14 = 14, - f15 = 15, - f16 = 16, - f17 = 17, - f18 = 18, - f19 = 19, - f20 = 20, - f21 = 21, - f22 = 22, - f23 = 23, - f24 = 24, - f25 = 25, - f26 = 26, - f27 = 27, - f28 = 28, - f29 = 29, - f30 = 30, - f31 = 31 - } FPRegisterID; - - } // namespace SparcRegisters - - class SparcAssembler : public GenericAssembler { - public: - typedef SparcRegisters::RegisterID RegisterID; - typedef SparcRegisters::FPRegisterID FPRegisterID; - AssemblerBuffer m_buffer; - bool oom() const { return m_buffer.oom(); } - - // Sparc conditional constants - typedef enum { - ConditionE = 0x1, // Zero - ConditionLE = 0x2, - ConditionL = 0x3, - ConditionLEU = 0x4, - ConditionCS = 0x5, - ConditionNEG = 0x6, - ConditionVS = 0x7, - ConditionA = 0x8, // branch_always - ConditionNE = 0x9, // Non-zero - ConditionG = 0xa, - ConditionGE = 0xb, - ConditionGU = 0xc, - ConditionCC = 0xd, - ConditionVC = 0xf - } Condition; - - - typedef enum { - DoubleConditionNE = 0x1, - DoubleConditionUL = 0x3, - DoubleConditionL = 0x4, - DoubleConditionUG = 0x5, - DoubleConditionG = 0x6, - DoubleConditionE = 0x9, - DoubleConditionUE = 0xa, - DoubleConditionGE = 0xb, - DoubleConditionUGE = 0xc, - DoubleConditionLE = 0xd, - DoubleConditionULE = 0xe - } DoubleCondition; - - typedef enum { - BranchOnCondition, - BranchOnDoubleCondition - } BranchType; - - class JmpSrc { - friend class SparcAssembler; - public: - JmpSrc() - : m_offset(-1) - { - } - - private: - JmpSrc(int offset) - : m_offset(offset) - { - } - - int m_offset; - }; - - class JmpDst { - friend class SparcAssembler; - public: - JmpDst() - : m_offset(-1) - , m_used(false) - { - } - - bool isUsed() const { return m_used; } - void used() { m_used = true; } - bool isValid() const { return m_offset != -1; } - private: - JmpDst(int offset) - : m_offset(offset) - , m_used(false) - { - ASSERT(m_offset == offset); - } - - int m_used : 1; - signed int m_offset : 31; - }; - - // Instruction formating - - void format_2_1(int rd, int op2, int imm22) - { - m_buffer.putInt(rd << 25 | op2 << 22 | (imm22 & 0x3FFFFF)); - } - - void format_2_2(int a, int cond, int op2, int disp22) - { - format_2_1((a & 0x1) << 4 | (cond & 0xF), op2, disp22); - } - - void format_2_3(int a, int cond, int op2, int cc1, int cc0, int p, int disp19) - { - format_2_2(a, cond, op2, (cc1 & 0x1) << 21 | (cc0 & 0x1) << 20 | (p & 0x1) << 19 | (disp19 & 0x7FFFF)); - } - - void format_2_4(int a, int rcond, int op2, int d16hi, int p, int rs1, int d16lo) - { - format_2_2(a, (rcond & 0x7), op2, (d16hi & 0x3) << 20 | (p & 0x1) << 19 | rs1 << 14 | (d16lo & 0x3FFF)); - } - - void format_3(int op1, int rd, int op3, int bits19) - { - m_buffer.putInt(op1 << 30 | rd << 25 | op3 << 19 | (bits19 & 0x7FFFF)); - } - - void format_3_1(int op1, int rd, int op3, int rs1, int bit8, int rs2) - { - format_3(op1, rd, op3, rs1 << 14 | (bit8 & 0xFF) << 5 | rs2); - } - - void format_3_1_imm(int op1, int rd, int op3, int rs1, int simm13) - { - format_3(op1, rd, op3, rs1 << 14 | 1 << 13 | (simm13 & 0x1FFF)); - } - - void format_3_2(int op1, int rd, int op3, int rs1, int rcond, int rs2) - { - format_3(op1, rd, op3, rs1 << 14 | (rcond & 0x3) << 10 | rs2); - } - - void format_3_2_imm(int op1, int rd, int op3, int rs1, int rcond, int simm10) - { - format_3(op1, rd, op3, rs1 << 14 | 1 << 13 | (rcond & 0x3) << 10 | (simm10 & 0x1FFF)); - } - - void format_3_3(int op1, int rd, int op3, int rs1, int cmask, int mmask) - { - format_3(op1, rd, op3, rs1 << 14 | 1 << 13 | (cmask & 0x7) << 5 | (mmask & 0xF)); - } - void format_3_4(int op1, int rd, int op3, int bits19) - { - format_3(op1, rd, op3, bits19); - } - - void format_3_5(int op1, int rd, int op3, int rs1, int x, int rs2) - { - format_3(op1, rd, op3, rs1 << 14 | (x & 0x1) << 12 | rs2); - } - - void format_3_6(int op1, int rd, int op3, int rs1, int shcnt32) - { - format_3(op1, rd, op3, rs1 << 14 | 1 << 13 | (shcnt32 & 0x1F)); - } - - void format_3_7(int op1, int rd, int op3, int rs1, int shcnt64) - { - format_3(op1, rd, op3, rs1 << 14 | 1 << 13 | 1 << 12 | (shcnt64 & 0x3F)); - } - - void format_3_8(int op1, int rd, int op3, int rs1, int bits9, int rs2) - { - format_3(op1, rd, op3, rs1 << 14 | (bits9 & 0x1FF) << 5 | rs2); - } - - void format_3_9(int op1, int cc1, int cc0, int op3, int rs1, int bits9, int rs2) - { - format_3(op1, (cc1 & 0x1) << 1 | (cc0 & 0x1), op3, rs1 << 14 | (bits9 & 0x1FF) << 5 | rs2); - } - - void format_4_1(int rd, int op3, int rs1, int cc1, int cc0, int rs2) - { - format_3(2, rd, op3, rs1 << 14 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | rs2); - } - - void format_4_1_imm(int rd, int op3, int rs1, int cc1, int cc0, int simm11) - { - format_3(2, rd, op3, rs1 << 14 | (cc1 & 0x1) << 12 | 1 << 13 |(cc0 & 0x1) << 11 | (simm11 & 0x7FF)); - } - - void format_4_2(int rd, int op3, int cc2, int cond, int cc1, int cc0, int rs2) - { - format_3(2, rd, op3, (cc2 & 0x1) << 18 | (cond & 0xF) << 14 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | rs2); - } - - void format_4_2_imm(int rd, int op3, int cc2, int cond, int cc1, int cc0, int simm11) - { - format_3(2, rd, op3, (cc2 & 0x1) << 18 | (cond & 0xF) << 14 | 1 << 13 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | (simm11 & 0x7FF)); - } - - void format_4_3(int rd, int op3, int rs1, int cc1, int cc0, int swap_trap) - { - format_3(2, rd, op3, rs1 << 14 | 1 << 13 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | (swap_trap & 0x7F)); - } - - void format_4_4(int rd, int op3, int rs1, int rcond, int opf_low, int rs2) - { - format_3(2, rd, op3, rs1 << 14 | (rcond & 0x7) << 10 | (opf_low & 0x1F) << 5 | rs2); - } - - void format_4_5(int rd, int op3, int cond, int opf_cc, int opf_low, int rs2) - { - format_3(2, rd, op3, (cond & 0xF) << 14 | (opf_cc & 0x7) << 11 | (opf_low & 0x3F) << 5 | rs2); - } - - void addcc_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "addcc %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x10, rs1, 0, rs2); - } - - void addcc_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "addcc %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0x10, rs1, simm13); - } - - void add_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "add %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0, rs1, 0, rs2); - } - - void add_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "add %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0, rs1, simm13); - } - - void andcc_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "andcc %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x11, rs1, 0, rs2); - } - - void andcc_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "andcc %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0x11, rs1, simm13); - } - - void or_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "or %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x2, rs1, 0, rs2); - } - - void or_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "or %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0x2, rs1, simm13); - } - - // sethi %hi(imm22) rd - void sethi(int imm22, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "sethi %%hi(0x%x), %s\n", MAYBE_PAD, - imm22, nameGpReg(rd)); - format_2_1(rd, 0x4, (imm22 >> 10)); - } - - void sll_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "sll %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_5(2, rd, 0x25, rs1, 0, rs2); - } - - void sll_imm(int rs1, int shcnt32, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "sll %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), shcnt32, nameGpReg(rd)); - format_3_6(2, rd, 0x25, rs1, shcnt32); - } - - void sra_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "sra %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_5(2, rd, 0x27, rs1, 0, rs2); - } - - void sra_imm(int rs1, int shcnt32, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "sra %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), shcnt32, nameGpReg(rd)); - format_3_6(2, rd, 0x27, rs1, shcnt32); - } - - void srl_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "srl %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_5(2, rd, 0x26, rs1, 0, rs2); - } - - void srl_imm(int rs1, int shcnt32, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "srl %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), shcnt32, nameGpReg(rd)); - format_3_6(2, rd, 0x26, rs1, shcnt32); - } - - void subcc_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "subcc %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x14, rs1, 0, rs2); - } - - void subcc_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "subcc %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0x14, rs1, simm13); - } - - void orcc_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "orcc %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x12, rs1, 0, rs2); - } - - void orcc_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "orcc %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0x12, rs1, simm13); - } - - void xorcc_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "xorcc %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x13, rs1, 0, rs2); - } - - void xorcc_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "xorcc %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0x13, rs1, simm13); - } - - void xnorcc_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "xnorcc %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x17, rs1, 0, rs2); - } - - void xnorcc_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "xnorcc %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0x17, rs1, simm13); - } - - void smulcc_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "smulcc %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x1b, rs1, 0, rs2); - } - - void smulcc_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "smulcc %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0x1b, rs1, simm13); - } - - void ldsb_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "ldsb [%s + %s], %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(3, rd, 0x9, rs1, 0, rs2); - } - - void ldsb_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "ldsb [%s + %d], %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(3, rd, 0x9, rs1, simm13); - } - - void ldub_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "ldub [%s + %s], %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(3, rd, 0x1, rs1, 0, rs2); - } - - void ldub_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "ldub [%s + %d], %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(3, rd, 0x1, rs1, simm13); - } - - void lduw_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "lduw [%s + %s], %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(3, rd, 0x0, rs1, 0, rs2); - } - - void lduwa_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "lduwa [%s + %s], %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(3, rd, 0x10, rs1, 0x82, rs2); - } - - void lduw_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "lduw [%s + %d], %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(3, rd, 0x0, rs1, simm13); - } - - void ldsh_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "ldsh [%s + %s], %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(3, rd, 0xa, rs1, 0, rs2); - } - - void ldsh_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "ldsh [%s + %d], %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(3, rd, 0xa, rs1, simm13); - } - - void lduh_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "lduh [%s + %s], %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(3, rd, 0x2, rs1, 0, rs2); - } - - void lduh_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "lduh [%s + %d], %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(3, rd, 0x2, rs1, simm13); - } - - void stb_r(int rd, int rs2, int rs1) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "stb %s, [%s + %s]\n", MAYBE_PAD, - nameGpReg(rd), nameGpReg(rs1), nameGpReg(rs2)); - format_3_1(3, rd, 0x5, rs1, 0, rs2); - } - - void stb_imm(int rd, int rs1, int simm13) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "stb %s, [%s + %d]\n", MAYBE_PAD, - nameGpReg(rd), nameGpReg(rs1), simm13); - format_3_1_imm(3, rd, 0x5, rs1, simm13); - } - - void sth_r(int rd, int rs2, int rs1) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "sth %s, [%s + %s]\n", MAYBE_PAD, - nameGpReg(rd), nameGpReg(rs1), nameGpReg(rs2)); - format_3_1(3, rd, 0x6, rs1, 0, rs2); - } - - void sth_imm(int rd, int rs1, int simm13) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "sth %s, [%s + %d]\n", MAYBE_PAD, - nameGpReg(rd), nameGpReg(rs1), simm13); - format_3_1_imm(3, rd, 0x6, rs1, simm13); - } - - void stw_r(int rd, int rs2, int rs1) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "stw %s, [%s + %s]\n", MAYBE_PAD, - nameGpReg(rd), nameGpReg(rs1), nameGpReg(rs2)); - format_3_1(3, rd, 0x4, rs1, 0, rs2); - } - - void stw_imm(int rd, int rs1, int simm13) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "stw %s, [%s + %d]\n", MAYBE_PAD, - nameGpReg(rd), nameGpReg(rs1), simm13); - format_3_1_imm(3, rd, 0x4, rs1, simm13); - } - - void ldf_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "ld [%s + %s], %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameFpReg(rd)); - format_3_1(3, rd, 0x20, rs1, 0, rs2); - } - - void ldf_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "ld [%s + %d], %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameFpReg(rd)); - format_3_1_imm(3, rd, 0x20, rs1, simm13); - } - - void stf_r(int rd, int rs2, int rs1) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "st %s, [%s + %s]\n", MAYBE_PAD, - nameFpReg(rd), nameGpReg(rs1), nameGpReg(rs2)); - format_3_1(3, rd, 0x24, rs1, 0, rs2); - } - - void stf_imm(int rd, int rs1, int simm13) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "st %s, [%s + %d]\n", MAYBE_PAD, - nameFpReg(rd), nameGpReg(rs1), simm13); - format_3_1_imm(3, rd, 0x24, rs1, simm13); - } - - void fmovd_r(int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fmovd %s, %s\n", MAYBE_PAD, - nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, 0, 0x2, rs2); - } - - void fcmpd_r(int rs1, int rs2) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fcmpd %s, %s\n", MAYBE_PAD, - nameFpReg(rs1), nameFpReg(rs2)); - format_3_9(2, 0, 0, 0x35, rs1, 0x52, rs2); - } - - void nop() - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "nop\n", MAYBE_PAD); - format_2_1(0, 0x4, 0); - } - - void branch_con(Condition cond, int target) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "b%s 0x%x\n", MAYBE_PAD, - nameICC(cond), target); - format_2_2(0, cond, 0x2, target); - } - - void fbranch_con(DoubleCondition cond, int target) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fb%s 0x%x\n", MAYBE_PAD, - nameFCC(cond), target); - format_2_2(0, cond, 0x6, target); - } - - void rdy(int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "rdy %s\n", MAYBE_PAD, - nameFpReg(rd)); - format_3_1(2, rd, 0x28, 0, 0, 0); - } - - void rdpc(int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "rdpc %s\n", MAYBE_PAD, - nameGpReg(rd)); - format_3_1(2, rd, 0x28, 5, 0, 0); - } - void jmpl_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "jmpl %s + %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x38, rs1, 0, rs2); - } - - void jmpl_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "jmpl %s + %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0x38, rs1, simm13); - } - - void save_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "save %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x3c, rs1, 0, rs2); - } - - void save_imm(int rs1, int simm13, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "save %s, %d, %s\n", MAYBE_PAD, - nameGpReg(rs1), simm13, nameGpReg(rd)); - format_3_1_imm(2, rd, 0x3c, rs1, simm13); - } - - void restore_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "restore %s, %s, %s\n", MAYBE_PAD, - nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd)); - format_3_1(2, rd, 0x3d, rs1, 0, rs2); - } - - void ta_imm(int swap_trap) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "ta %d\n", MAYBE_PAD, - swap_trap); - format_4_3(0x8, 0xa, 0, 0, 0, swap_trap); - } - - void movcc_imm(int simm11, int rd, Condition cond) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "mov%s %d, %s\n", MAYBE_PAD, - nameICC(cond), simm11, nameGpReg(rd)); - format_4_2_imm(rd, 0x2c, 1, cond, 0, 0, simm11); - } - - void fabss_r(int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fabss %s, %s\n", MAYBE_PAD, - nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, 0, 0x9, rs2); - } - - void faddd_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "faddd %s, %s, %s\n", MAYBE_PAD, - nameFpReg(rs1), nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, rs1, 0x42, rs2); - } - - void fsubd_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fsubd %s, %s, %s\n", MAYBE_PAD, - nameFpReg(rs1), nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, rs1, 0x46, rs2); - } - - void fmuld_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fmuld %s, %s, %s\n", MAYBE_PAD, - nameFpReg(rs1), nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, rs1, 0x4a, rs2); - } - - void fdivd_r(int rs1, int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fdivd %s, %s, %s\n", MAYBE_PAD, - nameFpReg(rs1), nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, rs1, 0x4e, rs2); - } - - void fsqrtd_r(int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fsqartd %s, %s\n", MAYBE_PAD, - nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, 0, 0x2a, rs2); - } - - void fabsd_r(int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fabsd %s, %s\n", MAYBE_PAD, - nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, 0, 0x0a, rs2); - } - - void fnegd_r(int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fnegd %s, %s\n", MAYBE_PAD, - nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, 0, 0x06, rs2); - } - - void fitod_r(int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fitod %s, %s\n", MAYBE_PAD, - nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, 0, 0xc8, rs2); - } - - void fdtoi_r(int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fdtoi %s, %s\n", MAYBE_PAD, - nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, 0, 0xd2, rs2); - } - - void fdtos_r(int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fdtos %s, %s\n", MAYBE_PAD, - nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, 0, 0xc6, rs2); - } - - void fstod_r(int rs2, int rd) - { - js::JaegerSpew(js::JSpew_Insns, - IPFX "fstod %s, %s\n", MAYBE_PAD, - nameFpReg(rs2), nameFpReg(rd)); - format_3_8(2, rd, 0x34, 0, 0xc9, rs2); - } - - static bool isimm13(int imm) - { - return (imm) <= 0xfff && (imm) >= -0x1000; - } - - static bool isimm22(int imm) - { - return (imm) <= 0x1fffff && (imm) >= -0x200000; - } - - void move_nocheck(int imm_v, RegisterID dest) - { - sethi(imm_v, dest); - or_imm(dest, imm_v & 0x3FF, dest); - } - - JmpSrc call() - { - JmpSrc r = JmpSrc(m_buffer.size()); - js::JaegerSpew(js::JSpew_Insns, - IPFX "call %d\n", MAYBE_PAD, - r.m_offset); - m_buffer.putInt(0x40000000); - nop(); - return r; - } - - JmpSrc jump_common(BranchType branchtype, int cond) - { - if (branchtype == BranchOnCondition) - branch_con(Condition(cond), 0); - else - fbranch_con(DoubleCondition(cond), 0); - - nop(); - branch_con(ConditionA, 7); - nop(); - move_nocheck(0, SparcRegisters::g2); - rdpc(SparcRegisters::g3); - jmpl_r(SparcRegisters::g2, SparcRegisters::g3, SparcRegisters::g0); - nop(); - return JmpSrc(m_buffer.size()); - } - - JmpSrc branch(Condition cond) - { - return jump_common(BranchOnCondition, cond); - } - - JmpSrc fbranch(DoubleCondition cond) - { - return jump_common(BranchOnDoubleCondition, cond); - } - - JmpSrc jmp() - { - return jump_common(BranchOnCondition, ConditionA); - } - - // Assembler admin methods: - - JmpDst label() - { - JmpDst r = JmpDst(m_buffer.size()); - js::JaegerSpew(js::JSpew_Insns, - IPFX "#label ((%d))\n", MAYBE_PAD, r.m_offset); - return r; - } - - // General helpers - - size_t size() const { return m_buffer.size(); } - unsigned char *buffer() const { return m_buffer.buffer(); } - - static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst) - { - return dst.m_offset - src.m_offset; - } - - static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst) - { - return dst.m_offset - src.m_offset; - } - - static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst) - { - return dst.m_offset - src.m_offset; - } - - static unsigned getCallReturnOffset(JmpSrc call) - { - return call.m_offset + 20; - } - - static void* getRelocatedAddress(void* code, JmpSrc jump) - { - ASSERT(jump.m_offset != -1); - - return reinterpret_cast(reinterpret_cast(code) + jump.m_offset); - } - - static void* getRelocatedAddress(void* code, JmpDst destination) - { - ASSERT(destination.m_offset != -1); - - return reinterpret_cast(reinterpret_cast(code) + destination.m_offset); - } - - void* executableAllocAndCopy(ExecutableAllocator* allocator, ExecutablePool **poolp, CodeKind kind) - { - return m_buffer.executableAllocAndCopy(allocator, poolp, kind); - } - - void* executableCopy(void* buffer) - { - return memcpy(buffer, m_buffer.buffer(), size()); - } - - static void patchPointerInternal(void* where, int value) - { - // Patch move_nocheck. - uint32_t *branch = (uint32_t*) where; - branch[0] &= 0xFFC00000; - branch[0] |= (value >> 10) & 0x3FFFFF; - branch[1] &= 0xFFFFFC00; - branch[1] |= value & 0x3FF; - ExecutableAllocator::cacheFlush(where, 8); - } - - static void patchbranch(void* where, int value) - { - uint32_t *branch = (uint32_t*) where; - branch[0] &= 0xFFC00000; - branch[0] |= value & 0x3FFFFF; - ExecutableAllocator::cacheFlush(where, 4); - } - - static bool canRelinkJump(void* from, void* to) - { - return true; - } - - static void relinkJump(void* from, void* to) - { - from = (void *)((int)from - 36); - js::JaegerSpew(js::JSpew_Insns, - ISPFX "##link ((%p)) jumps to ((%p))\n", - from, to); - - int value = ((int)to - (int)from) / 4; - if (isimm22(value)) - patchbranch(from, value); - else { - patchbranch(from, 4); - from = (void *)((intptr_t)from + 16); - patchPointerInternal(from, (int)(value * 4 - 24)); - } - } - - void linkJump(JmpSrc from, JmpDst to) - { - ASSERT(from.m_offset != -1); - ASSERT(to.m_offset != -1); - intptr_t code = (intptr_t)(m_buffer.data()); - void *where = (void *)((intptr_t)code + from.m_offset); - void *target = (void *)((intptr_t)code + to.m_offset); - relinkJump(where, target); - } - - static void linkJump(void* code, JmpSrc from, void* to) - { - ASSERT(from.m_offset != -1); - void *where = (void *)((intptr_t)code + from.m_offset); - relinkJump(where, to); - } - - static void relinkCall(void* from, void* to) - { - js::JaegerSpew(js::JSpew_Insns, - ISPFX "##relinkCall ((from=%p)) ((to=%p))\n", - from, to); - - void * where= (void *)((intptr_t)from - 20); - patchPointerInternal(where, (int)to); - ExecutableAllocator::cacheFlush(where, 8); - } - - static void linkCall(void* code, JmpSrc where, void* to) - { - void *from = (void *)((intptr_t)code + where.m_offset); - js::JaegerSpew(js::JSpew_Insns, - ISPFX "##linkCall ((from=%p)) ((to=%p))\n", - from, to); - int disp = ((int)to - (int)from)/4; - *(uint32_t *)((int)from) &= 0x40000000; - *(uint32_t *)((int)from) |= disp & 0x3fffffff; - ExecutableAllocator::cacheFlush(from, 4); - } - - static void linkPointer(void* code, JmpDst where, void* value) - { - js::JaegerSpew(js::JSpew_Insns, - ISPFX "##linkPointer ((%p + %#x)) points to ((%p))\n", - code, where.m_offset, value); - - void *from = (void *)((intptr_t)code + where.m_offset); - patchPointerInternal(from, (int)value); - } - - static void repatchInt32(void* where, int value) - { - js::JaegerSpew(js::JSpew_Insns, - ISPFX "##repatchInt32 ((where=%p)) holds ((value=%d))\n", - where, value); - - patchPointerInternal(where, value); - } - - static void repatchPointer(void* where, void* value) - { - js::JaegerSpew(js::JSpew_Insns, - ISPFX "##repatchPointer ((where = %p)) points to ((%p))\n", - where, value); - - patchPointerInternal(where, (int)value); - } - - static void repatchLoadPtrToLEA(void* where) - { - // sethi is used. The offset is in a register - if (*(uint32_t *)((int)where) & 0x01000000) - where = (void *)((intptr_t)where + 8); - - *(uint32_t *)((int)where) &= 0x3fffffff; - *(uint32_t *)((int)where) |= 0x80000000; - ExecutableAllocator::cacheFlush(where, 4); - } - - static void repatchLEAToLoadPtr(void* where) - { - // sethi is used. The offset is in a register - if (*(uint32_t *)((int)where) & 0x01000000) - where = (void *)((intptr_t)where + 8); - - *(uint32_t *)((int)where) &= 0x3fffffff; - *(uint32_t *)((int)where) |= 0xc0000000; - ExecutableAllocator::cacheFlush(where, 4); - } - - private: - static char const * nameGpReg(int reg) - { - ASSERT(reg <= 31); - ASSERT(reg >= 0); - static char const * const names[] = { - "%g0", "%g1", "%g2", "%g3", - "%g4", "%g5", "%g6", "%g7", - "%o0", "%o1", "%o2", "%o3", - "%o4", "%o5", "%sp", "%o7", - "%l0", "%l1", "%l2", "%l3", - "%l4", "%l5", "%l6", "%l7", - "%i0", "%i1", "%i2", "%i3", - "%i4", "%i5", "%fp", "%i7" - }; - return names[reg]; - } - - static char const * nameFpReg(int reg) - { - ASSERT(reg <= 31); - ASSERT(reg >= 0); - static char const * const names[] = { - "%f0", "%f1", "%f2", "%f3", - "%f4", "%f5", "%f6", "%f7", - "%f8", "%f9", "%f10", "%f11", - "%f12", "%f13", "%f14", "%f15", - "%f16", "%f17", "%f18", "%f19", - "%f20", "%f21", "%f22", "%f23", - "%f24", "%f25", "%f26", "%f27", - "%f28", "%f29", "%f30", "%f31" - }; - return names[reg]; - } - - static char const * nameICC(Condition cc) - { - ASSERT(cc <= ConditionVC); - ASSERT(cc >= 0); - - uint32_t ccIndex = cc; - static char const * const inames[] = { - " ", "e ", - "le ", "l ", - "leu", "cs ", - "neg", "vs ", - "a ", "ne ", - "g ", "ge ", - "gu ", "cc ", - " ", "vc " - }; - return inames[ccIndex]; - } - - static char const * nameFCC(DoubleCondition cc) - { - ASSERT(cc <= DoubleConditionULE); - ASSERT(cc >= 0); - - uint32_t ccIndex = cc; - static char const * const fnames[] = { - " ", "ne ", - " ", "ul ", - "l ", "ug ", - "g ", " ", - " ", "e ", - "ue ", "ge ", - "ugu", "le ", - "ule", " " - }; - return fnames[ccIndex]; - } - - - }; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) && CPU(SPARC) - -#endif /* assembler_assembler_SparcAssembler_h */ diff --git a/js/src/assembler/moco/MocoStubs.h b/js/src/assembler/moco/MocoStubs.h deleted file mode 100644 index 4dc46d5ee43..00000000000 --- a/js/src/assembler/moco/MocoStubs.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef assembler_moco_MocoStubs_h -#define assembler_moco_MocoStubs_h - -namespace JSC { - -class JITCode { -public: - JITCode(void* start, size_t size) - : m_start(start), m_size(size) - { } - JITCode() { } - void* start() const { return m_start; } - size_t size() const { return m_size; } -private: - void* m_start; - size_t m_size; -}; - -class CodeBlock { -public: - CodeBlock(JITCode& jc) - : m_jitcode(jc) - { - } - JITCode& getJITCode() { return m_jitcode; } -private: - JITCode& m_jitcode; -}; - -} // namespace JSC - -#endif /* assembler_moco_MocoStubs_h */ diff --git a/js/src/assembler/wtf/SegmentedVector.h b/js/src/assembler/wtf/SegmentedVector.h deleted file mode 100644 index 9d67d71f656..00000000000 --- a/js/src/assembler/wtf/SegmentedVector.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef assembler_wtf_SegmentedVector_h -#define assembler_wtf_SegmentedVector_h - -#include "js/Utility.h" -#include "js/Vector.h" - -namespace WTF { - - // An iterator for SegmentedVector. It supports only the pre ++ operator - template class SegmentedVector; - template class SegmentedVectorIterator { - private: - friend class SegmentedVector; - public: - typedef SegmentedVectorIterator Iterator; - - ~SegmentedVectorIterator() { } - - T& operator*() const { return (*m_vector.m_segments[m_segment])[m_index]; } - T* operator->() const { return &(*m_vector.m_segments[m_segment])[m_index]; } - - // Only prefix ++ operator supported - Iterator& operator++() - { - ASSERT(m_index != SegmentSize); - ++m_index; - //if (m_index >= m_vector.m_segments.at(m_segment)->size()) { - if (m_index >= m_vector.m_segments[m_segment]->length()) { - //if (m_segment + 1 < m_vector.m_segments.size()) { - if (m_segment + 1 < m_vector.m_segments.length()) { - //ASSERT(m_vector.m_segments.at(m_segment)->size() > 0); - ASSERT(m_vector.m_segments[m_segment]->length() > 0); - ++m_segment; - m_index = 0; - } else { - // Points to the "end" symbol - m_segment = 0; - m_index = SegmentSize; - } - } - return *this; - } - - bool operator==(const Iterator& other) const - { - return (m_index == other.m_index && m_segment = other.m_segment && &m_vector == &other.m_vector); - } - - bool operator!=(const Iterator& other) const - { - return (m_index != other.m_index || m_segment != other.m_segment || &m_vector != &other.m_vector); - } - - SegmentedVectorIterator& operator=(const SegmentedVectorIterator& other) - { - m_vector = other.m_vector; - m_segment = other.m_segment; - m_index = other.m_index; - return *this; - } - - private: - SegmentedVectorIterator(SegmentedVector& vector, size_t segment, size_t index) - : m_vector(vector) - , m_segment(segment) - , m_index(index) - { - } - - SegmentedVector& m_vector; - size_t m_segment; - size_t m_index; - }; - - // SegmentedVector is just like Vector, but it doesn't move the values - // stored in its buffer when it grows. Therefore, it is safe to keep - // pointers into a SegmentedVector. - template class SegmentedVector { - friend class SegmentedVectorIterator; - public: - typedef SegmentedVectorIterator Iterator; - - SegmentedVector() - : m_size(0) - { - m_segments.append(&m_inlineSegment); - } - - ~SegmentedVector() - { - deleteAllSegments(); - } - - size_t size() const { return m_size; } - bool isEmpty() const { return !size(); } - - T& at(size_t index) - { - if (index < SegmentSize) - return m_inlineSegment[index]; - return segmentFor(index)->at(subscriptFor(index)); - } - - T& operator[](size_t index) - { - return at(index); - } - - T& last() - { - return at(size() - 1); - } - - template void append(const U& value) - { - ++m_size; - - if (m_size <= SegmentSize) { - //m_inlineSegment.uncheckedAppend(value); - m_inlineSegment.append(value); - return; - } - - if (!segmentExistsFor(m_size - 1)) - m_segments.append(js_new()); - //segmentFor(m_size - 1)->uncheckedAppend(value); - segmentFor(m_size - 1)->append(value); - } - - T& alloc() - { - append(T()); - return last(); - } - - void removeLast() - { - if (m_size <= SegmentSize) - m_inlineSegment.removeLast(); - else - segmentFor(m_size - 1)->removeLast(); - --m_size; - } - - void grow(size_t size) - { - ASSERT(size > m_size); - ensureSegmentsFor(size); - m_size = size; - } - - void clear() - { - deleteAllSegments(); - m_segments.resize(1); - m_inlineSegment.clear(); - m_size = 0; - } - - Iterator begin() - { - return Iterator(*this, 0, m_size ? 0 : SegmentSize); - } - - Iterator end() - { - return Iterator(*this, 0, SegmentSize); - } - - private: - typedef js::Vector Segment; - - void deleteAllSegments() - { - // Skip the first segment, because it's our inline segment, which was - // not created by new. - //for (size_t i = 1; i < m_segments.size(); i++) - for (size_t i = 1; i < m_segments.length(); i++) - js_delete(m_segments[i]); - } - - bool segmentExistsFor(size_t index) - { - //return index / SegmentSize < m_segments.size(); - return index / SegmentSize < m_segments.length(); - } - - Segment* segmentFor(size_t index) - { - return m_segments[index / SegmentSize]; - } - - size_t subscriptFor(size_t index) - { - return index % SegmentSize; - } - - void ensureSegmentsFor(size_t size) - { - size_t segmentCount = m_size / SegmentSize; - if (m_size % SegmentSize) - ++segmentCount; - //segmentCount = std::max(segmentCount, 1); // We always have at least our inline segment. - segmentCount = segmentCount > 1 ? segmentCount : 1; // We always have at least our inline segment. - - size_t neededSegmentCount = size / SegmentSize; - if (size % SegmentSize) - ++neededSegmentCount; - - // Fill up to N - 1 segments. - size_t end = neededSegmentCount - 1; - for (size_t i = segmentCount - 1; i < end; ++i) - ensureSegment(i, SegmentSize); - - // Grow segment N to accomodate the remainder. - ensureSegment(end, subscriptFor(size - 1) + 1); - } - - void ensureSegment(size_t segmentIndex, size_t size) - { - ASSERT(segmentIndex <= m_segments.size()); - if (segmentIndex == m_segments.size()) - m_segments.append(js_new()); - m_segments[segmentIndex]->grow(size); - } - - size_t m_size; - Segment m_inlineSegment; - js::Vector m_segments; - }; - -} // namespace WTF - -using WTF::SegmentedVector; - -#endif /* assembler_wtf_SegmentedVector_h */ diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index 3d2f9dd93d3..11fc37837db 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -11,7 +11,6 @@ #include "mozilla/Attributes.h" #include "mozilla/MathAlgorithms.h" -#include "assembler/assembler/AssemblerBufferWithConstantPool.h" #include "jit/arm/Architecture-arm.h" #include "jit/CompactBuffer.h" #include "jit/IonCode.h" diff --git a/js/src/jit/shared/Assembler-x86-shared.h b/js/src/jit/shared/Assembler-x86-shared.h index ffe5df35deb..7bbb3975bb6 100644 --- a/js/src/jit/shared/Assembler-x86-shared.h +++ b/js/src/jit/shared/Assembler-x86-shared.h @@ -675,7 +675,6 @@ class AssemblerX86Shared : public AssemblerShared } void cmpEAX(Label *label) { cmpSrc(label); } void bind(Label *label) { - JSC::MacroAssembler::Label jsclabel; JSC::X86Assembler::JmpDst dst(masm.label()); if (label->used()) { bool more; @@ -690,7 +689,6 @@ class AssemblerX86Shared : public AssemblerShared label->bind(dst.offset()); } void bind(RepatchLabel *label) { - JSC::MacroAssembler::Label jsclabel; JSC::X86Assembler::JmpDst dst(masm.label()); if (label->used()) { JSC::X86Assembler::JmpSrc jmp(label->offset()); @@ -704,7 +702,6 @@ class AssemblerX86Shared : public AssemblerShared // Re-routes pending jumps to a new label. void retarget(Label *label, Label *target) { - JSC::MacroAssembler::Label jsclabel; if (label->used()) { bool more; JSC::X86Assembler::JmpSrc jmp(label->offset()); diff --git a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h index 843b2e616d1..9ba6a299970 100644 --- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h +++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h @@ -9,7 +9,6 @@ #include "mozilla/DebugOnly.h" -#include "assembler/wtf/SegmentedVector.h" #include "jit/IonSpewer.h" #include "jit/shared/IonAssemblerBuffer.h" diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index 82acde428e8..669ec7e571a 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -408,7 +408,6 @@ class Assembler : public AssemblerX86Shared // Re-routes pending jumps to an external target, flushing the label in the // process. void retarget(Label *label, ImmPtr target, Relocation::Kind reloc) { - JSC::MacroAssembler::Label jsclabel; if (label->used()) { bool more; JSC::X86Assembler::JmpSrc jmp(label->offset()); diff --git a/js/src/moz.build b/js/src/moz.build index 8980935096c..7ddcdc01855 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -373,7 +373,6 @@ if CONFIG['ENABLE_ION']: ] elif CONFIG['JS_CODEGEN_ARM']: SOURCES += [ - 'assembler/assembler/ARMAssembler.cpp', 'assembler/assembler/MacroAssemblerARM.cpp', ]