summaryrefslogtreecommitdiffstats
path: root/vm/compiler/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'vm/compiler/codegen')
-rw-r--r--vm/compiler/codegen/x86/LowerAlu.cpp50
1 files changed, 34 insertions, 16 deletions
diff --git a/vm/compiler/codegen/x86/LowerAlu.cpp b/vm/compiler/codegen/x86/LowerAlu.cpp
index 2231baca1..c8c4d66e8 100644
--- a/vm/compiler/codegen/x86/LowerAlu.cpp
+++ b/vm/compiler/codegen/x86/LowerAlu.cpp
@@ -291,56 +291,74 @@ int common_fp_to_long(bool isDouble, u2 vA, u2 vB) {
load_fp_stack_VR(OpndSize_32, vB); //flds
}
- load_fp_stack_global_data_API("valuePosInfLong", OpndSize_64);
+ //Check if it is the special Negative Infinity value
load_fp_stack_global_data_API("valueNegInfLong", OpndSize_64);
-
- //ST(0) ST(1) ST(2) --> LintMin LintMax value
- compare_fp_stack(true, 2, false/*isDouble*/); //ST(2)
- //ST(0) ST(1) --> LintMax value
+ //Stack status: ST(0) ST(1) --> LlongMin value
+ compare_fp_stack(true, 1, false/*isDouble*/); // Pops ST(1)
conditional_jump(Condition_AE, ".float_to_long_negInf", true);
rememberState(1);
- compare_fp_stack(true, 1, false/*isDouble*/); //ST(1)
+
+ //Check if it is the special Positive Infinity value
+ load_fp_stack_global_data_API("valuePosInfLong", OpndSize_64);
+ //Stack status: ST(0) ST(1) --> LlongMax value
+ compare_fp_stack(true, 1, false/*isDouble*/); // Pops ST(1)
rememberState(2);
- //ST(0) --> value
conditional_jump(Condition_C, ".float_to_long_nanInf", true);
- //fnstcw, orw, fldcw, xorw
+
+ //Normal Case
+ //We want to truncate to 0 for conversion. That will be rounding mode 0x11
load_effective_addr(-2, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
store_fpu_cw(false/*checkException*/, 0, PhysicalReg_ESP, true);
+ //Change control word to rounding mode 11:
alu_binary_imm_mem(OpndSize_16, or_opc, 0xc00, 0, PhysicalReg_ESP, true);
+ //Load the control word
load_fpu_cw(0, PhysicalReg_ESP, true);
+ //Reset the control word
alu_binary_imm_mem(OpndSize_16, xor_opc, 0xc00, 0, PhysicalReg_ESP, true);
+ //Perform the actual conversion
store_int_fp_stack_VR(true/*pop*/, OpndSize_64, vA); //fistpll
- //fldcw
+ // Restore the original control word
load_fpu_cw(0, PhysicalReg_ESP, true);
load_effective_addr(2, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
rememberState(3);
+ /* NOTE: We do not need to pop out the original value we pushed
+ * since load_fpu_cw above already clears the stack for
+ * normal values.
+ */
unconditional_jump(".float_to_long_okay", true);
+
+ //We can be here for positive infinity or NaN. Check parity bit
insertLabel(".float_to_long_nanInf", true);
conditional_jump(Condition_NP, ".float_to_long_posInf", true);
- //fstpl??
goToState(2);
-
+ //Save corresponding Long NaN value
load_global_data_API("valueNanLong", OpndSize_64, 1, false);
-
set_virtual_reg(vA, OpndSize_64, 1, false);
transferToState(3);
+ //Pop out the original value we pushed
+ compare_fp_stack(true, 0, false/*isDouble*/); //ST(0)
unconditional_jump(".float_to_long_okay", true);
+
insertLabel(".float_to_long_posInf", true);
- //fstpl
goToState(2);
-
+ //Save corresponding Long Positive Infinity value
load_global_data_API("valuePosInfLong", OpndSize_64, 2, false);
set_virtual_reg(vA, OpndSize_64, 2, false);
transferToState(3);
+ //Pop out the original value we pushed
+ compare_fp_stack(true, 0, false/*isDouble*/); //ST(0)
unconditional_jump(".float_to_long_okay", true);
+
insertLabel(".float_to_long_negInf", true);
//fstpl
- //fstpl
goToState(1);
-
+ //Load corresponding Long Negative Infinity value
load_global_data_API("valueNegInfLong", OpndSize_64, 3, false);
set_virtual_reg(vA, OpndSize_64, 3, false);
transferToState(3);
+ //Pop out the original value we pushed
+ compare_fp_stack(true, 0, false/*isDouble*/); //ST(0)
+
insertLabel(".float_to_long_okay", true);
return 0;
}