Skip to content

Commit

Permalink
Java implementation of 64bit ldiv and lrem bytecodes for 32bit archit…
Browse files Browse the repository at this point in the history
…ectures.
  • Loading branch information
Ian Rogers committed Apr 6, 2009
1 parent dd51336 commit d69b02b
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1164,38 +1164,10 @@ protected final void emit_ldiv() {
asm.emitIDIV_Reg_Reg_Quad(EAX, ECX);
asm.emitPUSH_Reg(EAX); // push result
} else {
// (1) zero check
asm.emitMOV_Reg_RegInd(T0, SP);
asm.emitOR_Reg_RegDisp(T0, SP, ONE_SLOT);
asm.emitBranchLikelyNextInstruction();
ForwardReference fr1 = asm.forwardJcc(Assembler.NE);
asm.emitINT_Imm(RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO + RVM_TRAP_BASE); // trap if divisor is 0
fr1.resolve(asm);
// (2) save RVM nonvolatiles
int numNonVols = NONVOLATILE_GPRS.length;
Offset off = Offset.fromIntSignExtend(numNonVols * WORDSIZE);
for (int i = 0; i < numNonVols; i++) {
asm.emitPUSH_Reg(NONVOLATILE_GPRS[i]);
}
// (3) Push args to C function (reversed)
asm.emitPUSH_RegDisp(SP, off.plus(4));
asm.emitPUSH_RegDisp(SP, off.plus(4));
asm.emitPUSH_RegDisp(SP, off.plus(20));
asm.emitPUSH_RegDisp(SP, off.plus(20));
// (4) invoke C function through bootrecord
asm.emitMOV_Reg_Abs(S0, Magic.getTocPointer().plus(Entrypoints.the_boot_recordField.getOffset()));
asm.emitCALL_RegDisp(S0, Entrypoints.sysLongDivideIPField.getOffset());
// (5) pop space for arguments
adjustStack(4 * WORDSIZE, true);
// (6) restore RVM nonvolatiles
for (int i = numNonVols - 1; i >= 0; i--) {
asm.emitPOP_Reg(NONVOLATILE_GPRS[i]);
}
// (7) pop expression stack
adjustStack(WORDSIZE*4, true);
// (8) push results
asm.emitPUSH_Reg(T1);
asm.emitPUSH_Reg(T0);
genParameterRegisterLoad(asm, 4); // pass 4 parameter words
asm.emitCALL_Abs(Magic.getTocPointer().plus(Entrypoints.ldivMethod.getOffset()));
asm.emitPUSH_Reg(T0); // high half
asm.emitPUSH_Reg(T1); // low half
}
}

Expand All @@ -1212,38 +1184,10 @@ protected final void emit_lrem() {
asm.emitIDIV_Reg_Reg_Quad(EAX, ECX);
asm.emitPUSH_Reg(EDX); // push result
} else {
// (1) zero check
asm.emitMOV_Reg_RegInd(T0, SP);
asm.emitOR_Reg_RegDisp(T0, SP, ONE_SLOT);
asm.emitBranchLikelyNextInstruction();
ForwardReference fr1 = asm.forwardJcc(Assembler.NE);
asm.emitINT_Imm(RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO + RVM_TRAP_BASE); // trap if divisor is 0
fr1.resolve(asm);
// (2) save RVM nonvolatiles
int numNonVols = NONVOLATILE_GPRS.length;
Offset off = Offset.fromIntSignExtend(numNonVols * WORDSIZE);
for (int i = 0; i < numNonVols; i++) {
asm.emitPUSH_Reg(NONVOLATILE_GPRS[i]);
}
// (3) Push args to C function (reversed)
asm.emitPUSH_RegDisp(SP, off.plus(4));
asm.emitPUSH_RegDisp(SP, off.plus(4));
asm.emitPUSH_RegDisp(SP, off.plus(20));
asm.emitPUSH_RegDisp(SP, off.plus(20));
// (4) invoke C function through bootrecord
asm.emitMOV_Reg_Abs(S0, Magic.getTocPointer().plus(Entrypoints.the_boot_recordField.getOffset()));
asm.emitCALL_RegDisp(S0, Entrypoints.sysLongRemainderIPField.getOffset());
// (5) pop space for arguments
adjustStack(4 * WORDSIZE, true);
// (6) restore RVM nonvolatiles
for (int i = numNonVols - 1; i >= 0; i--) {
asm.emitPOP_Reg(NONVOLATILE_GPRS[i]);
}
// (7) pop expression stack
adjustStack(WORDSIZE*4, true);
// (8) push results
asm.emitPUSH_Reg(T1);
asm.emitPUSH_Reg(T0);
genParameterRegisterLoad(asm, 4); // pass 4 parameter words
asm.emitCALL_Abs(Magic.getTocPointer().plus(Entrypoints.lremMethod.getOffset()));
asm.emitPUSH_Reg(T0); // high half
asm.emitPUSH_Reg(T1); // low half
}
}

