提交 bc08383d 编写于 作者: K kvn

6997311: SIGFPE in new long division asm code

Summary: use unsigned DIV instruction
Reviewed-by: never
上级 99a453d9
...@@ -1275,6 +1275,12 @@ void Assembler::idivl(Register src) { ...@@ -1275,6 +1275,12 @@ void Assembler::idivl(Register src) {
emit_byte(0xF8 | encode); emit_byte(0xF8 | encode);
} }
void Assembler::divl(Register src) { // Unsigned
int encode = prefix_and_encode(src->encoding());
emit_byte(0xF7);
emit_byte(0xF0 | encode);
}
void Assembler::imull(Register dst, Register src) { void Assembler::imull(Register dst, Register src) {
int encode = prefix_and_encode(dst->encoding(), src->encoding()); int encode = prefix_and_encode(dst->encoding(), src->encoding());
emit_byte(0x0F); emit_byte(0x0F);
......
...@@ -1011,6 +1011,7 @@ private: ...@@ -1011,6 +1011,7 @@ private:
void hlt(); void hlt();
void idivl(Register src); void idivl(Register src);
void divl(Register src); // Unsigned division
void idivq(Register src); void idivq(Register src);
......
...@@ -8863,48 +8863,64 @@ instruct divL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlag ...@@ -8863,48 +8863,64 @@ instruct divL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlag
effect( TEMP tmp, TEMP tmp2, KILL cr ); effect( TEMP tmp, TEMP tmp2, KILL cr );
ins_cost(1000); ins_cost(1000);
format %{ "MOV $tmp,abs($imm) # ldiv EDX:EAX,$imm\n\t" format %{ "MOV $tmp,abs($imm) # ldiv EDX:EAX,$imm\n\t"
"XOR $tmp2,$tmp2\n\t"
"CMP $tmp,EDX\n\t" "CMP $tmp,EDX\n\t"
"JA,s fast\n\t" "JA,s fast\n\t"
"MOV $tmp2,EAX\n\t" "MOV $tmp2,EAX\n\t"
"MOV EAX,EDX\n\t" "MOV EAX,EDX\n\t"
"SAR EDX,31\n\t" "MOV EDX,0\n\t"
"IDIV $tmp\n\t" "JLE,s pos\n\t"
"XCHG EAX,$tmp2 \n\t" "LNEG EAX : $tmp2\n\t"
"IDIV $tmp\n\t" "DIV $tmp # unsigned division\n\t"
"CDQ\n\t" "XCHG EAX,$tmp2\n\t"
"ADD EDX,$tmp2\n\t" "DIV $tmp\n\t"
"LNEG $tmp2 : EAX\n\t"
"JMP,s done\n" "JMP,s done\n"
"pos:\n\t"
"DIV $tmp\n\t"
"XCHG EAX,$tmp2\n"
"fast:\n\t" "fast:\n\t"
"IDIV $tmp\n\t" "DIV $tmp\n"
"XOR EDX,EDX\n"
"done:\n\t" "done:\n\t"
"MOV EDX,$tmp2\n\t"
"NEG EDX:EAX # if $imm < 0" %} "NEG EDX:EAX # if $imm < 0" %}
ins_encode %{ ins_encode %{
int con = (int)$imm$$constant; int con = (int)$imm$$constant;
assert(con != 0 && con != -1 && con != min_jint, "wrong divisor"); assert(con != 0 && con != -1 && con != min_jint, "wrong divisor");
int pcon = (con > 0) ? con : -con; int pcon = (con > 0) ? con : -con;
Label Lfast, Ldone; Label Lfast, Lpos, Ldone;
__ movl($tmp$$Register, pcon); __ movl($tmp$$Register, pcon);
__ xorl($tmp2$$Register,$tmp2$$Register);
__ cmpl($tmp$$Register, HIGH_FROM_LOW($dst$$Register)); __ cmpl($tmp$$Register, HIGH_FROM_LOW($dst$$Register));
__ jccb(Assembler::above, Lfast); __ jccb(Assembler::above, Lfast); // result fits into 32 bit
__ movl($tmp2$$Register, $dst$$Register); // save __ movl($tmp2$$Register, $dst$$Register); // save
__ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register)); __ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register));
__ sarl(HIGH_FROM_LOW($dst$$Register), 31); // src sign __ movl(HIGH_FROM_LOW($dst$$Register),0); // preserve flags
__ idivl($tmp$$Register); __ jccb(Assembler::lessEqual, Lpos); // result is positive
// Negative dividend.
// convert value to positive to use unsigned division
__ lneg($dst$$Register, $tmp2$$Register);
__ divl($tmp$$Register);
__ xchgl($dst$$Register, $tmp2$$Register); __ xchgl($dst$$Register, $tmp2$$Register);
__ idivl($tmp$$Register); __ divl($tmp$$Register);
__ cdql(); // revert result back to negative
__ addl(HIGH_FROM_LOW($dst$$Register),$tmp2$$Register); __ lneg($tmp2$$Register, $dst$$Register);
__ jmpb(Ldone); __ jmpb(Ldone);
__ bind(Lpos);
__ divl($tmp$$Register); // Use unsigned division
__ xchgl($dst$$Register, $tmp2$$Register);
// Fallthrow for final divide, tmp2 has 32 bit hi result
__ bind(Lfast); __ bind(Lfast);
// fast path: src is positive and result fits into 32 bit // fast path: src is positive
__ idivl($tmp$$Register); __ divl($tmp$$Register); // Use unsigned division
__ xorl(HIGH_FROM_LOW($dst$$Register),HIGH_FROM_LOW($dst$$Register));
__ bind(Ldone); __ bind(Ldone);
__ movl(HIGH_FROM_LOW($dst$$Register),$tmp2$$Register);
if (con < 0) { if (con < 0) {
__ lneg(HIGH_FROM_LOW($dst$$Register), $dst$$Register); __ lneg(HIGH_FROM_LOW($dst$$Register), $dst$$Register);
} }
...@@ -8922,18 +8938,27 @@ instruct modL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlag ...@@ -8922,18 +8938,27 @@ instruct modL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlag
"JA,s fast\n\t" "JA,s fast\n\t"
"MOV $tmp2,EAX\n\t" "MOV $tmp2,EAX\n\t"
"MOV EAX,EDX\n\t" "MOV EAX,EDX\n\t"
"SAR EDX,31\n\t" "MOV EDX,0\n\t"
"IDIV $tmp\n\t" "JLE,s pos\n\t"
"LNEG EAX : $tmp2\n\t"
"DIV $tmp # unsigned division\n\t"
"MOV EAX,$tmp2\n\t"
"DIV $tmp\n\t"
"NEG EDX\n\t"
"JMP,s done\n"
"pos:\n\t"
"DIV $tmp\n\t"
"MOV EAX,$tmp2\n" "MOV EAX,$tmp2\n"
"fast:\n\t" "fast:\n\t"
"IDIV $tmp\n\t" "DIV $tmp\n"
"done:\n\t"
"MOV EAX,EDX\n\t" "MOV EAX,EDX\n\t"
"SAR EDX,31\n\t" %} "SAR EDX,31\n\t" %}
ins_encode %{ ins_encode %{
int con = (int)$imm$$constant; int con = (int)$imm$$constant;
assert(con != 0 && con != -1 && con != min_jint, "wrong divisor"); assert(con != 0 && con != -1 && con != min_jint, "wrong divisor");
int pcon = (con > 0) ? con : -con; int pcon = (con > 0) ? con : -con;
Label Lfast; Label Lfast, Lpos, Ldone;
__ movl($tmp$$Register, pcon); __ movl($tmp$$Register, pcon);
__ cmpl($tmp$$Register, HIGH_FROM_LOW($dst$$Register)); __ cmpl($tmp$$Register, HIGH_FROM_LOW($dst$$Register));
...@@ -8941,12 +8966,28 @@ instruct modL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlag ...@@ -8941,12 +8966,28 @@ instruct modL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlag
__ movl($tmp2$$Register, $dst$$Register); // save __ movl($tmp2$$Register, $dst$$Register); // save
__ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register)); __ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register));
__ sarl(HIGH_FROM_LOW($dst$$Register), 31); // src sign __ movl(HIGH_FROM_LOW($dst$$Register),0); // preserve flags
__ idivl($tmp$$Register); __ jccb(Assembler::lessEqual, Lpos); // result is positive
// Negative dividend.
// convert value to positive to use unsigned division
__ lneg($dst$$Register, $tmp2$$Register);
__ divl($tmp$$Register);
__ movl($dst$$Register, $tmp2$$Register);
__ divl($tmp$$Register);
// revert remainder back to negative
__ negl(HIGH_FROM_LOW($dst$$Register));
__ jmpb(Ldone);
__ bind(Lpos);
__ divl($tmp$$Register);
__ movl($dst$$Register, $tmp2$$Register); __ movl($dst$$Register, $tmp2$$Register);
__ bind(Lfast); __ bind(Lfast);
__ idivl($tmp$$Register); // fast path: src is positive
__ divl($tmp$$Register);
__ bind(Ldone);
__ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register)); __ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register));
__ sarl(HIGH_FROM_LOW($dst$$Register), 31); // result sign __ sarl(HIGH_FROM_LOW($dst$$Register), 31); // result sign
......
/* /*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -108,8 +108,10 @@ public class Test implements Runnable { ...@@ -108,8 +108,10 @@ public class Test implements Runnable {
if (quo != quo0 || rem != rem0) { if (quo != quo0 || rem != rem0) {
if (VERBOSE) { if (VERBOSE) {
System.out.println(" " + dividend + " / " + divisor() + " = " + System.out.println("Computed: " + dividend + " / " + divisor() + " = " +
quo + ", " + dividend + " % " + divisor() + " = " + rem); quo + ", " + dividend + " % " + divisor() + " = " + rem );
System.out.println("expected: " + dividend + " / " + divisor() + " = " +
quo0 + ", " + dividend + " % " + divisor() + " = " + rem0);
// Report sign of rem failure // Report sign of rem failure
if (rem != 0 && (rem ^ dividend) < 0) { if (rem != 0 && (rem ^ dividend) < 0) {
System.out.println(" rem & dividend have different signs"); System.out.println(" rem & dividend have different signs");
...@@ -168,7 +170,7 @@ public class Test implements Runnable { ...@@ -168,7 +170,7 @@ public class Test implements Runnable {
for (int i = start; i <= end; i++) { for (int i = start; i <= end; i++) {
for (int s = 0; s < 64; s += 4) { for (int s = 0; s < 64; s += 4) {
total++; total++;
long dividend = i << s; long dividend = ((long)i) << s;
if (!checkL(dividend)) { if (!checkL(dividend)) {
wrong++; wrong++;
// Stop on the first failure // Stop on the first failure
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册