support 64-bit multiplies on 32-bit systems

This commit is contained in:
Joel Dice 2008-04-29 16:11:17 -06:00
parent 4c2d44099b
commit 59f92b6208

View File

@ -35,6 +35,12 @@ enum {
r15 = 15, r15 = 15,
}; };
int64_t FORCE_ALIGN
multiplyLong(int64_t a, int64_t b)
{
return a * b;
}
int64_t FORCE_ALIGN int64_t FORCE_ALIGN
divideLong(int64_t a, int64_t b) divideLong(int64_t a, int64_t b)
{ {
@ -438,9 +444,9 @@ pushR(Context*, unsigned, Assembler::Register*);
void void
pushC(Context* c, unsigned size, Assembler::Constant* a) pushC(Context* c, unsigned size, Assembler::Constant* a)
{ {
int64_t v = a->value->value();
if (BytesPerWord == 4 and size == 8) { if (BytesPerWord == 4 and size == 8) {
int64_t v = a->value->value();
ResolvedPromise low(v & 0xFFFFFFFF); ResolvedPromise low(v & 0xFFFFFFFF);
Assembler::Constant al(&low); Assembler::Constant al(&low);
@ -450,17 +456,26 @@ pushC(Context* c, unsigned size, Assembler::Constant* a)
pushC(c, 4, &ah); pushC(c, 4, &ah);
pushC(c, 4, &al); pushC(c, 4, &al);
} else { } else {
if (isInt8(v)) { if (a->value->resolved()) {
c->code.append(0x6a); int64_t v = a->value->value();
c->code.append(v); if (isInt8(v)) {
} else if (isInt32(v)) { c->code.append(0x6a);
c->code.append(0x68); c->code.append(v);
c->code.append4(v); } else if (isInt32(v)) {
c->code.append(0x68);
c->code.append4(v);
} else {
Assembler::Register tmp(c->client->acquireTemporary());
moveCR(c, size, a, &tmp);
pushR(c, size, &tmp);
c->client->releaseTemporary(tmp.low);
}
} else { } else {
Assembler::Register tmp(c->client->acquireTemporary()); assert(c, BytesPerWord == 4);
moveCR(c, size, a, &tmp);
pushR(c, size, &tmp); c->code.append(0x68);
c->client->releaseTemporary(tmp.low); appendImmediateTask(c, a->value, c->code.length());
c->code.appendAddress(static_cast<uintptr_t>(0));
} }
} }
} }
@ -1174,41 +1189,71 @@ addRM(Context* c, unsigned size UNUSED, Assembler::Register* a,
} }
void void
multiplyRR(Context* c, unsigned size UNUSED, Assembler::Register* a, multiplyRR(Context* c, unsigned size, Assembler::Register* a,
Assembler::Register* b) Assembler::Register* b)
{ {
assert(c, BytesPerWord == 8 or size == 4); // todo if (BytesPerWord == 4 and size == 8) {
pushR(c, size, a);
pushR(c, size, b);
rex(c); Assembler::Constant address
c->code.append(0x0f); (resolved(c, reinterpret_cast<intptr_t>(multiplyLong)));
c->code.append(0xaf); callC(c, BytesPerWord, &address);
c->code.append(0xc0 | (b->low << 3) | a->low);
Assembler::Register axdx(rax, rdx);
moveRR(c, 4, &axdx, b);
ResolvedPromise offsetPromise(16);
Assembler::Constant offset(&offsetPromise);
Assembler::Register stack(rsp);
addCR(c, BytesPerWord, &offset, &stack);
} else {
rex(c);
c->code.append(0x0f);
c->code.append(0xaf);
c->code.append(0xc0 | (b->low << 3) | a->low);
}
} }
void void
multiplyCR(Context* c, unsigned size, Assembler::Constant* a, multiplyCR(Context* c, unsigned size, Assembler::Constant* a,
Assembler::Register* b) Assembler::Register* b)
{ {
assert(c, BytesPerWord == 8 or size == 4); // todo if (BytesPerWord == 4 and size == 8) {
pushC(c, size, a);
pushR(c, size, b);
int64_t v = a->value->value(); Assembler::Constant address
if (v) { (resolved(c, reinterpret_cast<intptr_t>(multiplyLong)));
if (isInt32(v)) { callC(c, BytesPerWord, &address);
rex(c);
if (isInt8(v)) { Assembler::Register axdx(rax, rdx);
c->code.append(0x6b); moveRR(c, 4, &axdx, b);
c->code.append(0xc0 | (b->low << 3) | b->low);
c->code.append(v); ResolvedPromise offsetPromise(16);
Assembler::Constant offset(&offsetPromise);
Assembler::Register stack(rsp);
addCR(c, BytesPerWord, &offset, &stack);
} else {
int64_t v = a->value->value();
if (v) {
if (isInt32(v)) {
rex(c);
if (isInt8(v)) {
c->code.append(0x6b);
c->code.append(0xc0 | (b->low << 3) | b->low);
c->code.append(v);
} else {
c->code.append(0x69);
c->code.append(0xc0 | (b->low << 3) | b->low);
c->code.append4(v);
}
} else { } else {
c->code.append(0x69); Assembler::Register tmp(c->client->acquireTemporary());
c->code.append(0xc0 | (b->low << 3) | b->low); moveCR(c, size, a, &tmp);
c->code.append4(v); multiplyRR(c, size, &tmp, b);
c->client->releaseTemporary(tmp.low);
} }
} else {
Assembler::Register tmp(c->client->acquireTemporary());
moveCR(c, size, a, &tmp);
multiplyRR(c, size, &tmp, b);
c->client->releaseTemporary(tmp.low);
} }
} }
} }
@ -1996,6 +2041,7 @@ class MyAssembler: public Assembler {
*syncStack = false; *syncStack = false;
switch (op) { switch (op) {
case Multiply:
case Divide: case Divide:
case Remainder: case Remainder:
if (BytesPerWord == 4 and size == 8) { if (BytesPerWord == 4 and size == 8) {