Expand Down
44 changes: 44 additions & 0 deletions rvm/src/org/jikesrvm/compilers/baseline/ia32/BaselineMagic.java
Original file line number Diff line number Diff line change
Expand Up @@ -2058,6 +2058,50 @@ void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
generators.put(getMethodReference(Magic.class, MagicNames.pause, void.class), g);
}

/**
* Signed long divide by 32bit divisor giving 32bit quotient
*/
private static final class SignedDivide extends MagicGenerator {
@Override
void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
// stack: value1.high = divident
// value1.low
// value2 = divisor <-- ESP
if (VM.VerifyAssertions) VM._assert(S0 != EAX && S0 != EDX);
asm.emitPOP_Reg(S0);
asm.emitPOP_Reg(EAX);
asm.emitPOP_Reg(EDX);
asm.emitIDIV_Reg_Reg(EAX, S0);
asm.emitPUSH_Reg(EAX);
}
}
static {
MagicGenerator g = new SignedDivide();
generators.put(getMethodReference(Magic.class, MagicNames.signedDivide, long.class, int.class, int.class), g);
}

/**
* Unsigned long divide by 32bit divisor giving 32bit quotient
*/
private static final class UnsignedDivide extends MagicGenerator {
@Override
void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
// stack: value1.high = divident
// value1.low
// value2 = divisor <-- ESP
if (VM.VerifyAssertions) VM._assert(S0 != EAX && S0 != EDX);
asm.emitPOP_Reg(S0);
asm.emitPOP_Reg(EAX);
asm.emitPOP_Reg(EDX);
asm.emitDIV_Reg_Reg(EAX, S0);
asm.emitPUSH_Reg(EAX);
}
}
static {
MagicGenerator g = new UnsignedDivide();
generators.put(getMethodReference(Magic.class, MagicNames.unsignedDivide, long.class, int.class, int.class), g);
}

