Commit 1f4f2d0d authored by Michael Munday's avatar Michael Munday

cmd/compile: fix uint64 to float casts on ppc64

Adds the FCFIDU instruction and uses it instead of the FCFID
instruction for unsigned integer to float casts. This change means
that unsigned integers do not have to be cast to signed integers
before being cast to a floating point value. Therefore it is no
longer necessary to insert instructions to detect and fix
values that overflow int64.

The previous code generating the uint64 to int64 cast handled
overflow by truncating the uint64 value. This truncation can
change the result of the rounding performed by the integer to
float cast.

The FCFIDU instruction was added in Power ISA 2.06B.

Fixes #15539.

Change-Id: Ia37a9631293eff91032d4cd9a9bec759d2142437
Reviewed-on: https://go-review.googlesource.com/22772Reviewed-by: default avatarDavid Chase <drchase@google.com>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 3747c009
...@@ -442,12 +442,8 @@ func gmove(f *gc.Node, t *gc.Node) { ...@@ -442,12 +442,8 @@ func gmove(f *gc.Node, t *gc.Node) {
return return
//warn("gmove: convert int to float not implemented: %N -> %N\n", f, t); //warn("gmove: convert int to float not implemented: %N -> %N\n", f, t);
//return;
// algorithm is:
// if small enough, use native int64 -> uint64 conversion.
// otherwise, halve (rounding to odd?), convert, and double.
/* /*
* integer to float * signed integer to float
*/ */
case gc.TINT32<<16 | gc.TFLOAT32, case gc.TINT32<<16 | gc.TFLOAT32,
gc.TINT32<<16 | gc.TFLOAT64, gc.TINT32<<16 | gc.TFLOAT64,
...@@ -456,8 +452,29 @@ func gmove(f *gc.Node, t *gc.Node) { ...@@ -456,8 +452,29 @@ func gmove(f *gc.Node, t *gc.Node) {
gc.TINT16<<16 | gc.TFLOAT32, gc.TINT16<<16 | gc.TFLOAT32,
gc.TINT16<<16 | gc.TFLOAT64, gc.TINT16<<16 | gc.TFLOAT64,
gc.TINT8<<16 | gc.TFLOAT32, gc.TINT8<<16 | gc.TFLOAT32,
gc.TINT8<<16 | gc.TFLOAT64, gc.TINT8<<16 | gc.TFLOAT64:
gc.TUINT16<<16 | gc.TFLOAT32, var r1 gc.Node
gc.Regalloc(&r1, gc.Types[gc.TINT64], nil)
gmove(f, &r1)
gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t)
p1 := gins(ppc64.AMOVD, &r1, nil)
p1.To.Type = obj.TYPE_MEM
p1.To.Reg = ppc64.REGSP
p1.To.Offset = -8
p1 = gins(ppc64.AFMOVD, nil, &r2)
p1.From.Type = obj.TYPE_MEM
p1.From.Reg = ppc64.REGSP
p1.From.Offset = -8
gins(ppc64.AFCFID, &r2, &r2)
gc.Regfree(&r1)
gmove(&r2, t)
gc.Regfree(&r2)
return
/*
* unsigned integer to float
*/
case gc.TUINT16<<16 | gc.TFLOAT32,
gc.TUINT16<<16 | gc.TFLOAT64, gc.TUINT16<<16 | gc.TFLOAT64,
gc.TUINT8<<16 | gc.TFLOAT32, gc.TUINT8<<16 | gc.TFLOAT32,
gc.TUINT8<<16 | gc.TFLOAT64, gc.TUINT8<<16 | gc.TFLOAT64,
...@@ -465,22 +482,10 @@ func gmove(f *gc.Node, t *gc.Node) { ...@@ -465,22 +482,10 @@ func gmove(f *gc.Node, t *gc.Node) {
gc.TUINT32<<16 | gc.TFLOAT64, gc.TUINT32<<16 | gc.TFLOAT64,
gc.TUINT64<<16 | gc.TFLOAT32, gc.TUINT64<<16 | gc.TFLOAT32,
gc.TUINT64<<16 | gc.TFLOAT64: gc.TUINT64<<16 | gc.TFLOAT64:
bignodes()
var r1 gc.Node var r1 gc.Node
gc.Regalloc(&r1, gc.Types[gc.TINT64], nil) gc.Regalloc(&r1, gc.Types[gc.TUINT64], nil)
gmove(f, &r1) gmove(f, &r1)
if ft == gc.TUINT64 {
gc.Nodreg(&r2, gc.Types[gc.TUINT64], ppc64.REGTMP)
gmove(&bigi, &r2)
gins(ppc64.ACMPU, &r1, &r2)
p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1)
p2 := gins(ppc64.ASRD, nil, &r1)
p2.From.Type = obj.TYPE_CONST
p2.From.Offset = 1
gc.Patch(p1, gc.Pc)
}
gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t) gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t)
p1 := gins(ppc64.AMOVD, &r1, nil) p1 := gins(ppc64.AMOVD, &r1, nil)
p1.To.Type = obj.TYPE_MEM p1.To.Type = obj.TYPE_MEM
...@@ -490,15 +495,8 @@ func gmove(f *gc.Node, t *gc.Node) { ...@@ -490,15 +495,8 @@ func gmove(f *gc.Node, t *gc.Node) {
p1.From.Type = obj.TYPE_MEM p1.From.Type = obj.TYPE_MEM
p1.From.Reg = ppc64.REGSP p1.From.Reg = ppc64.REGSP
p1.From.Offset = -8 p1.From.Offset = -8
gins(ppc64.AFCFID, &r2, &r2) gins(ppc64.AFCFIDU, &r2, &r2)
gc.Regfree(&r1) gc.Regfree(&r1)
if ft == gc.TUINT64 {
p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) // use CR0 here again
gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], ppc64.FREGTWO)
gins(ppc64.AFMUL, &r1, &r2)
gc.Patch(p1, gc.Pc)
}
gmove(&r2, t) gmove(&r2, t)
gc.Regfree(&r2) gc.Regfree(&r2)
return return
......
...@@ -628,6 +628,8 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { ...@@ -628,6 +628,8 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
ppc64.AFCTIDZ, ppc64.AFCTIDZ,
ppc64.AFCFID, ppc64.AFCFID,
ppc64.AFCFIDCC, ppc64.AFCFIDCC,
ppc64.AFCFIDU,
ppc64.AFCFIDUCC,
ppc64.AFMOVS, ppc64.AFMOVS,
ppc64.AFMOVD, ppc64.AFMOVD,
ppc64.AFRSP, ppc64.AFRSP,
......
...@@ -71,6 +71,7 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{ ...@@ -71,6 +71,7 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{
ppc64.AFDIVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AFDIVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AFCTIDZ & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AFCTIDZ & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AFCFID & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AFCFID & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AFCFIDU & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AFCMPU & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead}, ppc64.AFCMPU & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
ppc64.AFRSP & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv}, ppc64.AFRSP & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
ppc64.AFSQRT & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite}, ppc64.AFSQRT & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
...@@ -206,6 +207,7 @@ func initvariants() { ...@@ -206,6 +207,7 @@ func initvariants() {
initvariant(ppc64.AFADD, ppc64.AFADDCC) initvariant(ppc64.AFADD, ppc64.AFADDCC)
initvariant(ppc64.AFADDS, ppc64.AFADDSCC) initvariant(ppc64.AFADDS, ppc64.AFADDSCC)
initvariant(ppc64.AFCFID, ppc64.AFCFIDCC) initvariant(ppc64.AFCFID, ppc64.AFCFIDCC)
initvariant(ppc64.AFCFIDU, ppc64.AFCFIDUCC)
initvariant(ppc64.AFCTID, ppc64.AFCTIDCC) initvariant(ppc64.AFCTID, ppc64.AFCTIDCC)
initvariant(ppc64.AFCTIDZ, ppc64.AFCTIDZCC) initvariant(ppc64.AFCTIDZ, ppc64.AFCTIDZCC)
initvariant(ppc64.AFCTIW, ppc64.AFCTIWCC) initvariant(ppc64.AFCTIW, ppc64.AFCTIWCC)
......
...@@ -480,6 +480,8 @@ const ( ...@@ -480,6 +480,8 @@ const (
/* AFCFIW; AFCFIWCC */ /* AFCFIW; AFCFIWCC */
AFCFID AFCFID
AFCFIDCC AFCFIDCC
AFCFIDU
AFCFIDUCC
AFCTID AFCTID
AFCTIDCC AFCTIDCC
AFCTIDZ AFCTIDZ
......
...@@ -247,6 +247,8 @@ var Anames = []string{ ...@@ -247,6 +247,8 @@ var Anames = []string{
"EXTSWCC", "EXTSWCC",
"FCFID", "FCFID",
"FCFIDCC", "FCFIDCC",
"FCFIDU",
"FCFIDUCC",
"FCTID", "FCTID",
"FCTIDCC", "FCTIDCC",
"FCTIDZ", "FCTIDZ",
......
...@@ -1105,6 +1105,8 @@ func buildop(ctxt *obj.Link) { ...@@ -1105,6 +1105,8 @@ func buildop(ctxt *obj.Link) {
opset(AFCTIDZCC, r0) opset(AFCTIDZCC, r0)
opset(AFCFID, r0) opset(AFCFID, r0)
opset(AFCFIDCC, r0) opset(AFCFIDCC, r0)
opset(AFCFIDU, r0)
opset(AFCFIDUCC, r0)
opset(AFRES, r0) opset(AFRES, r0)
opset(AFRESCC, r0) opset(AFRESCC, r0)
opset(AFRSQRTE, r0) opset(AFRSQRTE, r0)
...@@ -2716,6 +2718,10 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 { ...@@ -2716,6 +2718,10 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
return OPVCC(63, 846, 0, 0) return OPVCC(63, 846, 0, 0)
case AFCFIDCC: case AFCFIDCC:
return OPVCC(63, 846, 0, 1) return OPVCC(63, 846, 0, 1)
case AFCFIDU:
return OPVCC(63, 974, 0, 0)
case AFCFIDUCC:
return OPVCC(63, 974, 0, 1)
case AFCTIW: case AFCTIW:
return OPVCC(63, 14, 0, 0) return OPVCC(63, 14, 0, 0)
case AFCTIWCC: case AFCTIWCC:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment