refactor intrinsic support

This ensures that the low-level, architecture specific code need not
be aware of the semantics and names of Java methods.
This commit is contained in:
Joel Dice 2009-10-17 19:26:14 -06:00
parent f702795178
commit 15020d77a6
6 changed files with 156 additions and 144 deletions

View File

@ -56,14 +56,14 @@ enum BinaryOperation {
Float2Float, Float2Float,
Float2Int, Float2Int,
Int2Float, Int2Float,
FloatSqrt, FloatSquareRoot,
FloatAbs, FloatAbsolute,
Abs, Absolute,
NoBinaryOperation = -1 NoBinaryOperation = -1
}; };
const unsigned BinaryOperationCount = Abs + 1; const unsigned BinaryOperationCount = Absolute + 1;
enum TernaryOperation { enum TernaryOperation {
Add, Add,
@ -344,14 +344,6 @@ class Assembler {
virtual int framePointerOffset() = 0; virtual int framePointerOffset() = 0;
virtual void nextFrame(void** stack, void** base) = 0; virtual void nextFrame(void** stack, void** base) = 0;
virtual BinaryOperation binaryIntrinsic(const char* className,
const char* methodName,
const char* parameterSpec) = 0;
virtual TernaryOperation ternaryIntrinsic(const char* className,
const char* methodName,
const char* parameterSpec) = 0;
virtual void plan virtual void plan
(UnaryOperation op, (UnaryOperation op,
unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask,

View File

@ -783,51 +783,76 @@ class Context {
virtual intptr_t getThunk(BinaryOperation op, unsigned size, virtual intptr_t getThunk(BinaryOperation op, unsigned size,
unsigned resultSize) unsigned resultSize)
{ {
if (size == 8) {
switch(op) { switch(op) {
case FloatNegate: case FloatNegate:
if (size == 4) { assert(t, resultSize == 8);
return local::getThunk(t, negateFloatThunk);
} else {
return local::getThunk(t, negateDoubleThunk); return local::getThunk(t, negateDoubleThunk);
}
case FloatSquareRoot:
assert(t, resultSize == 8);
return local::getThunk(t, squareRootDoubleThunk);
case Float2Float: case Float2Float:
if (size == 4 and resultSize == 8) { assert(t, resultSize == 4);
return local::getThunk(t, floatToDoubleThunk);
} else if (size == 8 and resultSize == 4) {
return local::getThunk(t, doubleToFloatThunk); return local::getThunk(t, doubleToFloatThunk);
}
case Float2Int: case Float2Int:
if (size == 4 and resultSize == 4) { if (resultSize == 8) {
return local::getThunk(t, floatToIntThunk);
} else if (size == 4 and resultSize == 8) {
return local::getThunk(t, floatToLongThunk);
} else if (size == 8 and resultSize == 4) {
return local::getThunk(t, doubleToIntThunk);
} else if (size == 8 and resultSize == 8) {
return local::getThunk(t, doubleToLongThunk); return local::getThunk(t, doubleToLongThunk);
} else {
assert(t, resultSize == 4);
return local::getThunk(t, doubleToIntThunk);
} }
case Int2Float: case Int2Float:
if (size == 4 and resultSize == 4) { if (resultSize == 8) {
return local::getThunk(t, intToFloatThunk);
} else if (size == 4 and resultSize == 8) {
return local::getThunk(t, intToDoubleThunk);
} else if (size == 8 and resultSize == 4) {
return local::getThunk(t, longToFloatThunk);
} else if (size == 8 and resultSize == 8) {
return local::getThunk(t, longToDoubleThunk); return local::getThunk(t, longToDoubleThunk);
} else {
assert(t, resultSize == 4);
return local::getThunk(t, longToFloatThunk);
} }
default: break; default: abort(t);
}
} else {
assert(t, size == 4);
switch(op) {
case FloatNegate:
assert(t, size == 4);
return local::getThunk(t, negateFloatThunk);
case FloatAbsolute:
assert(t, size == 4);
return local::getThunk(t, absoluteFloatThunk);
case Float2Float:
assert(t, resultSize == 8);
return local::getThunk(t, floatToDoubleThunk);
case Float2Int:
if (resultSize == 4) {
return local::getThunk(t, floatToIntThunk);
} else {
assert(t, resultSize == 8);
return local::getThunk(t, floatToLongThunk);
} }
abort(t); case Int2Float:
if (resultSize == 4) {
return local::getThunk(t, intToFloatThunk);
} else {
assert(t, resultSize == 8);
return local::getThunk(t, intToDoubleThunk);
} }
virtual intptr_t getThunk(TernaryOperation op, unsigned size, unsigned) default: abort(t);
{ }
}
}
virtual intptr_t getThunk(TernaryOperation op, unsigned size, unsigned) {
if (size == 8) { if (size == 8) {
switch (op) { switch (op) {
case Divide: case Divide:
@ -862,9 +887,10 @@ class Context {
case JumpIfFloatLessOrEqualOrUnordered: case JumpIfFloatLessOrEqualOrUnordered:
return local::getThunk(t, compareDoublesLThunk); return local::getThunk(t, compareDoublesLThunk);
default: break; default: abort(t);
} }
} else if (size == 4) { } else {
assert(t, size == 4);
switch (op) { switch (op) {
case FloatAdd: case FloatAdd:
return local::getThunk(t, addFloatThunk); return local::getThunk(t, addFloatThunk);
@ -889,11 +915,9 @@ class Context {
case JumpIfFloatLessOrEqualOrUnordered: case JumpIfFloatLessOrEqualOrUnordered:
return local::getThunk(t, compareFloatsLThunk); return local::getThunk(t, compareFloatsLThunk);
default: break; default: abort(t);
} }
} }
abort(t);
} }
MyThread* t; MyThread* t;
@ -2055,6 +2079,12 @@ negateDouble(uint64_t a)
return doubleToBits(- bitsToDouble(a)); return doubleToBits(- bitsToDouble(a));
} }
uint64_t
squareRootDouble(uint64_t a)
{
return doubleToBits(sqrt(bitsToDouble(a)));
}
uint64_t uint64_t
doubleToFloat(int64_t a) doubleToFloat(int64_t a)
{ {
@ -2109,6 +2139,12 @@ negateFloat(uint32_t a)
return floatToBits(- bitsToFloat(a)); return floatToBits(- bitsToFloat(a));
} }
uint64_t
absoluteFloat(uint32_t a)
{
return floatToBits(fabsf(bitsToFloat(a)));
}
int64_t int64_t
divideLong(int64_t b, int64_t a) divideLong(int64_t b, int64_t a)
{ {
@ -2868,6 +2904,38 @@ floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
return t->exception == 0; return t->exception == 0;
} }
bool
intrinsic(MyThread* t, Frame* frame, object target)
{
#define MATCH(name, constant) \
(byteArrayLength(t, name) - 1 == sizeof(constant) \
and strcmp(reinterpret_cast<char*>(&byteArrayBody(t, name, 0)), \
constant) == 0)
object className = vm::className(t, methodClass(t, target));
if (UNLIKELY(MATCH(className, "java/lang/Math"))) {
Compiler* c = frame->c;
if (MATCH(methodName(t, target), "sqrt")
and MATCH(methodSpec(t, target), "(D)D"))
{
frame->pushLong(c->fsqrt(8, frame->popLong()));
return true;
} else if (MATCH(methodName(t, target), "abs")) {
if (MATCH(methodSpec(t, target), "(I)I")) {
frame->pushInt(c->abs(4, frame->popInt()));
return true;
} else if (MATCH(methodSpec(t, target), "(J)J")) {
frame->pushLong(c->abs(8, frame->popLong()));
return true;
} else if (MATCH(methodSpec(t, target), "(F)F")) {
frame->pushInt(c->fabs(4, frame->popInt()));
return true;
}
}
}
return false;
}
void void
compile(MyThread* t, Frame* initialFrame, unsigned ip, compile(MyThread* t, Frame* initialFrame, unsigned ip,
int exceptionHandlerStart) int exceptionHandlerStart)
@ -3878,58 +3946,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
assert(t, methodFlags(t, target) & ACC_STATIC); assert(t, methodFlags(t, target) & ACC_STATIC);
bool usedIntrinsic = false; if (not intrinsic(t, frame, target)) {
int params = methodParameterCount(t, target);
if (params == 1) {
BinaryOperation op = t->arch->binaryIntrinsic
(reinterpret_cast<char*>
(&byteArrayBody(t, className(t, methodClass(t, target)), 0)),
reinterpret_cast<char*>
(&byteArrayBody(t, methodName(t, target), 0)),
reinterpret_cast<char*>
(&byteArrayBody(t, methodSpec(t, target), 0)));
if (op != NoBinaryOperation) {
if (DebugIntrinsics) {
fprintf(stderr, "Using binary intrinsic %i.\n", op);
}
int opSize = methodParameterFootprint(t, target) * 4;
int resSize = resultSize(t, methodReturnCode(t, target));
Compiler::Operand* param;
if (opSize == 4) {
param = frame->popInt();
} else {
param = frame->popLong();
}
Compiler::Operand* operand = c->operation
(op, opSize, resSize, operandTypeForFieldCode
(t, methodReturnCode(t, target)), param);
if (resSize == 4) {
frame->pushInt(operand);
} else {
frame->pushLong(operand);
}
usedIntrinsic = true;
}
} else if (params == 2) {
TernaryOperation op = t->arch->ternaryIntrinsic
(reinterpret_cast<char*>
(&byteArrayBody(t, className(t, methodClass(t, target)), 0)),
reinterpret_cast<char*>
(&byteArrayBody(t, methodName(t, target), 0)),
reinterpret_cast<char*>
(&byteArrayBody(t, methodSpec(t, target), 0)));
if (op != NoTernaryOperation) {
if (DebugIntrinsics) {
fprintf(stderr, "Could use ternary intrinsic %i.\n", op);
}
//int aSize, bSize;
//int resSize = resultSize(t, methodReturnCode(t, target));
//TODO: use intrinsic
}
}
if (not usedIntrinsic) {
bool tailCall = isTailCall(t, code, ip, context->method, target); bool tailCall = isTailCall(t, code, ip, context->method, target);
compileDirectInvoke(t, frame, target, tailCall); compileDirectInvoke(t, frame, target, tailCall);
} }

View File

@ -6371,22 +6371,26 @@ class MyCompiler: public Compiler {
return result; return result;
} }
virtual Operand* operation(BinaryOperation op, unsigned aSize, virtual Operand* abs(unsigned size, Operand* a) {
unsigned resSize, OperandType resType, Operand* a) assert(&c, static_cast<Value*>(a)->type == ValueGeneral);
{ Value* result = value(&c, ValueGeneral);
Value* result = value(&c, valueType(&c, resType)); appendTranslate(&c, Absolute, size, static_cast<Value*>(a), size, result);
appendTranslate(&c, op, aSize, static_cast<Value*>(a), resSize, result);
return result; return result;
} }
virtual Operand* operation(TernaryOperation op, unsigned aSize, virtual Operand* fabs(unsigned size, Operand* a) {
unsigned bSize, unsigned resSize, assert(&c, static_cast<Value*>(a)->type == ValueFloat);
OperandType resType, Operand* a, Operand* b) Value* result = value(&c, ValueFloat);
{ appendTranslate
Value* result = value(&c, valueType(&c, resType)); (&c, FloatAbsolute, size, static_cast<Value*>(a), size, result);
appendCombine return result;
(&c, op, aSize, static_cast<Value*>(a), bSize, static_cast<Value*>(b), }
resSize, result);
virtual Operand* fsqrt(unsigned size, Operand* a) {
assert(&c, static_cast<Value*>(a)->type == ValueFloat);
Value* result = value(&c, ValueFloat);
appendTranslate
(&c, FloatSquareRoot, size, static_cast<Value*>(a), size, result);
return result; return result;
} }

View File

@ -176,12 +176,9 @@ class Compiler {
virtual Operand* xor_(unsigned size, Operand* a, Operand* b) = 0; virtual Operand* xor_(unsigned size, Operand* a, Operand* b) = 0;
virtual Operand* neg(unsigned size, Operand* a) = 0; virtual Operand* neg(unsigned size, Operand* a) = 0;
virtual Operand* fneg(unsigned size, Operand* a) = 0; virtual Operand* fneg(unsigned size, Operand* a) = 0;
virtual Operand* operation(BinaryOperation op, unsigned aSize, virtual Operand* abs(unsigned size, Operand* a) = 0;
unsigned resSize, OperandType resType, virtual Operand* fabs(unsigned size, Operand* a) = 0;
Operand* a) = 0; virtual Operand* fsqrt(unsigned size, Operand* a) = 0;
virtual Operand* operation(TernaryOperation op, unsigned aSize,
unsigned bSize, unsigned resSize,
OperandType resType, Operand* a, Operand* b) = 0;
virtual Operand* f2f(unsigned aSize, unsigned resSize, Operand* a) = 0; virtual Operand* f2f(unsigned aSize, unsigned resSize, Operand* a) = 0;
virtual Operand* f2i(unsigned aSize, unsigned resSize, Operand* a) = 0; virtual Operand* f2i(unsigned aSize, unsigned resSize, Operand* a) = 0;
virtual Operand* i2f(unsigned aSize, unsigned resSize, Operand* a) = 0; virtual Operand* i2f(unsigned aSize, unsigned resSize, Operand* a) = 0;

View File

@ -11,6 +11,7 @@ THUNK(multiplyDouble)
THUNK(divideDouble) THUNK(divideDouble)
THUNK(moduloDouble) THUNK(moduloDouble)
THUNK(negateDouble) THUNK(negateDouble)
THUNK(squareRootDouble)
THUNK(doubleToFloat) THUNK(doubleToFloat)
THUNK(doubleToInt) THUNK(doubleToInt)
THUNK(doubleToLong) THUNK(doubleToLong)
@ -20,6 +21,7 @@ THUNK(multiplyFloat)
THUNK(divideFloat) THUNK(divideFloat)
THUNK(moduloFloat) THUNK(moduloFloat)
THUNK(negateFloat) THUNK(negateFloat)
THUNK(absoluteFloat)
THUNK(divideLong) THUNK(divideLong)
THUNK(moduloLong) THUNK(moduloLong)
THUNK(floatToDouble) THUNK(floatToDouble)

View File

@ -2446,7 +2446,7 @@ floatNegateRR(Context* c, unsigned aSize, Assembler::Register* a,
} }
void void
floatAbsRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a, floatAbsoluteRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a,
unsigned bSize UNUSED, Assembler::Register* b) unsigned bSize UNUSED, Assembler::Register* b)
{ {
assert(c, floatReg(a) and floatReg(b)); assert(c, floatReg(a) and floatReg(b));
@ -2471,7 +2471,7 @@ floatAbsRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a,
} }
void void
absRR(Context* c, unsigned aSize, Assembler::Register* a, absoluteRR(Context* c, unsigned aSize, Assembler::Register* a,
unsigned bSize UNUSED, Assembler::Register* b UNUSED) unsigned bSize UNUSED, Assembler::Register* b UNUSED)
{ {
assert(c, aSize == bSize and a->low == rax and b->low == rax); assert(c, aSize == bSize and a->low == rax and b->low == rax);
@ -2533,8 +2533,8 @@ populateTables(ArchitectureContext* c)
bo[index(c, Move, C, M)] = CAST2(moveCM); bo[index(c, Move, C, M)] = CAST2(moveCM);
bo[index(c, Move, A, R)] = CAST2(moveAR); bo[index(c, Move, A, R)] = CAST2(moveAR);
bo[index(c, FloatSqrt, R, R)] = CAST2(floatSqrtRR); bo[index(c, FloatSquareRoot, R, R)] = CAST2(floatSqrtRR);
bo[index(c, FloatSqrt, M, R)] = CAST2(floatSqrtMR); bo[index(c, FloatSquareRoot, M, R)] = CAST2(floatSqrtMR);
bo[index(c, MoveZ, R, R)] = CAST2(moveZRR); bo[index(c, MoveZ, R, R)] = CAST2(moveZRR);
bo[index(c, MoveZ, M, R)] = CAST2(moveZMR); bo[index(c, MoveZ, M, R)] = CAST2(moveZMR);
@ -2591,8 +2591,8 @@ populateTables(ArchitectureContext* c)
bo[index(c, Int2Float, R, R)] = CAST2(int2FloatRR); bo[index(c, Int2Float, R, R)] = CAST2(int2FloatRR);
bo[index(c, Int2Float, M, R)] = CAST2(int2FloatMR); bo[index(c, Int2Float, M, R)] = CAST2(int2FloatMR);
bo[index(c, Abs, R, R)] = CAST2(absRR); bo[index(c, Absolute, R, R)] = CAST2(absoluteRR);
bo[index(c, FloatAbs, R, R)] = CAST2(floatAbsRR); bo[index(c, FloatAbsolute, R, R)] = CAST2(floatAbsoluteRR);
bro[branchIndex(c, R, R)] = CAST_BRANCH(branchRR); bro[branchIndex(c, R, R)] = CAST_BRANCH(branchRR);
bro[branchIndex(c, C, R)] = CAST_BRANCH(branchCR); bro[branchIndex(c, C, R)] = CAST_BRANCH(branchCR);
@ -2839,13 +2839,13 @@ class MyArchitecture: public Assembler::Architecture {
case Float2Float: case Float2Float:
case Float2Int: case Float2Int:
case Int2Float: case Int2Float:
case FloatAbs: case FloatAbsolute:
case FloatNegate: case FloatNegate:
case FloatSqrt: case FloatSquareRoot:
return false; return false;
case Negate: case Negate:
case Abs: case Absolute:
return true; return true;
default: default:
@ -2892,16 +2892,16 @@ class MyArchitecture: public Assembler::Architecture {
and strcmp(methodName, "sqrt") == 0 and strcmp(methodName, "sqrt") == 0
and strcmp(parameterSpec, "(D)D") == 0) and strcmp(parameterSpec, "(D)D") == 0)
{ {
return FloatSqrt; return FloatSquareRoot;
} else if (strcmp(methodName, "abs")) { } else if (strcmp(methodName, "abs")) {
if (strcmp(parameterSpec, "(I)I") == 0 if (strcmp(parameterSpec, "(I)I") == 0
or strcmp(parameterSpec, "(J)J") == 0) or strcmp(parameterSpec, "(J)J") == 0)
{ {
return Abs; return Absolute;
} else if (useSSE(&c) } else if (useSSE(&c)
and strcmp(parameterSpec, "(F)F") == 0) and strcmp(parameterSpec, "(F)F") == 0)
{ {
return FloatAbs; return FloatAbsolute;
} }
} }
} }
@ -2933,12 +2933,12 @@ class MyArchitecture: public Assembler::Architecture {
| (static_cast<uint64_t>(1) << rax); | (static_cast<uint64_t>(1) << rax);
break; break;
case Abs: case Absolute:
*aTypeMask = (1 << RegisterOperand); *aTypeMask = (1 << RegisterOperand);
*aRegisterMask = (static_cast<uint64_t>(1) << rax); *aRegisterMask = (static_cast<uint64_t>(1) << rax);
break; break;
case FloatAbs: case FloatAbsolute:
*aTypeMask = (1 << RegisterOperand); *aTypeMask = (1 << RegisterOperand);
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32) *aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
| FloatRegisterMask; | FloatRegisterMask;
@ -2954,7 +2954,7 @@ class MyArchitecture: public Assembler::Architecture {
} }
break; break;
case FloatSqrt: case FloatSquareRoot:
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); *aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32) *aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
| FloatRegisterMask; | FloatRegisterMask;
@ -3025,12 +3025,12 @@ class MyArchitecture: public Assembler::Architecture {
| (static_cast<uint64_t>(GeneralRegisterMask) << 32); | (static_cast<uint64_t>(GeneralRegisterMask) << 32);
switch (op) { switch (op) {
case Abs: case Absolute:
*bTypeMask = (1 << RegisterOperand); *bTypeMask = (1 << RegisterOperand);
*bRegisterMask = (static_cast<uint64_t>(1) << rax); *bRegisterMask = (static_cast<uint64_t>(1) << rax);
break; break;
case FloatAbs: case FloatAbsolute:
*bTypeMask = (1 << RegisterOperand); *bTypeMask = (1 << RegisterOperand);
*bRegisterMask = aRegisterMask; *bRegisterMask = aRegisterMask;
break; break;
@ -3041,7 +3041,7 @@ class MyArchitecture: public Assembler::Architecture {
break; break;
case FloatNegate: case FloatNegate:
case FloatSqrt: case FloatSquareRoot:
case Float2Float: case Float2Float:
case Int2Float: case Int2Float:
*bTypeMask = (1 << RegisterOperand); *bTypeMask = (1 << RegisterOperand);