Skip to content

Commit 3d01f28

Browse files
committed
cmd/compile: stop using fucomi* ops for 387 builds
The fucomi* opcodes were only introduced for the Pentium Pro. They do not exist for an MMX Pentium. Use the fucom* instructions instead and move the condition codes from the fp flags register to the integer flags register explicitly. The use of fucomi* opcodes in ggen.go was introduced in 1.5 (CL 8738). The bad ops were generated for 64-bit floating-point comparisons. The use of fucomi* opcodes in gsubr.go dates back to at least 1.1. The bad ops were generated for float{32,64} to uint64 conversions. Fixes #13923 Change-Id: I5290599f5edea8abf8fb18036f44fa78bd1fc9e6 Reviewed-on: https://go-review.googlesource.com/18590 Reviewed-by: Minux Ma <[email protected]> Reviewed-by: Russ Cox <[email protected]>
1 parent f3ce054 commit 3d01f28

File tree

4 files changed

+120
-11
lines changed

4 files changed

+120
-11
lines changed
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright 2016 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package gc
6+
7+
import "testing"
8+
9+
// For GO386=387, make sure fucomi* opcodes are not used
10+
// for comparison operations.
11+
// Note that this test will fail only on a Pentium MMX
12+
// processor (with GOARCH=386 GO386=387), as it just runs
13+
// some code and looks for an unimplemented instruction fault.
14+
15+
//go:noinline
16+
func compare1(a, b float64) bool {
17+
return a < b
18+
}
19+
20+
//go:noinline
21+
func compare2(a, b float32) bool {
22+
return a < b
23+
}
24+
25+
func TestFloatCompare(t *testing.T) {
26+
if !compare1(3, 5) {
27+
t.Errorf("compare1 returned false")
28+
}
29+
if !compare2(3, 5) {
30+
t.Errorf("compare2 returned false")
31+
}
32+
}
33+
34+
// For GO386=387, make sure fucomi* opcodes are not used
35+
// for float->int conversions.
36+
37+
//go:noinline
38+
func cvt1(a float64) uint64 {
39+
return uint64(a)
40+
}
41+
42+
//go:noinline
43+
func cvt2(a float64) uint32 {
44+
return uint32(a)
45+
}
46+
47+
//go:noinline
48+
func cvt3(a float32) uint64 {
49+
return uint64(a)
50+
}
51+
52+
//go:noinline
53+
func cvt4(a float32) uint32 {
54+
return uint32(a)
55+
}
56+
57+
//go:noinline
58+
func cvt5(a float64) int64 {
59+
return int64(a)
60+
}
61+
62+
//go:noinline
63+
func cvt6(a float64) int32 {
64+
return int32(a)
65+
}
66+
67+
//go:noinline
68+
func cvt7(a float32) int64 {
69+
return int64(a)
70+
}
71+
72+
//go:noinline
73+
func cvt8(a float32) int32 {
74+
return int32(a)
75+
}
76+
77+
func TestFloatConvert(t *testing.T) {
78+
if got := cvt1(3.5); got != 3 {
79+
t.Errorf("cvt1 got %d, wanted 3", got)
80+
}
81+
if got := cvt2(3.5); got != 3 {
82+
t.Errorf("cvt2 got %d, wanted 3", got)
83+
}
84+
if got := cvt3(3.5); got != 3 {
85+
t.Errorf("cvt3 got %d, wanted 3", got)
86+
}
87+
if got := cvt4(3.5); got != 3 {
88+
t.Errorf("cvt4 got %d, wanted 3", got)
89+
}
90+
if got := cvt5(3.5); got != 3 {
91+
t.Errorf("cvt5 got %d, wanted 3", got)
92+
}
93+
if got := cvt6(3.5); got != 3 {
94+
t.Errorf("cvt6 got %d, wanted 3", got)
95+
}
96+
if got := cvt7(3.5); got != 3 {
97+
t.Errorf("cvt7 got %d, wanted 3", got)
98+
}
99+
if got := cvt8(3.5); got != 3 {
100+
t.Errorf("cvt8 got %d, wanted 3", got)
101+
}
102+
}

