@@ -162,39 +162,66 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
162
162
}
163
163
p .To .Type = obj .TYPE_REG
164
164
p .To .Reg = gc .SSARegNum (v )
165
+
166
+ case ssa .OpPPC64MOVDaddr :
167
+ p := gc .Prog (ppc64 .AMOVD )
168
+ p .From .Type = obj .TYPE_ADDR
169
+ p .To .Type = obj .TYPE_REG
170
+ p .To .Reg = gc .SSARegNum (v )
171
+
172
+ var wantreg string
173
+ // Suspect comment, copied from ARM code
174
+ // MOVD $sym+off(base), R
175
+ // the assembler expands it as the following:
176
+ // - base is SP: add constant offset to SP
177
+ // when constant is large, tmp register (R11) may be used
178
+ // - base is SB: load external address from constant pool (use relocation)
179
+ switch v .Aux .(type ) {
180
+ default :
181
+ v .Fatalf ("aux is of unknown type %T" , v .Aux )
182
+ case * ssa.ExternSymbol :
183
+ wantreg = "SB"
184
+ gc .AddAux (& p .From , v )
185
+ case * ssa.ArgSymbol , * ssa.AutoSymbol :
186
+ wantreg = "SP"
187
+ gc .AddAux (& p .From , v )
188
+ case nil :
189
+ // No sym, just MOVD $off(SP), R
190
+ wantreg = "SP"
191
+ p .From .Reg = ppc64 .REGSP
192
+ p .From .Offset = v .AuxInt
193
+ }
194
+ if reg := gc .SSAReg (v .Args [0 ]); reg .Name () != wantreg {
195
+ v .Fatalf ("bad reg %s for symbol type %T, want %s" , reg .Name (), v .Aux , wantreg )
196
+ }
197
+
165
198
case ssa .OpPPC64MOVDconst , ssa .OpPPC64MOVWconst , ssa .OpPPC64MOVHconst , ssa .OpPPC64MOVBconst , ssa .OpPPC64FMOVDconst , ssa .OpPPC64FMOVSconst :
166
199
p := gc .Prog (v .Op .Asm ())
167
200
p .From .Type = obj .TYPE_CONST
168
201
p .From .Offset = v .AuxInt
169
202
p .To .Type = obj .TYPE_REG
170
203
p .To .Reg = gc .SSARegNum (v )
171
204
172
- case ssa .OpPPC64FCMPU :
173
- p := gc .Prog (v .Op .Asm ())
174
- p .From .Type = obj .TYPE_REG
175
- p .From .Reg = gc .SSARegNum (v .Args [1 ])
176
- p .Reg = gc .SSARegNum (v .Args [0 ])
177
-
178
- case ssa .OpPPC64CMP , ssa .OpPPC64CMPW , ssa .OpPPC64CMPU , ssa .OpPPC64CMPWU :
205
+ case ssa .OpPPC64FCMPU , ssa .OpPPC64CMP , ssa .OpPPC64CMPW , ssa .OpPPC64CMPU , ssa .OpPPC64CMPWU :
179
206
p := gc .Prog (v .Op .Asm ())
180
207
p .From .Type = obj .TYPE_REG
181
- p .From .Reg = gc .SSARegNum (v .Args [1 ])
182
- p .Reg = gc .SSARegNum (v .Args [0 ])
208
+ p .From .Reg = gc .SSARegNum (v .Args [0 ])
183
209
p .To .Type = obj .TYPE_REG
184
- p .To .Reg = gc .SSARegNum (v .Args [0 ])
210
+ p .To .Reg = gc .SSARegNum (v .Args [1 ])
185
211
186
212
case ssa .OpPPC64CMPconst :
187
213
p := gc .Prog (v .Op .Asm ())
188
- p .From .Type = obj .TYPE_CONST
189
- p .From .Offset = v .AuxInt
190
- p .Reg = gc .SSARegNum (v .Args [0 ])
214
+ p .From .Type = obj .TYPE_REG
215
+ p .From .Reg = gc .SSARegNum (v .Args [0 ])
216
+ p .To .Type = obj .TYPE_CONST
217
+ p .To .Offset = v .AuxInt
191
218
192
219
case ssa .OpPPC64MOVBreg , ssa .OpPPC64MOVBZreg , ssa .OpPPC64MOVHreg , ssa .OpPPC64MOVHZreg , ssa .OpPPC64MOVWreg , ssa .OpPPC64MOVWZreg :
193
220
// Shift in register to required size
194
221
p := gc .Prog (v .Op .Asm ())
195
222
p .From .Type = obj .TYPE_REG
196
223
p .From .Reg = gc .SSARegNum (v .Args [0 ])
197
- p .To .Reg = gc .SSARegNum (v . Args [ 0 ] )
224
+ p .To .Reg = gc .SSARegNum (v )
198
225
p .To .Type = obj .TYPE_REG
199
226
200
227
case ssa .OpPPC64MOVDload , ssa .OpPPC64MOVWload , ssa .OpPPC64MOVBload , ssa .OpPPC64MOVHload , ssa .OpPPC64MOVWZload , ssa .OpPPC64MOVBZload , ssa .OpPPC64MOVHZload :
@@ -212,13 +239,15 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
212
239
p .To .Type = obj .TYPE_REG
213
240
p .To .Reg = gc .SSARegNum (v )
214
241
case ssa .OpPPC64MOVDstoreconst , ssa .OpPPC64MOVWstoreconst , ssa .OpPPC64MOVHstoreconst , ssa .OpPPC64MOVBstoreconst :
242
+ // TODO: pretty sure this is bogus, PPC has no such instruction unless constant is zero.
215
243
p := gc .Prog (v .Op .Asm ())
216
244
p .From .Type = obj .TYPE_CONST
217
245
sc := v .AuxValAndOff ()
218
246
p .From .Offset = sc .Val ()
219
247
p .To .Type = obj .TYPE_MEM
220
248
p .To .Reg = gc .SSARegNum (v .Args [0 ])
221
249
gc .AddAux2 (& p .To , v , sc .Off ())
250
+
222
251
case ssa .OpPPC64MOVDstore , ssa .OpPPC64MOVWstore , ssa .OpPPC64MOVHstore , ssa .OpPPC64MOVBstore :
223
252
p := gc .Prog (v .Op .Asm ())
224
253
p .From .Type = obj .TYPE_REG
@@ -272,17 +301,79 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
272
301
}
273
302
}
274
303
304
+ var blockJump = [... ]struct {
305
+ asm , invasm obj.As
306
+ }{
307
+ ssa .BlockPPC64EQ : {ppc64 .ABEQ , ppc64 .ABNE },
308
+ ssa .BlockPPC64NE : {ppc64 .ABNE , ppc64 .ABEQ },
309
+
310
+ ssa .BlockPPC64LT : {ppc64 .ABLT , ppc64 .ABGE },
311
+ ssa .BlockPPC64GE : {ppc64 .ABGE , ppc64 .ABLT },
312
+ ssa .BlockPPC64LE : {ppc64 .ABLE , ppc64 .ABGT },
313
+ ssa .BlockPPC64GT : {ppc64 .ABGT , ppc64 .ABLE },
314
+
315
+ ssa .BlockPPC64ULT : {ppc64 .ABLT , ppc64 .ABGE },
316
+ ssa .BlockPPC64UGE : {ppc64 .ABGE , ppc64 .ABLT },
317
+ ssa .BlockPPC64ULE : {ppc64 .ABLE , ppc64 .ABGT },
318
+ ssa .BlockPPC64UGT : {ppc64 .ABGT , ppc64 .ABLE },
319
+ }
320
+
275
321
func ssaGenBlock (s * gc.SSAGenState , b , next * ssa.Block ) {
276
322
s .SetLineno (b .Line )
277
323
278
324
switch b .Kind {
279
- case ssa .BlockCall :
325
+ case ssa .BlockPlain , ssa . BlockCall , ssa . BlockCheck :
280
326
if b .Succs [0 ].Block () != next {
281
327
p := gc .Prog (obj .AJMP )
282
328
p .To .Type = obj .TYPE_BRANCH
283
329
s .Branches = append (s .Branches , gc.Branch {P : p , B : b .Succs [0 ].Block ()})
284
330
}
331
+ case ssa .BlockExit :
332
+ gc .Prog (obj .AUNDEF ) // tell plive.go that we never reach here
285
333
case ssa .BlockRet :
286
334
gc .Prog (obj .ARET )
335
+
336
+ case ssa .BlockPPC64EQ , ssa .BlockPPC64NE ,
337
+ ssa .BlockPPC64LT , ssa .BlockPPC64GE ,
338
+ ssa .BlockPPC64LE , ssa .BlockPPC64GT ,
339
+ ssa .BlockPPC64ULT , ssa .BlockPPC64UGT ,
340
+ ssa .BlockPPC64ULE , ssa .BlockPPC64UGE :
341
+ jmp := blockJump [b .Kind ]
342
+ likely := b .Likely
343
+ var p * obj.Prog
344
+ switch next {
345
+ case b .Succs [0 ].Block ():
346
+ p = gc .Prog (jmp .invasm )
347
+ likely *= - 1
348
+ p .To .Type = obj .TYPE_BRANCH
349
+ s .Branches = append (s .Branches , gc.Branch {P : p , B : b .Succs [1 ].Block ()})
350
+ case b .Succs [1 ].Block ():
351
+ p = gc .Prog (jmp .asm )
352
+ p .To .Type = obj .TYPE_BRANCH
353
+ s .Branches = append (s .Branches , gc.Branch {P : p , B : b .Succs [0 ].Block ()})
354
+ default :
355
+ p = gc .Prog (jmp .asm )
356
+ p .To .Type = obj .TYPE_BRANCH
357
+ s .Branches = append (s .Branches , gc.Branch {P : p , B : b .Succs [0 ].Block ()})
358
+ q := gc .Prog (obj .AJMP )
359
+ q .To .Type = obj .TYPE_BRANCH
360
+ s .Branches = append (s .Branches , gc.Branch {P : q , B : b .Succs [1 ].Block ()})
361
+ }
362
+
363
+ // liblink reorders the instruction stream as it sees fit.
364
+ // Pass along what we know so liblink can make use of it.
365
+ // TODO: Once we've fully switched to SSA,
366
+ // make liblink leave our output alone.
367
+ //switch likely {
368
+ //case ssa.BranchUnlikely:
369
+ // p.From.Type = obj.TYPE_CONST
370
+ // p.From.Offset = 0
371
+ //case ssa.BranchLikely:
372
+ // p.From.Type = obj.TYPE_CONST
373
+ // p.From.Offset = 1
374
+ //}
375
+
376
+ default :
377
+ b .Unimplementedf ("branch not implemented: %s. Control: %s" , b .LongString (), b .Control .LongString ())
287
378
}
288
379
}
0 commit comments