/**
* Floating point square root
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import static org.jikesrvm.compilers.opt.ir.Operators.GETFIELD_opcode;
import static org.jikesrvm.compilers.opt.ir.Operators.GETSTATIC_opcode;
import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE;
import static org.jikesrvm.compilers.opt.ir.Operators.LONG_DIV_opcode;
import static org.jikesrvm.compilers.opt.ir.Operators.LONG_REM_opcode;
import static org.jikesrvm.compilers.opt.ir.Operators.MONITORENTER_opcode;
import static org.jikesrvm.compilers.opt.ir.Operators.MONITOREXIT_opcode;
import static org.jikesrvm.compilers.opt.ir.Operators.NEWARRAY_UNRESOLVED_opcode;
Expand Down Expand Up @@ -54,6 +56,7 @@
import org.jikesrvm.compilers.opt.ir.Call;
import org.jikesrvm.compilers.opt.ir.GetField;
import org.jikesrvm.compilers.opt.ir.GetStatic;
import org.jikesrvm.compilers.opt.ir.GuardedBinary;
import org.jikesrvm.compilers.opt.ir.IR;
import org.jikesrvm.compilers.opt.ir.IRTools;
import org.jikesrvm.compilers.opt.ir.Instruction;
Expand Down Expand Up @@ -138,6 +141,35 @@ public void perform(IR ir) {
int opcode = inst.getOpcode();

switch (opcode) {
case LONG_DIV_opcode: {
if (VM.BuildFor64Addr) break; // don't reduce operator
RVMMethod target = Entrypoints.ldivMethod;
Call.mutate2(inst,
CALL,
GuardedBinary.getClearResult(inst),
IRTools.AC(target.getOffset()),
MethodOperand.STATIC(target),
GuardedBinary.getClearVal1(inst),
GuardedBinary.getClearVal2(inst));
if (!ir.options.FREQ_FOCUS_EFFORT || !inst.getBasicBlock().getInfrequent()) {
inline(inst, ir);
}
}

case LONG_REM_opcode: {
if (VM.BuildFor64Addr) break; // don't reduce operator
RVMMethod target = Entrypoints.lremMethod;
Call.mutate2(inst,
CALL,
GuardedBinary.getClearResult(inst),
IRTools.AC(target.getOffset()),
MethodOperand.STATIC(target),
GuardedBinary.getClearVal1(inst),
GuardedBinary.getClearVal2(inst));
if (!ir.options.FREQ_FOCUS_EFFORT || !inst.getBasicBlock().getInfrequent()) {
inline(inst, ir);
}
}

case NEW_opcode: {
TypeOperand Type = New.getClearType(inst);
Expand Down
28 changes: 0 additions & 28 deletions rvm/src/org/jikesrvm/compilers/opt/lir2mir/ConvertLIRtoMIR.java
Original file line number Diff line number Diff line change
Expand Up @@ -216,34 +216,6 @@ public void perform(IR ir) {
}
break;

case LONG_DIV_opcode: {
if (VM.BuildForPowerPC && VM.BuildFor64Addr) break; // don't reduce operator -- leave for BURS
Call.mutate2(s,
SYSCALL,
GuardedBinary.getClearResult(s),
null,
MethodOperand.STATIC(Entrypoints.sysLongDivideIPField),
GuardedBinary.getClearVal1(s),
GuardedBinary.getClearVal2(s));
ConvertToLowLevelIR.expandSysCallTarget(s, ir);
CallingConvention.expandSysCall(s, ir);
}
break;

case LONG_REM_opcode: {
if (VM.BuildForPowerPC && VM.BuildFor64Addr) break; // don't reduce operator -- leave for BURS
Call.mutate2(s,
SYSCALL,
GuardedBinary.getClearResult(s),
null,
MethodOperand.STATIC(Entrypoints.sysLongRemainderIPField),
GuardedBinary.getClearVal1(s),
GuardedBinary.getClearVal2(s));
ConvertToLowLevelIR.expandSysCallTarget(s, ir);
CallingConvention.expandSysCall(s, ir);
}
break;

case FLOAT_REM_opcode:
case DOUBLE_REM_opcode: {
if (VM.BuildForPowerPC) {
Expand Down
4 changes: 0 additions & 4 deletions rvm/src/org/jikesrvm/runtime/BootRecord.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,6 @@ public void setHeapRange(int id, Address start, Address end) {

// arithmetic
@Entrypoint
public Address sysLongDivideIP;
@Entrypoint
public Address sysLongRemainderIP;
@Entrypoint
public Address sysLongToFloatIP;
@Entrypoint
public Address sysLongToDoubleIP;
Expand Down
9 changes: 5 additions & 4 deletions rvm/src/org/jikesrvm/runtime/Entrypoints.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ public class Entrypoints {
"objectAddressRemapper",
org.jikesrvm.runtime.ObjectAddressRemapper.class);

public static final NormalMethod ldivMethod =
getMethod(org.jikesrvm.runtime.RuntimeEntrypoints.class, "ldiv", "(JJ)J");
public static final NormalMethod lremMethod =
getMethod(org.jikesrvm.runtime.RuntimeEntrypoints.class, "lrem", "(JJ)J");

public static final NormalMethod instanceOfMethod =
getMethod(org.jikesrvm.runtime.RuntimeEntrypoints.class, "instanceOf", "(Ljava/lang/Object;I)Z");
public static final NormalMethod checkcastMethod =
Expand Down Expand Up @@ -331,10 +336,6 @@ public class Entrypoints {
getField(org.jikesrvm.runtime.BootRecord.class, "the_boot_record", org.jikesrvm.runtime.BootRecord.class);
public static final RVMField externalSignalFlagField =
getField(org.jikesrvm.runtime.BootRecord.class, "externalSignalFlag", int.class);
public static final RVMField sysLongDivideIPField =
getField(org.jikesrvm.runtime.BootRecord.class, "sysLongDivideIP", org.vmmagic.unboxed.Address.class);
public static final RVMField sysLongRemainderIPField =
getField(org.jikesrvm.runtime.BootRecord.class, "sysLongRemainderIP", org.vmmagic.unboxed.Address.class);
public static final RVMField sysLongToFloatIPField =
getField(org.jikesrvm.runtime.BootRecord.class, "sysLongToFloatIP", org.vmmagic.unboxed.Address.class);
public static final RVMField sysLongToDoubleIPField =
Expand Down
20 changes: 20 additions & 0 deletions rvm/src/org/jikesrvm/runtime/Magic.java
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,26 @@ public static void pause() {
}
}

/**
* A hardware signed long divide by 32bit divisor giving 32bit quotient
*/
public static int signedDivide(long u, int v) {
if (VM.runningVM && VM.VerifyAssertions) {
VM._assert(VM.NOT_REACHED); // call site should have been hijacked by magic in compiler
}
return 0;
}

