From bc08383d9d6e93a262614bb6cdd32423b99061c1 Mon Sep 17 00:00:00 2001 From: kvn Date: Sat, 6 Nov 2010 18:52:07 -0700 Subject: [PATCH] 6997311: SIGFPE in new long division asm code Summary: use unsigned DIV instruction Reviewed-by: never --- src/cpu/x86/vm/assembler_x86.cpp | 6 +++ src/cpu/x86/vm/assembler_x86.hpp | 1 + src/cpu/x86/vm/x86_32.ad | 91 +++++++++++++++++++++++--------- test/compiler/6603011/Test.java | 10 ++-- 4 files changed, 79 insertions(+), 29 deletions(-) diff --git a/src/cpu/x86/vm/assembler_x86.cpp b/src/cpu/x86/vm/assembler_x86.cpp index bb62c15de..64be76d7c 100644 --- a/src/cpu/x86/vm/assembler_x86.cpp +++ b/src/cpu/x86/vm/assembler_x86.cpp @@ -1275,6 +1275,12 @@ void Assembler::idivl(Register src) { 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) { int encode = prefix_and_encode(dst->encoding(), src->encoding()); emit_byte(0x0F); diff --git a/src/cpu/x86/vm/assembler_x86.hpp b/src/cpu/x86/vm/assembler_x86.hpp index 88d082e5d..fb832b689 100644 --- a/src/cpu/x86/vm/assembler_x86.hpp +++ b/src/cpu/x86/vm/assembler_x86.hpp @@ -1011,6 +1011,7 @@ private: void hlt(); void idivl(Register src); + void divl(Register src); // Unsigned division void idivq(Register src); diff --git a/src/cpu/x86/vm/x86_32.ad b/src/cpu/x86/vm/x86_32.ad index d0e75c473..21b6bf97b 100644 --- a/src/cpu/x86/vm/x86_32.ad +++ b/src/cpu/x86/vm/x86_32.ad @@ -8863,48 +8863,64 @@ instruct divL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlag effect( TEMP tmp, TEMP tmp2, KILL cr ); ins_cost(1000); format %{ "MOV $tmp,abs($imm) # ldiv EDX:EAX,$imm\n\t" + "XOR $tmp2,$tmp2\n\t" "CMP $tmp,EDX\n\t" "JA,s fast\n\t" "MOV $tmp2,EAX\n\t" "MOV EAX,EDX\n\t" - "SAR EDX,31\n\t" - "IDIV $tmp\n\t" - "XCHG EAX,$tmp2 \n\t" - "IDIV $tmp\n\t" - "CDQ\n\t" - "ADD EDX,$tmp2\n\t" + "MOV EDX,0\n\t" + "JLE,s pos\n\t" + "LNEG EAX : $tmp2\n\t" + "DIV $tmp # unsigned division\n\t" + "XCHG EAX,$tmp2\n\t" + "DIV $tmp\n\t" + "LNEG $tmp2 : EAX\n\t" "JMP,s done\n" + "pos:\n\t" + "DIV $tmp\n\t" + "XCHG EAX,$tmp2\n" "fast:\n\t" - "IDIV $tmp\n\t" - "XOR EDX,EDX\n" + "DIV $tmp\n" "done:\n\t" + "MOV EDX,$tmp2\n\t" "NEG EDX:EAX # if $imm < 0" %} ins_encode %{ int con = (int)$imm$$constant; assert(con != 0 && con != -1 && con != min_jint, "wrong divisor"); int pcon = (con > 0) ? con : -con; - Label Lfast, Ldone; + Label Lfast, Lpos, Ldone; __ movl($tmp$$Register, pcon); + __ xorl($tmp2$$Register,$tmp2$$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($dst$$Register, HIGH_FROM_LOW($dst$$Register)); - __ sarl(HIGH_FROM_LOW($dst$$Register), 31); // src sign - __ idivl($tmp$$Register); + __ movl(HIGH_FROM_LOW($dst$$Register),0); // preserve flags + __ 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); - __ idivl($tmp$$Register); - __ cdql(); - __ addl(HIGH_FROM_LOW($dst$$Register),$tmp2$$Register); + __ divl($tmp$$Register); + // revert result back to negative + __ lneg($tmp2$$Register, $dst$$Register); __ 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); - // fast path: src is positive and result fits into 32 bit - __ idivl($tmp$$Register); - __ xorl(HIGH_FROM_LOW($dst$$Register),HIGH_FROM_LOW($dst$$Register)); + // fast path: src is positive + __ divl($tmp$$Register); // Use unsigned division __ bind(Ldone); + __ movl(HIGH_FROM_LOW($dst$$Register),$tmp2$$Register); if (con < 0) { __ 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" "MOV $tmp2,EAX\n\t" "MOV EAX,EDX\n\t" - "SAR EDX,31\n\t" - "IDIV $tmp\n\t" + "MOV EDX,0\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" "fast:\n\t" - "IDIV $tmp\n\t" + "DIV $tmp\n" + "done:\n\t" "MOV EAX,EDX\n\t" "SAR EDX,31\n\t" %} ins_encode %{ int con = (int)$imm$$constant; assert(con != 0 && con != -1 && con != min_jint, "wrong divisor"); int pcon = (con > 0) ? con : -con; - Label Lfast; + Label Lfast, Lpos, Ldone; __ movl($tmp$$Register, pcon); __ 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($dst$$Register, HIGH_FROM_LOW($dst$$Register)); - __ sarl(HIGH_FROM_LOW($dst$$Register), 31); // src sign - __ idivl($tmp$$Register); + __ movl(HIGH_FROM_LOW($dst$$Register),0); // preserve flags + __ 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); __ bind(Lfast); - __ idivl($tmp$$Register); + // fast path: src is positive + __ divl($tmp$$Register); + + __ bind(Ldone); __ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register)); __ sarl(HIGH_FROM_LOW($dst$$Register), 31); // result sign diff --git a/test/compiler/6603011/Test.java b/test/compiler/6603011/Test.java index 718b33587..74c1062d9 100644 --- a/test/compiler/6603011/Test.java +++ b/test/compiler/6603011/Test.java @@ -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. * * 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 (VERBOSE) { - System.out.println(" " + dividend + " / " + divisor() + " = " + - quo + ", " + dividend + " % " + divisor() + " = " + rem); + System.out.println("Computed: " + dividend + " / " + divisor() + " = " + + quo + ", " + dividend + " % " + divisor() + " = " + rem ); + System.out.println("expected: " + dividend + " / " + divisor() + " = " + + quo0 + ", " + dividend + " % " + divisor() + " = " + rem0); // Report sign of rem failure if (rem != 0 && (rem ^ dividend) < 0) { 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 s = 0; s < 64; s += 4) { total++; - long dividend = i << s; + long dividend = ((long)i) << s; if (!checkL(dividend)) { wrong++; // Stop on the first failure -- GitLab