summaryrefslogtreecommitdiffstats
path: root/vm/compiler/codegen
diff options
context:
space:
mode:
authorUdayan Banerji <udayan.banerji@intel.com>2013-04-01 14:27:09 -0700
committerElliott Hughes <enh@google.com>2013-04-01 14:39:34 -0700
commit05d4f7c4a9e0604a247954220363e28cc92c382d (patch)
tree94d89a258ac165268cde7519d702de91d6182d55 /vm/compiler/codegen
parentddff71d449765984d1cae6b6e8191fa9956d135b (diff)
downloadandroid_dalvik-05d4f7c4a9e0604a247954220363e28cc92c382d.tar.gz
android_dalvik-05d4f7c4a9e0604a247954220363e28cc92c382d.tar.bz2
android_dalvik-05d4f7c4a9e0604a247954220363e28cc92c382d.zip
[x86] FPU stack needs to be reset after double conversion
The x86 codegen uses the FPU stack for double/float to long conversions. We need to clear out the FPU stack after done, to prevent an eventual stack overflow. Change-Id: I2f306d7c228ad3da2b84faf9f08326769a9417af Signed-off-by: Udayan Banerji <udayan.banerji@intel.com>
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;
}