Sat, 06 Nov 2010 18:52:07 -0700
6997311: SIGFPE in new long division asm code
Summary: use unsigned DIV instruction
Reviewed-by: never
1.1 --- a/src/cpu/x86/vm/assembler_x86.cpp Sat Nov 06 02:53:59 2010 -0700 1.2 +++ b/src/cpu/x86/vm/assembler_x86.cpp Sat Nov 06 18:52:07 2010 -0700 1.3 @@ -1275,6 +1275,12 @@ 1.4 emit_byte(0xF8 | encode); 1.5 } 1.6 1.7 +void Assembler::divl(Register src) { // Unsigned 1.8 + int encode = prefix_and_encode(src->encoding()); 1.9 + emit_byte(0xF7); 1.10 + emit_byte(0xF0 | encode); 1.11 +} 1.12 + 1.13 void Assembler::imull(Register dst, Register src) { 1.14 int encode = prefix_and_encode(dst->encoding(), src->encoding()); 1.15 emit_byte(0x0F);
2.1 --- a/src/cpu/x86/vm/assembler_x86.hpp Sat Nov 06 02:53:59 2010 -0700 2.2 +++ b/src/cpu/x86/vm/assembler_x86.hpp Sat Nov 06 18:52:07 2010 -0700 2.3 @@ -1011,6 +1011,7 @@ 2.4 void hlt(); 2.5 2.6 void idivl(Register src); 2.7 + void divl(Register src); // Unsigned division 2.8 2.9 void idivq(Register src); 2.10
3.1 --- a/src/cpu/x86/vm/x86_32.ad Sat Nov 06 02:53:59 2010 -0700 3.2 +++ b/src/cpu/x86/vm/x86_32.ad Sat Nov 06 18:52:07 2010 -0700 3.3 @@ -8863,48 +8863,64 @@ 3.4 effect( TEMP tmp, TEMP tmp2, KILL cr ); 3.5 ins_cost(1000); 3.6 format %{ "MOV $tmp,abs($imm) # ldiv EDX:EAX,$imm\n\t" 3.7 + "XOR $tmp2,$tmp2\n\t" 3.8 "CMP $tmp,EDX\n\t" 3.9 "JA,s fast\n\t" 3.10 "MOV $tmp2,EAX\n\t" 3.11 "MOV EAX,EDX\n\t" 3.12 - "SAR EDX,31\n\t" 3.13 - "IDIV $tmp\n\t" 3.14 - "XCHG EAX,$tmp2 \n\t" 3.15 - "IDIV $tmp\n\t" 3.16 - "CDQ\n\t" 3.17 - "ADD EDX,$tmp2\n\t" 3.18 + "MOV EDX,0\n\t" 3.19 + "JLE,s pos\n\t" 3.20 + "LNEG EAX : $tmp2\n\t" 3.21 + "DIV $tmp # unsigned division\n\t" 3.22 + "XCHG EAX,$tmp2\n\t" 3.23 + "DIV $tmp\n\t" 3.24 + "LNEG $tmp2 : EAX\n\t" 3.25 "JMP,s done\n" 3.26 + "pos:\n\t" 3.27 + "DIV $tmp\n\t" 3.28 + "XCHG EAX,$tmp2\n" 3.29 "fast:\n\t" 3.30 - "IDIV $tmp\n\t" 3.31 - "XOR EDX,EDX\n" 3.32 + "DIV $tmp\n" 3.33 "done:\n\t" 3.34 + "MOV EDX,$tmp2\n\t" 3.35 "NEG EDX:EAX # if $imm < 0" %} 3.36 ins_encode %{ 3.37 int con = (int)$imm$$constant; 3.38 assert(con != 0 && con != -1 && con != min_jint, "wrong divisor"); 3.39 int pcon = (con > 0) ? con : -con; 3.40 - Label Lfast, Ldone; 3.41 + Label Lfast, Lpos, Ldone; 3.42 3.43 __ movl($tmp$$Register, pcon); 3.44 + __ xorl($tmp2$$Register,$tmp2$$Register); 3.45 __ cmpl($tmp$$Register, HIGH_FROM_LOW($dst$$Register)); 3.46 - __ jccb(Assembler::above, Lfast); 3.47 + __ jccb(Assembler::above, Lfast); // result fits into 32 bit 3.48 3.49 __ movl($tmp2$$Register, $dst$$Register); // save 3.50 __ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register)); 3.51 - __ sarl(HIGH_FROM_LOW($dst$$Register), 31); // src sign 3.52 - __ idivl($tmp$$Register); 3.53 + __ movl(HIGH_FROM_LOW($dst$$Register),0); // preserve flags 3.54 + __ jccb(Assembler::lessEqual, Lpos); // result is positive 3.55 + 3.56 + // Negative dividend. 3.57 + // convert value to positive to use unsigned division 3.58 + __ lneg($dst$$Register, $tmp2$$Register); 3.59 + __ divl($tmp$$Register); 3.60 __ xchgl($dst$$Register, $tmp2$$Register); 3.61 - __ idivl($tmp$$Register); 3.62 - __ cdql(); 3.63 - __ addl(HIGH_FROM_LOW($dst$$Register),$tmp2$$Register); 3.64 + __ divl($tmp$$Register); 3.65 + // revert result back to negative 3.66 + __ lneg($tmp2$$Register, $dst$$Register); 3.67 __ jmpb(Ldone); 3.68 3.69 + __ bind(Lpos); 3.70 + __ divl($tmp$$Register); // Use unsigned division 3.71 + __ xchgl($dst$$Register, $tmp2$$Register); 3.72 + // Fallthrow for final divide, tmp2 has 32 bit hi result 3.73 + 3.74 __ bind(Lfast); 3.75 - // fast path: src is positive and result fits into 32 bit 3.76 - __ idivl($tmp$$Register); 3.77 - __ xorl(HIGH_FROM_LOW($dst$$Register),HIGH_FROM_LOW($dst$$Register)); 3.78 + // fast path: src is positive 3.79 + __ divl($tmp$$Register); // Use unsigned division 3.80 3.81 __ bind(Ldone); 3.82 + __ movl(HIGH_FROM_LOW($dst$$Register),$tmp2$$Register); 3.83 if (con < 0) { 3.84 __ lneg(HIGH_FROM_LOW($dst$$Register), $dst$$Register); 3.85 } 3.86 @@ -8922,18 +8938,27 @@ 3.87 "JA,s fast\n\t" 3.88 "MOV $tmp2,EAX\n\t" 3.89 "MOV EAX,EDX\n\t" 3.90 - "SAR EDX,31\n\t" 3.91 - "IDIV $tmp\n\t" 3.92 + "MOV EDX,0\n\t" 3.93 + "JLE,s pos\n\t" 3.94 + "LNEG EAX : $tmp2\n\t" 3.95 + "DIV $tmp # unsigned division\n\t" 3.96 + "MOV EAX,$tmp2\n\t" 3.97 + "DIV $tmp\n\t" 3.98 + "NEG EDX\n\t" 3.99 + "JMP,s done\n" 3.100 + "pos:\n\t" 3.101 + "DIV $tmp\n\t" 3.102 "MOV EAX,$tmp2\n" 3.103 "fast:\n\t" 3.104 - "IDIV $tmp\n\t" 3.105 + "DIV $tmp\n" 3.106 + "done:\n\t" 3.107 "MOV EAX,EDX\n\t" 3.108 "SAR EDX,31\n\t" %} 3.109 ins_encode %{ 3.110 int con = (int)$imm$$constant; 3.111 assert(con != 0 && con != -1 && con != min_jint, "wrong divisor"); 3.112 int pcon = (con > 0) ? con : -con; 3.113 - Label Lfast; 3.114 + Label Lfast, Lpos, Ldone; 3.115 3.116 __ movl($tmp$$Register, pcon); 3.117 __ cmpl($tmp$$Register, HIGH_FROM_LOW($dst$$Register)); 3.118 @@ -8941,12 +8966,28 @@ 3.119 3.120 __ movl($tmp2$$Register, $dst$$Register); // save 3.121 __ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register)); 3.122 - __ sarl(HIGH_FROM_LOW($dst$$Register), 31); // src sign 3.123 - __ idivl($tmp$$Register); 3.124 + __ movl(HIGH_FROM_LOW($dst$$Register),0); // preserve flags 3.125 + __ jccb(Assembler::lessEqual, Lpos); // result is positive 3.126 + 3.127 + // Negative dividend. 3.128 + // convert value to positive to use unsigned division 3.129 + __ lneg($dst$$Register, $tmp2$$Register); 3.130 + __ divl($tmp$$Register); 3.131 __ movl($dst$$Register, $tmp2$$Register); 3.132 + __ divl($tmp$$Register); 3.133 + // revert remainder back to negative 3.134 + __ negl(HIGH_FROM_LOW($dst$$Register)); 3.135 + __ jmpb(Ldone); 3.136 + 3.137 + __ bind(Lpos); 3.138 + __ divl($tmp$$Register); 3.139 + __ movl($dst$$Register, $tmp2$$Register); 3.140 3.141 __ bind(Lfast); 3.142 - __ idivl($tmp$$Register); 3.143 + // fast path: src is positive 3.144 + __ divl($tmp$$Register); 3.145 + 3.146 + __ bind(Ldone); 3.147 __ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register)); 3.148 __ sarl(HIGH_FROM_LOW($dst$$Register), 31); // result sign 3.149
4.1 --- a/test/compiler/6603011/Test.java Sat Nov 06 02:53:59 2010 -0700 4.2 +++ b/test/compiler/6603011/Test.java Sat Nov 06 18:52:07 2010 -0700 4.3 @@ -1,5 +1,5 @@ 4.4 /* 4.5 - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. 4.6 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 4.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.8 * 4.9 * This code is free software; you can redistribute it and/or modify it 4.10 @@ -108,8 +108,10 @@ 4.11 4.12 if (quo != quo0 || rem != rem0) { 4.13 if (VERBOSE) { 4.14 - System.out.println(" " + dividend + " / " + divisor() + " = " + 4.15 - quo + ", " + dividend + " % " + divisor() + " = " + rem); 4.16 + System.out.println("Computed: " + dividend + " / " + divisor() + " = " + 4.17 + quo + ", " + dividend + " % " + divisor() + " = " + rem ); 4.18 + System.out.println("expected: " + dividend + " / " + divisor() + " = " + 4.19 + quo0 + ", " + dividend + " % " + divisor() + " = " + rem0); 4.20 // Report sign of rem failure 4.21 if (rem != 0 && (rem ^ dividend) < 0) { 4.22 System.out.println(" rem & dividend have different signs"); 4.23 @@ -168,7 +170,7 @@ 4.24 for (int i = start; i <= end; i++) { 4.25 for (int s = 0; s < 64; s += 4) { 4.26 total++; 4.27 - long dividend = i << s; 4.28 + long dividend = ((long)i) << s; 4.29 if (!checkL(dividend)) { 4.30 wrong++; 4.31 // Stop on the first failure