src/cmd/compile/internal/x86/ggen.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -764,9 +764,7 @@ func bgen_float(n *gc.Node, wantTrue bool, likely int, to *obj.Prog) {
764764
gc.Cgen(nr, &tmp)
765765
gc.Cgen(nl, &tmp)
766766
}
767-
768-
gins(x86.AFUCOMIP, &tmp, &n2)
769-
gins(x86.AFMOVDP, &tmp, &tmp) // annoying pop but still better than STSW+SAHF
767+
gins(x86.AFUCOMPP, &tmp, &n2)
770768
} else {
771769
// TODO(rsc): The moves back and forth to memory
772770
// here are for truncating the value to 32 bits.
@@ -783,9 +781,9 @@ func bgen_float(n *gc.Node, wantTrue bool, likely int, to *obj.Prog) {
783781
gc.Cgen(nl, &t2)
784782
gmove(&t2, &tmp)
785783
gins(x86.AFCOMFP, &t1, &tmp)
786-
gins(x86.AFSTSW, nil, &ax)
787-
gins(x86.ASAHF, nil, nil)
788784
}
785+
gins(x86.AFSTSW, nil, &ax)
786+
gins(x86.ASAHF, nil, nil)
789787
} else {
790788
// Not 387
791789
if !nl.Addable {

src/cmd/compile/internal/x86/gsubr.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -1198,14 +1198,17 @@ func floatmove(f *gc.Node, t *gc.Node) {
11981198

11991199
// if 0 > v { answer = 0 }
12001200
gins(x86.AFMOVD, &zerof, &f0)
1201-
1202-
gins(x86.AFUCOMIP, &f0, &f1)
1201+
gins(x86.AFUCOMP, &f0, &f1)
1202+
gins(x86.AFSTSW, nil, &ax)
1203+
gins(x86.ASAHF, nil, nil)
12031204
p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0)
12041205

12051206
// if 1<<64 <= v { answer = 0 too }
12061207
gins(x86.AFMOVD, &two64f, &f0)
12071208

1208-
gins(x86.AFUCOMIP, &f0, &f1)
1209+
gins(x86.AFUCOMP, &f0, &f1)
1210+
gins(x86.AFSTSW, nil, &ax)
1211+
gins(x86.ASAHF, nil, nil)
12091212
p2 := gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0)
12101213
gc.Patch(p1, gc.Pc)
12111214
gins(x86.AFMOVVP, &f0, t) // don't care about t, but will pop the stack
@@ -1235,7 +1238,9 @@ func floatmove(f *gc.Node, t *gc.Node) {
12351238
// actual work
12361239
gins(x86.AFMOVD, &two63f, &f0)
12371240

1238-
gins(x86.AFUCOMIP, &f0, &f1)
1241+
gins(x86.AFUCOMP, &f0, &f1)
1242+
gins(x86.AFSTSW, nil, &ax)
1243+
gins(x86.ASAHF, nil, nil)
12391244
p2 = gc.Gbranch(optoas(gc.OLE, gc.Types[tt]), nil, 0)
12401245
gins(x86.AFMOVVP, &f0, t)
12411246
p3 := gc.Gbranch(obj.AJMP, nil, 0)

src/cmd/compile/internal/x86/prog.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,12 @@ var progtable = [x86.ALAST]obj.ProgInfo{
9191
x86.AFCOMDPP: {Flags: gc.SizeD | gc.LeftAddr | gc.RightRead},
9292
x86.AFCOMF: {Flags: gc.SizeF | gc.LeftAddr | gc.RightRead},
9393
x86.AFCOMFP: {Flags: gc.SizeF | gc.LeftAddr | gc.RightRead},
94-
x86.AFUCOMIP: {Flags: gc.SizeF | gc.LeftAddr | gc.RightRead},
95-
x86.AFCHS: {Flags: gc.SizeD | RightRdwr}, // also SizeF
94+
// NOTE(khr): don't use FUCOMI* instructions, not available
95+
// on Pentium MMX. See issue 13923.
96+
//x86.AFUCOMIP: {Flags: gc.SizeF | gc.LeftAddr | gc.RightRead},
97+
x86.AFUCOMP: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
98+
x86.AFUCOMPP: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
99+
x86.AFCHS: {Flags: gc.SizeD | RightRdwr}, // also SizeF
96100

97101
x86.AFDIVDP: {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
98102
x86.AFDIVF: {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},

0 commit comments

Comments
 (0)