mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
6997311: SIGFPE in new long division asm code
Use unsigned DIV instruction Reviewed-by: never
This commit is contained in:
parent
085e1ad6e1
commit
ce2df719c6
4 changed files with 79 additions and 29 deletions
|
@ -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:
|
||||||
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
|
||||||
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
|
||||||
"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
|
||||||
|
|
||||||
__ 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
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* 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 {
|
||||||
|
|
||||||
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 {
|
||||||
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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue