mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 836486: Part 1 - Add in ARMv6 support for IonMonkey (r=jbramley)
* * * No Bug: Fix android bustage on armv6 push (r=red, CLOSED TREE) * * * aaand b2g
This commit is contained in:
parent
541c7cafe0
commit
8150d9a40c
@ -325,29 +325,53 @@ MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
|
||||
{
|
||||
JS_ASSERT(input != ScratchFloatReg);
|
||||
#ifdef JS_CPU_ARM
|
||||
Label notSplit;
|
||||
ma_vimm(0.5, ScratchFloatReg);
|
||||
ma_vadd(input, ScratchFloatReg, ScratchFloatReg);
|
||||
// Convert the double into an unsigned fixed point value with 24 bits of
|
||||
// precision. The resulting number will look like 0xII.DDDDDD
|
||||
as_vcvtFixed(ScratchFloatReg, false, 24, true);
|
||||
// Move the fixed point value into an integer register
|
||||
as_vxfer(output, InvalidReg, ScratchFloatReg, FloatToCore);
|
||||
// See if this value *might* have been an exact integer after adding 0.5
|
||||
// This tests the 1/2 through 1/16,777,216th places, but 0.5 needs to be tested out to
|
||||
// the 1/140,737,488,355,328th place.
|
||||
ma_tst(output, Imm32(0x00ffffff));
|
||||
// convert to a uint8 by shifting out all of the fraction bits
|
||||
ma_lsr(Imm32(24), output, output);
|
||||
// If any of the bottom 24 bits were non-zero, then we're good, since this number
|
||||
// can't be exactly XX.0
|
||||
ma_b(¬Split, NonZero);
|
||||
as_vxfer(ScratchRegister, InvalidReg, input, FloatToCore);
|
||||
ma_cmp(ScratchRegister, Imm32(0));
|
||||
// If the lower 32 bits of the double were 0, then this was an exact number,
|
||||
// and it should be even.
|
||||
ma_bic(Imm32(1), output, NoSetCond, Zero);
|
||||
bind(¬Split);
|
||||
if (hasVFPv3()) {
|
||||
Label notSplit;
|
||||
ma_vadd(input, ScratchFloatReg, ScratchFloatReg);
|
||||
// Convert the double into an unsigned fixed point value with 24 bits of
|
||||
// precision. The resulting number will look like 0xII.DDDDDD
|
||||
as_vcvtFixed(ScratchFloatReg, false, 24, true);
|
||||
// Move the fixed point value into an integer register
|
||||
as_vxfer(output, InvalidReg, ScratchFloatReg, FloatToCore);
|
||||
// see if this value *might* have been an exact integer after adding 0.5
|
||||
// This tests the 1/2 through 1/16,777,216th places, but 0.5 needs to be tested out to
|
||||
// the 1/140,737,488,355,328th place.
|
||||
ma_tst(output, Imm32(0x00ffffff));
|
||||
// convert to a uint8 by shifting out all of the fraction bits
|
||||
ma_lsr(Imm32(24), output, output);
|
||||
// If any of the bottom 24 bits were non-zero, then we're good, since this number
|
||||
// can't be exactly XX.0
|
||||
ma_b(¬Split, NonZero);
|
||||
as_vxfer(ScratchRegister, InvalidReg, input, FloatToCore);
|
||||
ma_cmp(ScratchRegister, Imm32(0));
|
||||
// If the lower 32 bits of the double were 0, then this was an exact number,
|
||||
// and it should be even.
|
||||
ma_bic(Imm32(1), output, NoSetCond, Zero);
|
||||
bind(¬Split);
|
||||
|
||||
} else {
|
||||
Label outOfRange;
|
||||
ma_vcmpz(input);
|
||||
// do the add, in place so we can reference it later
|
||||
ma_vadd(input, ScratchFloatReg, input);
|
||||
// do the conversion to an integer.
|
||||
as_vcvt(VFPRegister(ScratchFloatReg).uintOverlay(), VFPRegister(input));
|
||||
// copy the converted value out
|
||||
as_vxfer(output, InvalidReg, ScratchFloatReg, FloatToCore);
|
||||
as_vmrs(pc);
|
||||
ma_b(&outOfRange, Overflow);
|
||||
ma_cmp(output, Imm32(0xff));
|
||||
ma_mov(Imm32(0xff), output, NoSetCond, Above);
|
||||
ma_b(&outOfRange, Above);
|
||||
// convert it back to see if we got the same value back
|
||||
as_vcvt(ScratchFloatReg, VFPRegister(ScratchFloatReg).uintOverlay());
|
||||
// do the check
|
||||
as_vcmp(ScratchFloatReg, input);
|
||||
as_vmrs(pc);
|
||||
ma_bic(Imm32(1), output, NoSetCond, Zero);
|
||||
bind(&outOfRange);
|
||||
}
|
||||
#else
|
||||
|
||||
Label positive, done;
|
||||
|
@ -4,21 +4,124 @@
|
||||
* 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/. */
|
||||
#define HWCAP_ARMv7 (1 << 31)
|
||||
#include <mozilla/StandardInteger.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <elf.h>
|
||||
|
||||
// lame check for kernel version
|
||||
// see bug 586550
|
||||
#if !(defined(ANDROID) || defined(MOZ_B2G))
|
||||
#include <asm/hwcap.h>
|
||||
#else
|
||||
#define HWCAP_VFP (1<<0)
|
||||
#define HWCAP_VFPv3 (1<<1)
|
||||
#define HWCAP_VFPv3D16 (1<<2)
|
||||
#define HWCAP_VFPv4 (1<<3)
|
||||
#define HWCAP_IDIVA (1<<4)
|
||||
#define HWCAP_IDIVT (1<<5)
|
||||
#define HWCAP_NEON (1<<6)
|
||||
#define HWCAP_ARMv7 (1<<7)
|
||||
#endif
|
||||
#include "ion/arm/Architecture-arm.h"
|
||||
#include "ion/arm/Assembler-arm.h"
|
||||
namespace js {
|
||||
namespace ion {
|
||||
|
||||
uint32_t getFlags()
|
||||
{
|
||||
static bool isSet = false;
|
||||
static uint32_t flags = 0;
|
||||
if (isSet)
|
||||
return flags;
|
||||
|
||||
#if WTF_OS_LINUX
|
||||
int fd = open("/proc/self/auxv", O_RDONLY);
|
||||
if (fd > 0) {
|
||||
Elf32_auxv_t aux;
|
||||
while (read(fd, &aux, sizeof(Elf32_auxv_t))) {
|
||||
if (aux.a_type == AT_HWCAP) {
|
||||
close(fd);
|
||||
flags = aux.a_un.a_val;
|
||||
isSet = true;
|
||||
#ifdef __ARM_ARCH_7__
|
||||
// this should really be detected at runtime, but
|
||||
// /proc/*/auxv doesn't seem to carry the ISA
|
||||
// I could look in /proc/cpuinfo as well, but
|
||||
// the chances that it will be different from this
|
||||
// are low.
|
||||
flags |= HWCAP_ARMv7;
|
||||
#endif
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
#elif defined(WTF_OS_ANDROID) || defined(MOZ_B2G)
|
||||
FILE *fp = fopen("/proc/cpuinfo", "r");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
char buf[1024];
|
||||
fread(buf, sizeof(char), sizeof(buf), fp);
|
||||
fclose(fp);
|
||||
if (strstr(buf, "vfp"))
|
||||
flags |= HWCAP_VFP;
|
||||
|
||||
if (strstr(buf, "vfpv3"))
|
||||
flags |= HWCAP_VFPv3;
|
||||
|
||||
if (strstr(buf, "vfpv3d16"))
|
||||
flags |= HWCAP_VFPv3D16;
|
||||
|
||||
if (strstr(buf, "vfpv4"))
|
||||
flags |= HWCAP_VFPv4;
|
||||
|
||||
if (strstr(buf, "idiva"))
|
||||
flags |= HWCAP_IDIVA;
|
||||
|
||||
if (strstr(buf, "idivt"))
|
||||
flags |= HWCAP_IDIVT;
|
||||
|
||||
if (strstr(buf, "neon"))
|
||||
flags |= HWCAP_NEON;
|
||||
|
||||
// not part of the HWCAP flag, but I need to know this, and we're not using
|
||||
// that bit, so... I'm using it
|
||||
if (strstr(buf, "ARMv7"))
|
||||
flags |= HWCAP_ARMv7;
|
||||
|
||||
isSet = true;
|
||||
return flags;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasMOVWT()
|
||||
{
|
||||
return true;
|
||||
return js::ion::getFlags() & HWCAP_ARMv7;
|
||||
}
|
||||
bool hasVFPv3()
|
||||
{
|
||||
return true;
|
||||
return js::ion::getFlags() & HWCAP_VFPv3;
|
||||
}
|
||||
bool has32DR()
|
||||
bool hasVFP()
|
||||
{
|
||||
return true;
|
||||
return js::ion::getFlags() & HWCAP_VFP;
|
||||
}
|
||||
|
||||
bool has32DP()
|
||||
{
|
||||
return !(js::ion::getFlags() & HWCAP_VFPv3D16 && !(js::ion::getFlags() & HWCAP_NEON));
|
||||
}
|
||||
bool useConvReg()
|
||||
{
|
||||
return has32DP();
|
||||
}
|
||||
|
||||
} // namespace ion
|
||||
|
@ -16,7 +16,7 @@
|
||||
namespace js {
|
||||
namespace ion {
|
||||
|
||||
static const ptrdiff_t STACK_SLOT_SIZE = 4;
|
||||
static const uint32_t STACK_SLOT_SIZE = 4;
|
||||
static const uint32_t DOUBLE_STACK_ALIGNMENT = 2;
|
||||
|
||||
// In bytes: slots needed for potential memory->memory move spills.
|
||||
@ -209,6 +209,7 @@ class FloatRegisters
|
||||
|
||||
bool hasMOVWT();
|
||||
bool hasVFPv3();
|
||||
bool hasVFP();
|
||||
bool has16DP();
|
||||
|
||||
} // namespace ion
|
||||
|
@ -160,7 +160,7 @@ InstDTR::isTHIS(const Instruction &i)
|
||||
}
|
||||
|
||||
InstDTR *
|
||||
InstDTR::asTHIS(Instruction &i)
|
||||
InstDTR::asTHIS(const Instruction &i)
|
||||
{
|
||||
if (isTHIS(i))
|
||||
return (InstDTR*)&i;
|
||||
@ -174,7 +174,7 @@ InstLDR::isTHIS(const Instruction &i)
|
||||
}
|
||||
|
||||
InstLDR *
|
||||
InstLDR::asTHIS(Instruction &i)
|
||||
InstLDR::asTHIS(const Instruction &i)
|
||||
{
|
||||
if (isTHIS(i))
|
||||
return (InstLDR*)&i;
|
||||
@ -605,9 +605,20 @@ Assembler::getCF32Target(Iter *iter)
|
||||
uint32_t *dest = (uint32_t*) (targ_bot.decode() | (targ_top.decode() << 16));
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
if (inst1->is<InstLDR>()) {
|
||||
JS_NOT_REACHED("ldr-based relocs NYI");
|
||||
InstLDR *load = inst1->as<InstLDR>();
|
||||
uint32_t inst = load->encode();
|
||||
// get the address of the instruction as a raw pointer
|
||||
char *dataInst = reinterpret_cast<char*>(load);
|
||||
IsUp_ iu = IsUp_(inst & IsUp);
|
||||
int32_t offset = inst & 0xfff;
|
||||
if (iu != IsUp) {
|
||||
offset = - offset;
|
||||
}
|
||||
uint32_t **ptr = (uint32_t **)&dataInst[offset + 8];
|
||||
return *ptr;
|
||||
|
||||
}
|
||||
|
||||
JS_NOT_REACHED("unsupported branch relocation");
|
||||
@ -658,7 +669,22 @@ Assembler::getPtr32Target(Iter *start, Register *dest, RelocStyle *style)
|
||||
uint32_t *value = (uint32_t*) (targ_bot.decode() | (targ_top.decode() << 16));
|
||||
return value;
|
||||
}
|
||||
|
||||
if (load1->is<InstLDR>()) {
|
||||
InstLDR *load = load1->as<InstLDR>();
|
||||
uint32_t inst = load->encode();
|
||||
// get the address of the instruction as a raw pointer
|
||||
char *dataInst = reinterpret_cast<char*>(load);
|
||||
IsUp_ iu = IsUp_(inst & IsUp);
|
||||
int32_t offset = inst & 0xfff;
|
||||
if (iu == IsDown)
|
||||
offset = - offset;
|
||||
if (dest)
|
||||
*dest = toRD(*load);
|
||||
if (style)
|
||||
*style = L_LDR;
|
||||
uint32_t **ptr = (uint32_t **)&dataInst[offset + 8];
|
||||
return *ptr;
|
||||
}
|
||||
JS_NOT_REACHED("unsupported relocation");
|
||||
return NULL;
|
||||
}
|
||||
@ -1539,6 +1565,20 @@ Assembler::as_Imm32Pool(Register dest, uint32_t value, ARMBuffer::PoolEntry *pe,
|
||||
php.phd.init(0, c, PoolHintData::poolDTR, dest);
|
||||
return m_buffer.insertEntry(4, (uint8_t*)&php.raw, int32Pool, (uint8_t*)&value, pe);
|
||||
}
|
||||
void
|
||||
Assembler::as_WritePoolEntry(Instruction *addr, Condition c, uint32_t data)
|
||||
{
|
||||
JS_ASSERT(addr->is<InstLDR>());
|
||||
int32_t offset = addr->encode() & 0xfff;
|
||||
if ((addr->encode() & IsUp) != IsUp)
|
||||
offset = -offset;
|
||||
char * rawAddr = reinterpret_cast<char*>(addr);
|
||||
uint32_t * dest = reinterpret_cast<uint32_t*>(&rawAddr[offset + 8]);
|
||||
*dest = data;
|
||||
Condition orig_cond;
|
||||
addr->extractCond(&orig_cond);
|
||||
JS_ASSERT(orig_cond == c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_BranchPool(uint32_t value, RepatchLabel *label, ARMBuffer::PoolEntry *pe, Condition c)
|
||||
@ -2310,9 +2350,11 @@ Assembler::patchDataWithValueCheck(CodeLocationLabel label, ImmWord newValue, Im
|
||||
const uint32_t *val = getPtr32Target(&iter, &dest, &rs);
|
||||
JS_ASSERT((uint32_t)val == expectedValue.value);
|
||||
reinterpret_cast<MacroAssemblerARM*>(dummy)->ma_movPatchable(Imm32(newValue.value), dest, Always, rs, ptr);
|
||||
|
||||
AutoFlushCache::updateTop(uintptr_t(ptr), 4);
|
||||
AutoFlushCache::updateTop(uintptr_t(ptr->next()), 4);
|
||||
// L_LDR won't cause any instructions to be updated.
|
||||
if (rs != L_LDR) {
|
||||
AutoFlushCache::updateTop(uintptr_t(ptr), 4);
|
||||
AutoFlushCache::updateTop(uintptr_t(ptr->next()), 4);
|
||||
}
|
||||
}
|
||||
|
||||
// This just stomps over memory with 32 bits of raw data. Its purpose is to
|
||||
|
@ -1409,6 +1409,8 @@ class Assembler
|
||||
|
||||
BufferOffset as_dtm(LoadStore ls, Register rn, uint32_t mask,
|
||||
DTMMode mode, DTMWriteBack wb, Condition c = Always);
|
||||
//overwrite a pool entry with new data.
|
||||
void as_WritePoolEntry(Instruction *addr, Condition c, uint32_t data);
|
||||
// load a 32 bit immediate from a pool into a register
|
||||
BufferOffset as_Imm32Pool(Register dest, uint32_t value, ARMBuffer::PoolEntry *pe = NULL, Condition c = Always);
|
||||
// make a patchable jump that can target the entire 32 bit address space.
|
||||
@ -1789,7 +1791,7 @@ class InstDTR : public Instruction
|
||||
{ }
|
||||
|
||||
static bool isTHIS(const Instruction &i);
|
||||
static InstDTR *asTHIS(Instruction &i);
|
||||
static InstDTR *asTHIS(const Instruction &i);
|
||||
|
||||
};
|
||||
JS_STATIC_ASSERT(sizeof(InstDTR) == sizeof(Instruction));
|
||||
@ -1801,7 +1803,7 @@ class InstLDR : public InstDTR
|
||||
: InstDTR(IsLoad, IsWord, mode, rt, addr, c)
|
||||
{ }
|
||||
static bool isTHIS(const Instruction &i);
|
||||
static InstLDR *asTHIS(Instruction &i);
|
||||
static InstLDR *asTHIS(const Instruction &i);
|
||||
|
||||
};
|
||||
JS_STATIC_ASSERT(sizeof(InstDTR) == sizeof(InstLDR));
|
||||
|
@ -260,7 +260,15 @@ MacroAssemblerARM::ma_alu(Register src1, Imm32 imm, Register dest,
|
||||
if ((imm.value >> 16) != 0)
|
||||
as_movt(ScratchRegister, (imm.value >> 16) & 0xffff, c);
|
||||
} else {
|
||||
JS_NOT_REACHED("non-ARMv7 loading of immediates NYI.");
|
||||
// Going to have to use a load. If the operation is a move, then just move it into the
|
||||
// destination register
|
||||
if (op == op_mov) {
|
||||
as_Imm32Pool(dest, imm.value, NULL, c);
|
||||
return;
|
||||
} else {
|
||||
// If this isn't just going into a register, then stick it in a temp, and then proceed.
|
||||
as_Imm32Pool(ScratchRegister, imm.value, NULL, c);
|
||||
}
|
||||
}
|
||||
as_alu(dest, src1, O2Reg(ScratchRegister), op, sc, c);
|
||||
}
|
||||
@ -301,11 +309,17 @@ MacroAssemblerARM::ma_movPatchable(Imm32 imm_, Register dest,
|
||||
switch(rs) {
|
||||
case L_MOVWT:
|
||||
as_movw(dest, Imm16(imm & 0xffff), c, i);
|
||||
// i can be NULL here. that just means "insert in the next in sequence."
|
||||
// NextInst is special cased to not do anything when it is passed NULL, so two
|
||||
// consecutive instructions will be inserted.
|
||||
i = NextInst(i);
|
||||
as_movt(dest, Imm16(imm >> 16 & 0xffff), c, i);
|
||||
break;
|
||||
case L_LDR:
|
||||
//as_Imm32Pool(dest, imm, c, i);
|
||||
if(i == NULL)
|
||||
as_Imm32Pool(dest, imm, NULL, c);
|
||||
else
|
||||
as_WritePoolEntry(i, c, imm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -331,7 +345,13 @@ MacroAssemblerARM::ma_mov(const ImmGCPtr &ptr, Register dest)
|
||||
// As opposed to x86/x64 version, the data relocation has to be executed
|
||||
// before to recover the pointer, and not after.
|
||||
writeDataRelocation(ptr);
|
||||
ma_movPatchable(Imm32(ptr.value), dest, Always, L_MOVWT);
|
||||
RelocStyle rs;
|
||||
if (hasMOVWT()) {
|
||||
rs = L_MOVWT;
|
||||
} else {
|
||||
rs = L_LDR;
|
||||
}
|
||||
ma_movPatchable(Imm32(ptr.value), dest, Always, rs);
|
||||
}
|
||||
|
||||
// Shifts (just a move with a shifting op2)
|
||||
@ -1232,22 +1252,23 @@ MacroAssemblerARM::ma_vimm(double value, FloatRegister dest, Condition cc)
|
||||
double d;
|
||||
} dpun;
|
||||
dpun.d = value;
|
||||
if (hasVFPv3()) {
|
||||
if (dpun.s.lo == 0) {
|
||||
if (dpun.s.hi == 0) {
|
||||
// To zero a register, load 1.0, then execute dN <- dN - dN
|
||||
VFPImm dblEnc(0x3FF00000);
|
||||
as_vimm(dest, dblEnc, cc);
|
||||
as_vsub(dest, dest, dest, cc);
|
||||
return;
|
||||
}
|
||||
|
||||
VFPImm dblEnc(dpun.s.hi);
|
||||
if (dblEnc.isValid()) {
|
||||
as_vimm(dest, dblEnc, cc);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((dpun.s.lo) == 0) {
|
||||
if (dpun.s.hi == 0) {
|
||||
// To zero a register, load 1.0, then execute dN <- dN - dN
|
||||
VFPImm dblEnc(0x3FF00000);
|
||||
as_vimm(dest, dblEnc, cc);
|
||||
as_vsub(dest, dest, dest, cc);
|
||||
return;
|
||||
}
|
||||
|
||||
VFPImm dblEnc(dpun.s.hi);
|
||||
if (dblEnc.isValid()) {
|
||||
as_vimm(dest, dblEnc, cc);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
// Fall back to putting the value in a pool.
|
||||
as_FImm64Pool(dest, value, NULL, cc);
|
||||
|
@ -556,7 +556,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
|
||||
CodeOffsetLabel pushWithPatch(ImmWord imm) {
|
||||
CodeOffsetLabel label = currentOffset();
|
||||
ma_movPatchable(Imm32(imm.value), ScratchRegister, Always, L_MOVWT);
|
||||
ma_movPatchable(Imm32(imm.value), ScratchRegister, Always, hasMOVWT() ? L_MOVWT : L_LDR);
|
||||
ma_push(ScratchRegister);
|
||||
return label;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user