fix shift instruction implementations on ARM

Unlike x86, ARM does not implicitly mask the shift value, so we must
do so explicitly.
This commit is contained in:
Joel Dice 2012-08-11 19:09:03 +00:00
parent 2687333a37
commit 69ffa28e1b
4 changed files with 136 additions and 32 deletions

View File

@ -634,72 +634,118 @@ write4(uint8_t* dst, uint32_t v)
memcpy(dst, &v, 4);
}
void
andC(Context* con, unsigned size, Assembler::Constant* a,
Assembler::Register* b, Assembler::Register* dst);
void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t)
{
if (size == 8) {
int tmp1 = newTemp(con), tmp2 = newTemp(con);
emit(con, lsl(tmp1, b->high, a->low));
emit(con, rsbi(tmp2, a->low, 32));
int tmp1 = newTemp(con), tmp2 = newTemp(con), tmp3 = newTemp(con);
ResolvedPromise maskPromise(0x3F);
Assembler::Constant mask(&maskPromise);
Assembler::Register dst(tmp3);
andC(con, 4, &mask, a, &dst);
emit(con, lsl(tmp1, b->high, tmp3));
emit(con, rsbi(tmp2, tmp3, 32));
emit(con, orrsh(tmp1, tmp1, b->low, tmp2, LSR));
emit(con, SETS(subi(t->high, a->low, 32)));
emit(con, SETS(subi(t->high, tmp3, 32)));
emit(con, SETCOND(mov(t->high, tmp1), MI));
emit(con, SETCOND(lsl(t->high, b->low, t->high), PL));
emit(con, lsl(t->low, b->low, a->low));
freeTemp(con, tmp1); freeTemp(con, tmp2);
emit(con, lsl(t->low, b->low, tmp3));
freeTemp(con, tmp1); freeTemp(con, tmp2); freeTemp(con, tmp3);
} else {
emit(con, lsl(t->low, b->low, a->low));
int tmp = newTemp(con);
ResolvedPromise maskPromise(0x1F);
Assembler::Constant mask(&maskPromise);
Assembler::Register dst(tmp);
andC(con, size, &mask, a, &dst);
emit(con, lsl(t->low, b->low, tmp));
freeTemp(con, tmp);
}
}
void
moveRR(Context* con, unsigned srcSize, Assembler::Register* src,
unsigned dstSize, Assembler::Register* dst);
void shiftLeftC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
{
assert(con, size == TargetBytesPerWord);
emit(con, lsli(t->low, b->low, getValue(a)));
if (getValue(a) & 0x1F) {
emit(con, lsli(t->low, b->low, getValue(a) & 0x1F));
} else {
moveRR(con, size, b, size, t);
}
}
void shiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t)
{
if (size == 8) {
int tmp1 = newTemp(con), tmp2 = newTemp(con);
emit(con, lsr(tmp1, b->low, a->low));
emit(con, rsbi(tmp2, a->low, 32));
int tmp1 = newTemp(con), tmp2 = newTemp(con), tmp3 = newTemp(con);
ResolvedPromise maskPromise(0x3F);
Assembler::Constant mask(&maskPromise);
Assembler::Register dst(tmp3);
andC(con, 4, &mask, a, &dst);
emit(con, lsr(tmp1, b->low, tmp3));
emit(con, rsbi(tmp2, tmp3, 32));
emit(con, orrsh(tmp1, tmp1, b->high, tmp2, LSL));
emit(con, SETS(subi(t->low, a->low, 32)));
emit(con, SETS(subi(t->low, tmp3, 32)));
emit(con, SETCOND(mov(t->low, tmp1), MI));
emit(con, SETCOND(asr(t->low, b->high, t->low), PL));
emit(con, asr(t->high, b->high, a->low));
freeTemp(con, tmp1); freeTemp(con, tmp2);
emit(con, asr(t->high, b->high, tmp3));
freeTemp(con, tmp1); freeTemp(con, tmp2); freeTemp(con, tmp3);
} else {
emit(con, asr(t->low, b->low, a->low));
int tmp = newTemp(con);
ResolvedPromise maskPromise(0x1F);
Assembler::Constant mask(&maskPromise);
Assembler::Register dst(tmp);
andC(con, size, &mask, a, &dst);
emit(con, asr(t->low, b->low, tmp));
freeTemp(con, tmp);
}
}
void shiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
{
assert(con, size == TargetBytesPerWord);
emit(con, asri(t->low, b->low, getValue(a)));
if (getValue(a) & 0x1F) {
emit(con, asri(t->low, b->low, getValue(a) & 0x1F));
} else {
moveRR(con, size, b, size, t);
}
}
void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t)
{
emit(con, lsr(t->low, b->low, a->low));
int tmpShift = newTemp(con);
ResolvedPromise maskPromise(size == 8 ? 0x3F : 0x1F);
Assembler::Constant mask(&maskPromise);
Assembler::Register dst(tmpShift);
andC(con, 4, &mask, a, &dst);
emit(con, lsr(t->low, b->low, tmpShift));
if (size == 8) {
int tmpHi = newTemp(con), tmpLo = newTemp(con);
emit(con, SETS(rsbi(tmpHi, a->low, 32)));
emit(con, SETS(rsbi(tmpHi, tmpShift, 32)));
emit(con, lsl(tmpLo, b->high, tmpHi));
emit(con, orr(t->low, t->low, tmpLo));
emit(con, addi(tmpHi, a->low, -32));
emit(con, addi(tmpHi, tmpShift, -32));
emit(con, lsr(tmpLo, b->high, tmpHi));
emit(con, orr(t->low, t->low, tmpLo));
emit(con, lsr(t->high, b->high, a->low));
emit(con, lsr(t->high, b->high, tmpShift));
freeTemp(con, tmpHi); freeTemp(con, tmpLo);
}
freeTemp(con, tmpShift);
}
void unsignedShiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
{
assert(con, size == TargetBytesPerWord);
emit(con, lsri(t->low, b->low, getValue(a)));
if (getValue(a) & 0x1F) {
emit(con, lsri(t->low, b->low, getValue(a) & 0x1F));
} else {
moveRR(con, size, b, size, t);
}
}
class ConstantPoolEntry: public Promise {
@ -909,10 +955,6 @@ jumpR(Context* con, unsigned size UNUSED, Assembler::Register* target)
emit(con, bx(target->low));
}
void
moveRR(Context* con, unsigned srcSize, Assembler::Register* src,
unsigned dstSize, Assembler::Register* dst);
void
swapRR(Context* con, unsigned aSize, Assembler::Register* a,
unsigned bSize, Assembler::Register* b)