/**
* A hardware unsigned long divide by 32bit divisor giving 32bit quotient
*/
public static int unsignedDivide(long u, int v) {
if (VM.runningVM && VM.VerifyAssertions) {
VM._assert(VM.NOT_REACHED); // call site should have been hijacked by magic in compiler
}
return 0;
}

/**
* A hardware SQRT instruction
*/
Expand Down
2 changes: 2 additions & 0 deletions rvm/src/org/jikesrvm/runtime/MagicNames.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public class MagicNames {
public static final Atom loadObjectReference = Atom.findOrCreateAsciiAtom("loadObjectReference");
public static final Atom store = Atom.findOrCreateAsciiAtom("store");
public static final Atom pause = Atom.findOrCreateAsciiAtom("pause");
public static final Atom signedDivide = Atom.findOrCreateAsciiAtom("signedDivide");
public static final Atom unsignedDivide = Atom.findOrCreateAsciiAtom("unsignedDivide");
public static final Atom sqrt = Atom.findOrCreateAsciiAtom("sqrt");

public static final Atom getUnsignedByteAtOffset = Atom.findOrCreateAsciiAtom("getUnsignedByteAtOffset");
Expand Down
74 changes: 74 additions & 0 deletions rvm/src/org/jikesrvm/runtime/RuntimeEntrypoints.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,80 @@ public class RuntimeEntrypoints implements Constants, ArchitectureSpecific.Stack
public static final int TRAP_STORE_CHECK = 8; // opt-compiler
public static final int TRAP_STACK_OVERFLOW_FATAL = 9; // assertion checking

/**
* Perform signed division implementing the ldiv bytecode
*
* @param u dividend
* @param v divisor
* @return quotient
*/
@Entrypoint
static long ldiv(long u, long v) {
if (v == 0) {
raiseArithmeticException();
}
long au = Math.abs(u);
long av = Math.abs(v);
if ((av >>> 31) == 0) {
if (au < (av << 31)) {
long q = Magic.signedDivide(u, (int)v);
return (q << 32) >> 32;
}
}
long q = unsignedDivide(au, av);
long t = (u ^ v) >> 63;
return (q ^ t) - t;
}

/**
* Perform the unsigned division subcase of the ldiv bytecode
*
* @param u dividend
* @param v divisor
* @return quotient
*/
private static long unsignedDivide(long u, long v) {
if ((v >>> 32) == 0) {
if ((u >>> 32) < v) {
return Magic.unsignedDivide(u, (int)v) & 0xFFFFFFFF;
} else {
long u1 = u >>> 32;
long u0 = u & 0xFFFFFFFF;
long q1 = Magic.unsignedDivide(u1, (int)v) & 0xFFFFFFFF;
long k = u1 - q1 * v;
long q0 = Magic.unsignedDivide((k << 32) + u0, (int)v) & 0xFFFFFFFF;
return (q1 << 32) + q0;
}
} else {
int n = Long.numberOfLeadingZeros(v);
long v1 = (v << n) >>> 32;
long u1 = u >>> 1;
long q1 = Magic.unsignedDivide(u1, (int)v1) & 0xFFFFFFFF;
long q0 = (q1 << n) >>> 31;
if (q0 != 0) {
q0 = q0-1;
}
if ((u - q0*v) >= v) {
q0 = q0+1;
}
return q0;
}
}

/**
* Perform signed remainder implementing the lrem bytecode
*
* @param u dividend
* @param v divisor
* @return remainder
*/
@Entrypoint
static long lrem(long u, long v) {
// @TODO: optimize this further
long r = ldiv(u, v);
return u - (r * v);
}

//---------------------------------------------------------------//
// Type Checking. //
//---------------------------------------------------------------//
Expand Down
6 changes: 0 additions & 6 deletions rvm/src/org/jikesrvm/runtime/SysCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,6 @@ public abstract class SysCall {
public abstract void sysMonitorNotifyAll(Address monitor);

// arithmetic
@SysCallTemplate
public abstract long sysLongDivide(long x, long y);

@SysCallTemplate
public abstract long sysLongRemainder(long x, long y);

@SysCallTemplate
public abstract float sysLongToFloat(long x);

Expand Down

0 comments on commit d69b02b

Please sign in to comment.