diff options
author | Udayan Banerji <udayan.banerji@intel.com> | 2013-04-01 14:27:09 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2013-04-01 14:39:34 -0700 |
commit | 05d4f7c4a9e0604a247954220363e28cc92c382d (patch) | |
tree | 94d89a258ac165268cde7519d702de91d6182d55 /vm/compiler/codegen | |
parent | ddff71d449765984d1cae6b6e8191fa9956d135b (diff) | |
download | android_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.cpp | 50 |
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; } |