View File

@ -1930,14 +1930,14 @@ interpret3(Thread* t, const int base)
int32_t b = popInt(t);
int32_t a = popInt(t);
pushInt(t, a << b);
pushInt(t, a << (b & 0x1F));
} goto loop;
case ishr: {
int32_t b = popInt(t);
int32_t a = popInt(t);
pushInt(t, a >> b);
pushInt(t, a >> (b & 0x1F));
} goto loop;
case istore:
@ -1976,7 +1976,7 @@ interpret3(Thread* t, const int base)
int32_t b = popInt(t);
uint32_t a = popInt(t);
pushInt(t, a >> b);
pushInt(t, a >> (b & 0x1F));
} goto loop;
case ixor: {
@ -2238,14 +2238,14 @@ interpret3(Thread* t, const int base)
int32_t b = popInt(t);
int64_t a = popLong(t);
pushLong(t, a << b);
pushLong(t, a << (b & 0x3F));
} goto loop;
case lshr: {
int32_t b = popInt(t);
int64_t a = popLong(t);
pushLong(t, a >> b);
pushLong(t, a >> (b & 0x3F));
} goto loop;
case lstore:
@ -2284,7 +2284,7 @@ interpret3(Thread* t, const int base)
int64_t b = popInt(t);
uint64_t a = popLong(t);
pushLong(t, a >> b);
pushLong(t, a >> (b & 0x3F));
} goto loop;
case lxor: {

View File

@ -20,7 +20,7 @@ public class Integers {
return m;
}
public static void main(String[] args) {
public static void main(String[] args) throws Exception {
{ int foo = 1028;
foo -= 1023;
expect(foo == 5);
@ -266,5 +266,49 @@ public class Integers {
expect((y + 0x8000) == (-11760768 + 0x8000));
expect(Math.min(796, 1069) == 796);
{ int b = 1;
expect((b << 32) == 1); }
{ int b = 0xFFFFFFFF;
expect((b >>> -1) == 1); }
{ int b = 0x10000000;
expect((b >> -31) == 0x8000000); }
{ int b = 1; int s = 32;
expect((b << s) == 1); }
{ int b = 0xFFFFFFFF; int s = -1;
expect((b >>> s) == 1); }
{ int b = 0x10000000; int s = -31;
expect((b >> s) == 0x8000000); }
{ int b = 0xBE;
expect((b & 0xFF) == 0xBE); }
{ int b = 0xBE;
expect((b >>> 0) == 0xBE); }
{ int b = 0xBE;
expect((b >> 0) == 0xBE); }
{ int b = 0xBE;
expect((b << 0) == 0xBE); }
{ int b = 0xBE;
expect(((b >>> 0) & 0xFF) == 0xBE); }
{ java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
java.io.DataOutputStream dout = new java.io.DataOutputStream(bout);
dout.writeInt(0xCAFEBABE);
dout.flush();
byte[] array = bout.toByteArray();
expect((array[0] & 0xFF) == 0xCA);
expect((array[1] & 0xFF) == 0xFE);
expect((array[2] & 0xFF) == 0xBA);
expect((array[3] & 0xFF) == 0xBE);
}
}
}

View File

@ -337,6 +337,24 @@ public class Longs {
expect(z[0] == 337192406);
expect(z[1] == -437261072);
}
{ long b = 1;
expect((b << 64) == 1); }
{ long b = 0xFFFFFFFFFFFFFFFFL;
expect((b >>> -1) == 1); }
{ long b = 0x10000000000L;
expect((b >> -63) == 0x8000000000L); }
{ long b = 1; int s = 64;
expect((b << s) == 1); }
{ long b = 0xFFFFFFFFFFFFFFFFL; int s = -1;
expect((b >>> s) == 1); }
{ long b = 0x10000000000L; int s = -63;
expect((b >> s) == 0x8000000000L); }
}
}