@@ -73,11 +73,11 @@ var ssaRegToReg = []int16{
73
73
ppc64 .REG_F24 ,
74
74
ppc64 .REG_F25 ,
75
75
ppc64 .REG_F26 ,
76
- ppc64 .REG_F27 ,
77
- ppc64 .REG_F28 ,
78
- ppc64 .REG_F29 ,
79
- ppc64 .REG_F30 ,
80
- ppc64 .REG_F31 ,
76
+ // ppc64.REG_F27, // reserved for "floating conversion constant"
77
+ // ppc64.REG_F28, // 0.0
78
+ // ppc64.REG_F29, // 0.5
79
+ // ppc64.REG_F30, // 1.0
80
+ // ppc64.REG_F31, // 2.0
81
81
82
82
// ppc64.REG_CR0,
83
83
// ppc64.REG_CR1,
@@ -88,38 +88,24 @@ var ssaRegToReg = []int16{
88
88
// ppc64.REG_CR6,
89
89
// ppc64.REG_CR7,
90
90
91
- ppc64 .REG_CR ,
91
+ // ppc64.REG_CR,
92
92
// ppc64.REG_XER,
93
93
// ppc64.REG_LR,
94
94
// ppc64.REG_CTR,
95
95
}
96
96
97
- // Associated condition bit
98
- var condBits = map [ssa.Op ]uint8 {
99
- ssa .OpPPC64Equal : ppc64 .C_COND_EQ ,
100
- ssa .OpPPC64NotEqual : ppc64 .C_COND_EQ ,
101
- ssa .OpPPC64LessThan : ppc64 .C_COND_LT ,
102
- ssa .OpPPC64GreaterEqual : ppc64 .C_COND_LT ,
103
- ssa .OpPPC64GreaterThan : ppc64 .C_COND_GT ,
104
- ssa .OpPPC64LessEqual : ppc64 .C_COND_GT ,
105
- }
106
97
var condOps = map [ssa.Op ]obj.As {
107
98
ssa .OpPPC64Equal : ppc64 .ABEQ ,
108
99
ssa .OpPPC64NotEqual : ppc64 .ABNE ,
109
100
ssa .OpPPC64LessThan : ppc64 .ABLT ,
110
101
ssa .OpPPC64GreaterEqual : ppc64 .ABGE ,
111
102
ssa .OpPPC64GreaterThan : ppc64 .ABGT ,
112
103
ssa .OpPPC64LessEqual : ppc64 .ABLE ,
113
- }
114
104
115
- // Is the condition bit set? 1=yes 0=no
116
- var condBitSet = map [ssa.Op ]uint8 {
117
- ssa .OpPPC64Equal : 1 ,
118
- ssa .OpPPC64NotEqual : 0 ,
119
- ssa .OpPPC64LessThan : 1 ,
120
- ssa .OpPPC64GreaterEqual : 0 ,
121
- ssa .OpPPC64GreaterThan : 1 ,
122
- ssa .OpPPC64LessEqual : 0 ,
105
+ ssa .OpPPC64FLessThan : ppc64 .ABLT , // 1 branch for FCMP
106
+ ssa .OpPPC64FGreaterThan : ppc64 .ABGT , // 1 branch for FCMP
107
+ ssa .OpPPC64FLessEqual : ppc64 .ABLT , // 2 branches for FCMP <=, second is BEQ
108
+ ssa .OpPPC64FGreaterEqual : ppc64 .ABGT , // 2 branches for FCMP >=, second is BEQ
123
109
}
124
110
125
111
// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
@@ -205,38 +191,83 @@ func storeByType(t ssa.Type) obj.As {
205
191
panic ("bad store type" )
206
192
}
207
193
194
+ // scratchFpMem initializes an Addr (field of a Prog)
195
+ // to reference the scratchpad memory for movement between
196
+ // F and G registers for FP conversions.
197
+ func scratchFpMem (s * gc.SSAGenState , a * obj.Addr ) {
198
+ a .Type = obj .TYPE_MEM
199
+ a .Name = obj .NAME_AUTO
200
+ a .Node = s .ScratchFpMem
201
+ a .Sym = gc .Linksym (s .ScratchFpMem .Sym )
202
+ a .Reg = ppc64 .REGSP
203
+ }
204
+
208
205
func ssaGenValue (s * gc.SSAGenState , v * ssa.Value ) {
209
206
s .SetLineno (v .Line )
210
207
switch v .Op {
211
208
case ssa .OpInitMem :
212
209
// memory arg needs no code
213
210
case ssa .OpArg :
214
211
// input args need no code
215
- case ssa .OpSP , ssa .OpSB :
212
+ case ssa .OpSP , ssa .OpSB , ssa . OpGetG :
216
213
// nothing to do
217
214
218
215
case ssa .OpCopy , ssa .OpPPC64MOVDconvert :
219
- // TODO: copy of floats
220
- if v . Type .IsMemory () {
216
+ t := v . Type
217
+ if t .IsMemory () {
221
218
return
222
219
}
223
220
x := gc .SSARegNum (v .Args [0 ])
224
221
y := gc .SSARegNum (v )
225
222
if x != y {
226
- p := gc .Prog (ppc64 .AMOVD )
223
+ rt := obj .TYPE_REG
224
+ op := ppc64 .AMOVD
225
+
226
+ if t .IsFloat () {
227
+ op = ppc64 .AFMOVD
228
+ }
229
+ p := gc .Prog (op )
230
+ p .From .Type = rt
231
+ p .From .Reg = x
232
+ p .To .Type = rt
233
+ p .To .Reg = y
234
+ }
235
+
236
+ case ssa .OpPPC64Xf2i64 :
237
+ {
238
+ x := gc .SSARegNum (v .Args [0 ])
239
+ y := gc .SSARegNum (v )
240
+ p := gc .Prog (ppc64 .AFMOVD )
227
241
p .From .Type = obj .TYPE_REG
228
242
p .From .Reg = x
243
+ scratchFpMem (s , & p .To )
244
+ p = gc .Prog (ppc64 .AMOVD )
245
+ p .To .Type = obj .TYPE_REG
229
246
p .To .Reg = y
247
+ scratchFpMem (s , & p .From )
248
+ }
249
+ case ssa .OpPPC64Xi2f64 :
250
+ {
251
+ x := gc .SSARegNum (v .Args [0 ])
252
+ y := gc .SSARegNum (v )
253
+ p := gc .Prog (ppc64 .AMOVD )
254
+ p .From .Type = obj .TYPE_REG
255
+ p .From .Reg = x
256
+ scratchFpMem (s , & p .To )
257
+ p = gc .Prog (ppc64 .AFMOVD )
230
258
p .To .Type = obj .TYPE_REG
259
+ p .To .Reg = y
260
+ scratchFpMem (s , & p .From )
231
261
}
232
262
233
263
case ssa .OpPPC64LoweredGetClosurePtr :
234
264
// Closure pointer is R11 (already)
235
265
gc .CheckLoweredGetClosurePtr (v )
236
266
237
267
case ssa .OpLoadReg :
238
- p := gc . Prog ( loadByType (v .Type ) )
268
+ loadOp := loadByType (v .Type )
239
269
n , off := gc .AutoVar (v .Args [0 ])
270
+ p := gc .Prog (loadOp )
240
271
p .From .Type = obj .TYPE_MEM
241
272
p .From .Node = n
242
273
p .From .Sym = gc .Linksym (n .Sym )
@@ -251,10 +282,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
251
282
p .To .Reg = gc .SSARegNum (v )
252
283
253
284
case ssa .OpStoreReg :
254
- p := gc .Prog (storeByType (v .Type ))
285
+ storeOp := storeByType (v .Type )
286
+ n , off := gc .AutoVar (v )
287
+ p := gc .Prog (storeOp )
255
288
p .From .Type = obj .TYPE_REG
256
289
p .From .Reg = gc .SSARegNum (v .Args [0 ])
257
- n , off := gc .AutoVar (v )
258
290
p .To .Type = obj .TYPE_MEM
259
291
p .To .Node = n
260
292
p .To .Sym = gc .Linksym (n .Sym )
@@ -376,7 +408,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
376
408
p .To .Type = obj .TYPE_REG
377
409
p .To .Reg = ppc64 .REGTMP // Ignored; this is for the carry effect.
378
410
379
- case ssa .OpPPC64NEG , ssa .OpPPC64FNEG :
411
+ case ssa .OpPPC64NEG , ssa .OpPPC64FNEG , ssa . OpPPC64FSQRT , ssa . OpPPC64FSQRTS , ssa . OpPPC64FCTIDZ , ssa . OpPPC64FCTIWZ , ssa . OpPPC64FCFID , ssa . OpPPC64FRSP :
380
412
r := gc .SSARegNum (v )
381
413
p := gc .Prog (v .Op .Asm ())
382
414
p .To .Type = obj .TYPE_REG
@@ -510,8 +542,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
510
542
case ssa .OpPPC64Equal ,
511
543
ssa .OpPPC64NotEqual ,
512
544
ssa .OpPPC64LessThan ,
545
+ ssa .OpPPC64FLessThan ,
513
546
ssa .OpPPC64LessEqual ,
514
547
ssa .OpPPC64GreaterThan ,
548
+ ssa .OpPPC64FGreaterThan ,
515
549
ssa .OpPPC64GreaterEqual :
516
550
// On Power7 or later, can use isel instruction:
517
551
// for a < b, a > b, a = b:
@@ -549,6 +583,30 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
549
583
p = gc .Prog (obj .ANOP )
550
584
gc .Patch (pb , p )
551
585
586
+ case ssa .OpPPC64FLessEqual , // These include a second branch for EQ -- dealing with NaN prevents REL= to !REL conversion
587
+ ssa .OpPPC64FGreaterEqual :
588
+
589
+ p := gc .Prog (ppc64 .AMOVW )
590
+ p .From .Type = obj .TYPE_CONST
591
+ p .From .Offset = 1
592
+ p .To .Type = obj .TYPE_REG
593
+ p .To .Reg = gc .SSARegNum (v )
594
+
595
+ pb0 := gc .Prog (condOps [v .Op ])
596
+ pb0 .To .Type = obj .TYPE_BRANCH
597
+ pb1 := gc .Prog (ppc64 .ABEQ )
598
+ pb1 .To .Type = obj .TYPE_BRANCH
599
+
600
+ p = gc .Prog (ppc64 .AMOVW )
601
+ p .From .Type = obj .TYPE_CONST
602
+ p .From .Offset = 0
603
+ p .To .Type = obj .TYPE_REG
604
+ p .To .Reg = gc .SSARegNum (v )
605
+
606
+ p = gc .Prog (obj .ANOP )
607
+ gc .Patch (pb0 , p )
608
+ gc .Patch (pb1 , p )
609
+
552
610
case ssa .OpPPC64LoweredZero :
553
611
// Similar to how this is done on ARM,
554
612
// except that PPC MOVDU x,off(y) is *(y+off) = x; y=y+off
@@ -843,20 +901,22 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
843
901
}
844
902
845
903
var blockJump = [... ]struct {
846
- asm , invasm obj.As
904
+ asm , invasm obj.As
905
+ asmeq , invasmeq bool
847
906
}{
848
- ssa .BlockPPC64EQ : {ppc64 .ABEQ , ppc64 .ABNE },
849
- ssa .BlockPPC64NE : {ppc64 .ABNE , ppc64 .ABEQ },
850
-
851
- ssa .BlockPPC64LT : {ppc64 .ABLT , ppc64 .ABGE },
852
- ssa .BlockPPC64GE : {ppc64 .ABGE , ppc64 .ABLT },
853
- ssa .BlockPPC64LE : {ppc64 .ABLE , ppc64 .ABGT },
854
- ssa .BlockPPC64GT : {ppc64 .ABGT , ppc64 .ABLE },
855
-
856
- ssa .BlockPPC64ULT : {ppc64 .ABLT , ppc64 .ABGE },
857
- ssa .BlockPPC64UGE : {ppc64 .ABGE , ppc64 .ABLT },
858
- ssa .BlockPPC64ULE : {ppc64 .ABLE , ppc64 .ABGT },
859
- ssa .BlockPPC64UGT : {ppc64 .ABGT , ppc64 .ABLE },
907
+ ssa .BlockPPC64EQ : {ppc64 .ABEQ , ppc64 .ABNE , false , false },
908
+ ssa .BlockPPC64NE : {ppc64 .ABNE , ppc64 .ABEQ , false , false },
909
+
910
+ ssa .BlockPPC64LT : {ppc64 .ABLT , ppc64 .ABGE , false , false },
911
+ ssa .BlockPPC64GE : {ppc64 .ABGE , ppc64 .ABLT , false , false },
912
+ ssa .BlockPPC64LE : {ppc64 .ABLE , ppc64 .ABGT , false , false },
913
+ ssa .BlockPPC64GT : {ppc64 .ABGT , ppc64 .ABLE , false , false },
914
+
915
+ // TODO: need to work FP comparisons into block jumps
916
+ ssa .BlockPPC64FLT : {ppc64 .ABLT , ppc64 .ABGT , false , true },
917
+ ssa .BlockPPC64FGE : {ppc64 .ABGT , ppc64 .ABLT , true , false },
918
+ ssa .BlockPPC64FLE : {ppc64 .ABLT , ppc64 .ABGT , true , false },
919
+ ssa .BlockPPC64FGT : {ppc64 .ABGT , ppc64 .ABLT , false , true },
860
920
}
861
921
862
922
func ssaGenBlock (s * gc.SSAGenState , b , next * ssa.Block ) {
@@ -893,12 +953,17 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
893
953
gc .Prog (obj .AUNDEF ) // tell plive.go that we never reach here
894
954
case ssa .BlockRet :
895
955
gc .Prog (obj .ARET )
956
+ case ssa .BlockRetJmp :
957
+ p := gc .Prog (obj .AJMP )
958
+ p .To .Type = obj .TYPE_MEM
959
+ p .To .Name = obj .NAME_EXTERN
960
+ p .To .Sym = gc .Linksym (b .Aux .(* gc.Sym ))
896
961
897
962
case ssa .BlockPPC64EQ , ssa .BlockPPC64NE ,
898
963
ssa .BlockPPC64LT , ssa .BlockPPC64GE ,
899
964
ssa .BlockPPC64LE , ssa .BlockPPC64GT ,
900
- ssa .BlockPPC64ULT , ssa .BlockPPC64UGT ,
901
- ssa .BlockPPC64ULE , ssa .BlockPPC64UGE :
965
+ ssa .BlockPPC64FLT , ssa .BlockPPC64FGE ,
966
+ ssa .BlockPPC64FLE , ssa .BlockPPC64FGT :
902
967
jmp := blockJump [b .Kind ]
903
968
likely := b .Likely
904
969
var p * obj.Prog
@@ -908,14 +973,30 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
908
973
likely *= - 1
909
974
p .To .Type = obj .TYPE_BRANCH
910
975
s .Branches = append (s .Branches , gc.Branch {P : p , B : b .Succs [1 ].Block ()})
976
+ if jmp .invasmeq {
977
+ // TODO: The second branch is probably predict-not-taken since it is for FP equality
978
+ q := gc .Prog (ppc64 .ABEQ )
979
+ q .To .Type = obj .TYPE_BRANCH
980
+ s .Branches = append (s .Branches , gc.Branch {P : q , B : b .Succs [1 ].Block ()})
981
+ }
911
982
case b .Succs [1 ].Block ():
912
983
p = gc .Prog (jmp .asm )
913
984
p .To .Type = obj .TYPE_BRANCH
914
985
s .Branches = append (s .Branches , gc.Branch {P : p , B : b .Succs [0 ].Block ()})
986
+ if jmp .asmeq {
987
+ q := gc .Prog (ppc64 .ABEQ )
988
+ q .To .Type = obj .TYPE_BRANCH
989
+ s .Branches = append (s .Branches , gc.Branch {P : q , B : b .Succs [0 ].Block ()})
990
+ }
915
991
default :
916
992
p = gc .Prog (jmp .asm )
917
993
p .To .Type = obj .TYPE_BRANCH
918
994
s .Branches = append (s .Branches , gc.Branch {P : p , B : b .Succs [0 ].Block ()})
995
+ if jmp .asmeq {
996
+ q := gc .Prog (ppc64 .ABEQ )
997
+ q .To .Type = obj .TYPE_BRANCH
998
+ s .Branches = append (s .Branches , gc.Branch {P : q , B : b .Succs [0 ].Block ()})
999
+ }
919
1000
q := gc .Prog (obj .AJMP )
920
1001
q .To .Type = obj .TYPE_BRANCH
921
1002
s .Branches = append (s .Branches , gc.Branch {P : q , B : b .Succs [1 ].Block ()})
0 commit comments