1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/abi"
9 "cmd/compile/internal/base"
10 "cmd/compile/internal/ir"
11 "cmd/compile/internal/types"
12 "cmd/internal/obj"
13 "cmd/internal/src"
14 )
15
16
17
18
19 type Config struct {
20 arch string
21 PtrSize int64
22 RegSize int64
23 Types Types
24 lowerBlock blockRewriter
25 lowerValue valueRewriter
26 lateLowerBlock blockRewriter
27 lateLowerValue valueRewriter
28 splitLoad valueRewriter
29 registers []Register
30 gpRegMask regMask
31 fpRegMask regMask
32 fp32RegMask regMask
33 fp64RegMask regMask
34 simdRegMask regMask
35 specialRegMask regMask
36 intParamRegs []int8
37 floatParamRegs []int8
38 ABI1 *abi.ABIConfig
39 ABI0 *abi.ABIConfig
40 FPReg int8
41 LinkReg int8
42 hasGReg bool
43 ctxt *obj.Link
44 optimize bool
45 SoftFloat bool
46 Race bool
47 BigEndian bool
48 unalignedOK bool
49 haveBswap64 bool
50 haveBswap32 bool
51 haveBswap16 bool
52 haveCondSelect bool
53
54
55 mulRecipes map[int64]mulRecipe
56 }
57
58 type mulRecipe struct {
59 cost int
60 build func(*Value, *Value) *Value
61 }
62
63 type (
64 blockRewriter func(*Block) bool
65 valueRewriter func(*Value) bool
66 )
67
68 type Types struct {
69 Bool *types.Type
70 Int8 *types.Type
71 Int16 *types.Type
72 Int32 *types.Type
73 Int64 *types.Type
74 UInt8 *types.Type
75 UInt16 *types.Type
76 UInt32 *types.Type
77 UInt64 *types.Type
78 Int *types.Type
79 Float32 *types.Type
80 Float64 *types.Type
81 UInt *types.Type
82 Uintptr *types.Type
83 String *types.Type
84 BytePtr *types.Type
85 Int32Ptr *types.Type
86 UInt32Ptr *types.Type
87 IntPtr *types.Type
88 UintptrPtr *types.Type
89 Float32Ptr *types.Type
90 Float64Ptr *types.Type
91 BytePtrPtr *types.Type
92 Vec128 *types.Type
93 Vec256 *types.Type
94 Vec512 *types.Type
95 Mask *types.Type
96 }
97
98
99 func NewTypes() *Types {
100 t := new(Types)
101 t.SetTypPtrs()
102 return t
103 }
104
105
106 func (t *Types) SetTypPtrs() {
107 t.Bool = types.Types[types.TBOOL]
108 t.Int8 = types.Types[types.TINT8]
109 t.Int16 = types.Types[types.TINT16]
110 t.Int32 = types.Types[types.TINT32]
111 t.Int64 = types.Types[types.TINT64]
112 t.UInt8 = types.Types[types.TUINT8]
113 t.UInt16 = types.Types[types.TUINT16]
114 t.UInt32 = types.Types[types.TUINT32]
115 t.UInt64 = types.Types[types.TUINT64]
116 t.Int = types.Types[types.TINT]
117 t.Float32 = types.Types[types.TFLOAT32]
118 t.Float64 = types.Types[types.TFLOAT64]
119 t.UInt = types.Types[types.TUINT]
120 t.Uintptr = types.Types[types.TUINTPTR]
121 t.String = types.Types[types.TSTRING]
122 t.BytePtr = types.NewPtr(types.Types[types.TUINT8])
123 t.Int32Ptr = types.NewPtr(types.Types[types.TINT32])
124 t.UInt32Ptr = types.NewPtr(types.Types[types.TUINT32])
125 t.IntPtr = types.NewPtr(types.Types[types.TINT])
126 t.UintptrPtr = types.NewPtr(types.Types[types.TUINTPTR])
127 t.Float32Ptr = types.NewPtr(types.Types[types.TFLOAT32])
128 t.Float64Ptr = types.NewPtr(types.Types[types.TFLOAT64])
129 t.BytePtrPtr = types.NewPtr(types.NewPtr(types.Types[types.TUINT8]))
130 t.Vec128 = types.TypeVec128
131 t.Vec256 = types.TypeVec256
132 t.Vec512 = types.TypeVec512
133 t.Mask = types.TypeMask
134 }
135
136 type Logger interface {
137
138 Logf(string, ...any)
139
140
141
142 Log() bool
143
144
145 Fatalf(pos src.XPos, msg string, args ...any)
146
147
148 Warnl(pos src.XPos, fmt_ string, args ...any)
149
150
151 Debug_checknil() bool
152 }
153
154 type Frontend interface {
155 Logger
156
157
158 StringData(string) *obj.LSym
159
160
161
162 SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot
163
164
165
166 Syslook(string) *obj.LSym
167
168
169 UseWriteBarrier() bool
170
171
172 Func() *ir.Func
173 }
174
175
176 func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat bool) *Config {
177 c := &Config{arch: arch, Types: types}
178 switch arch {
179 case "amd64":
180 c.PtrSize = 8
181 c.RegSize = 8
182 c.lowerBlock = rewriteBlockAMD64
183 c.lowerValue = rewriteValueAMD64
184 c.lateLowerBlock = rewriteBlockAMD64latelower
185 c.lateLowerValue = rewriteValueAMD64latelower
186 c.splitLoad = rewriteValueAMD64splitload
187 c.registers = registersAMD64[:]
188 c.gpRegMask = gpRegMaskAMD64
189 c.fpRegMask = fpRegMaskAMD64
190 c.simdRegMask = simdRegMaskAMD64
191 c.specialRegMask = specialRegMaskAMD64
192 c.intParamRegs = paramIntRegAMD64
193 c.floatParamRegs = paramFloatRegAMD64
194 c.FPReg = framepointerRegAMD64
195 c.LinkReg = linkRegAMD64
196 c.hasGReg = true
197 c.unalignedOK = true
198 c.haveBswap64 = true
199 c.haveBswap32 = true
200 c.haveBswap16 = true
201 c.haveCondSelect = true
202 case "386":
203 c.PtrSize = 4
204 c.RegSize = 4
205 c.lowerBlock = rewriteBlock386
206 c.lowerValue = rewriteValue386
207 c.splitLoad = rewriteValue386splitload
208 c.registers = registers386[:]
209 c.gpRegMask = gpRegMask386
210 c.fpRegMask = fpRegMask386
211 c.FPReg = framepointerReg386
212 c.LinkReg = linkReg386
213 c.hasGReg = false
214 c.unalignedOK = true
215 c.haveBswap32 = true
216 c.haveBswap16 = true
217 case "arm":
218 c.PtrSize = 4
219 c.RegSize = 4
220 c.lowerBlock = rewriteBlockARM
221 c.lowerValue = rewriteValueARM
222 c.registers = registersARM[:]
223 c.gpRegMask = gpRegMaskARM
224 c.fpRegMask = fpRegMaskARM
225 c.FPReg = framepointerRegARM
226 c.LinkReg = linkRegARM
227 c.hasGReg = true
228 case "arm64":
229 c.PtrSize = 8
230 c.RegSize = 8
231 c.lowerBlock = rewriteBlockARM64
232 c.lowerValue = rewriteValueARM64
233 c.lateLowerBlock = rewriteBlockARM64latelower
234 c.lateLowerValue = rewriteValueARM64latelower
235 c.registers = registersARM64[:]
236 c.gpRegMask = gpRegMaskARM64
237 c.fpRegMask = fpRegMaskARM64
238 c.simdRegMask = simdRegMaskARM64
239 c.intParamRegs = paramIntRegARM64
240 c.floatParamRegs = paramFloatRegARM64
241 c.FPReg = framepointerRegARM64
242 c.LinkReg = linkRegARM64
243 c.hasGReg = true
244 c.unalignedOK = true
245 c.haveBswap64 = true
246 c.haveBswap32 = true
247 c.haveBswap16 = true
248 c.haveCondSelect = true
249 case "ppc64":
250 c.BigEndian = true
251 fallthrough
252 case "ppc64le":
253 c.PtrSize = 8
254 c.RegSize = 8
255 c.lowerBlock = rewriteBlockPPC64
256 c.lowerValue = rewriteValuePPC64
257 c.lateLowerBlock = rewriteBlockPPC64latelower
258 c.lateLowerValue = rewriteValuePPC64latelower
259 c.registers = registersPPC64[:]
260 c.gpRegMask = gpRegMaskPPC64
261 c.fpRegMask = fpRegMaskPPC64
262 c.specialRegMask = specialRegMaskPPC64
263 c.intParamRegs = paramIntRegPPC64
264 c.floatParamRegs = paramFloatRegPPC64
265 c.FPReg = framepointerRegPPC64
266 c.LinkReg = linkRegPPC64
267 c.hasGReg = true
268 c.unalignedOK = true
269
270
271
272
273 c.haveBswap64 = true
274 c.haveBswap32 = true
275 c.haveBswap16 = true
276 c.haveCondSelect = true
277 case "mips64":
278 c.BigEndian = true
279 fallthrough
280 case "mips64le":
281 c.PtrSize = 8
282 c.RegSize = 8
283 c.lowerBlock = rewriteBlockMIPS64
284 c.lowerValue = rewriteValueMIPS64
285 c.lateLowerBlock = rewriteBlockMIPS64latelower
286 c.lateLowerValue = rewriteValueMIPS64latelower
287 c.registers = registersMIPS64[:]
288 c.gpRegMask = gpRegMaskMIPS64
289 c.fpRegMask = fpRegMaskMIPS64
290 c.specialRegMask = specialRegMaskMIPS64
291 c.FPReg = framepointerRegMIPS64
292 c.LinkReg = linkRegMIPS64
293 c.hasGReg = true
294 case "loong64":
295 c.PtrSize = 8
296 c.RegSize = 8
297 c.lowerBlock = rewriteBlockLOONG64
298 c.lowerValue = rewriteValueLOONG64
299 c.lateLowerBlock = rewriteBlockLOONG64latelower
300 c.lateLowerValue = rewriteValueLOONG64latelower
301 c.registers = registersLOONG64[:]
302 c.gpRegMask = gpRegMaskLOONG64
303 c.fpRegMask = fpRegMaskLOONG64
304 c.intParamRegs = paramIntRegLOONG64
305 c.floatParamRegs = paramFloatRegLOONG64
306 c.FPReg = framepointerRegLOONG64
307 c.LinkReg = linkRegLOONG64
308 c.hasGReg = true
309 c.unalignedOK = true
310 c.haveBswap64 = true
311 c.haveBswap32 = true
312 c.haveBswap16 = true
313 c.haveCondSelect = true
314 case "s390x":
315 c.PtrSize = 8
316 c.RegSize = 8
317 c.lowerBlock = rewriteBlockS390X
318 c.lowerValue = rewriteValueS390X
319 c.registers = registersS390X[:]
320 c.gpRegMask = gpRegMaskS390X
321 c.fpRegMask = fpRegMaskS390X
322 c.intParamRegs = paramIntRegS390X
323 c.floatParamRegs = paramFloatRegS390X
324 c.FPReg = framepointerRegS390X
325 c.LinkReg = linkRegS390X
326 c.hasGReg = true
327 c.BigEndian = true
328 c.unalignedOK = true
329 c.haveBswap64 = true
330 c.haveBswap32 = true
331 c.haveBswap16 = true
332 case "mips":
333 c.BigEndian = true
334 fallthrough
335 case "mipsle":
336 c.PtrSize = 4
337 c.RegSize = 4
338 c.lowerBlock = rewriteBlockMIPS
339 c.lowerValue = rewriteValueMIPS
340 c.registers = registersMIPS[:]
341 c.gpRegMask = gpRegMaskMIPS
342 c.fpRegMask = fpRegMaskMIPS
343 c.specialRegMask = specialRegMaskMIPS
344 c.FPReg = framepointerRegMIPS
345 c.LinkReg = linkRegMIPS
346 c.hasGReg = true
347 case "riscv64":
348 c.PtrSize = 8
349 c.RegSize = 8
350 c.lowerBlock = rewriteBlockRISCV64
351 c.lowerValue = rewriteValueRISCV64
352 c.lateLowerBlock = rewriteBlockRISCV64latelower
353 c.lateLowerValue = rewriteValueRISCV64latelower
354 c.registers = registersRISCV64[:]
355 c.gpRegMask = gpRegMaskRISCV64
356 c.fpRegMask = fpRegMaskRISCV64
357 c.intParamRegs = paramIntRegRISCV64
358 c.floatParamRegs = paramFloatRegRISCV64
359 c.FPReg = framepointerRegRISCV64
360 c.hasGReg = true
361 case "wasm":
362 c.PtrSize = 8
363 c.RegSize = 8
364 c.lowerBlock = rewriteBlockWasm
365 c.lowerValue = rewriteValueWasm
366 c.registers = registersWasm[:]
367 c.gpRegMask = gpRegMaskWasm
368 c.fpRegMask = fpRegMaskWasm
369 c.fp32RegMask = fp32RegMaskWasm
370 c.fp64RegMask = fp64RegMaskWasm
371 c.simdRegMask = simdRegMaskWasm
372 c.FPReg = framepointerRegWasm
373 c.LinkReg = linkRegWasm
374 c.hasGReg = true
375 c.unalignedOK = true
376 c.haveCondSelect = true
377 default:
378 ctxt.Diag("arch %s not implemented", arch)
379 }
380 c.ctxt = ctxt
381 c.optimize = optimize
382 c.SoftFloat = softfloat
383 if softfloat {
384 c.floatParamRegs = nil
385 }
386
387 c.ABI0 = abi.NewABIConfig(0, 0, ctxt.Arch.FixedFrameSize, 0)
388 c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs), ctxt.Arch.FixedFrameSize, 1)
389
390 if ctxt.Flag_shared {
391
392
393
394 opcodeTable[Op386LoweredWB].reg.clobbers = opcodeTable[Op386LoweredWB].reg.clobbers.addReg(3)
395 }
396
397 c.buildRecipes(arch)
398
399 return c
400 }
401
402 func (c *Config) Ctxt() *obj.Link { return c.ctxt }
403
404 func (c *Config) haveByteSwap(size int64) bool {
405 switch size {
406 case 8:
407 return c.haveBswap64
408 case 4:
409 return c.haveBswap32
410 case 2:
411 return c.haveBswap16
412 default:
413 base.Fatalf("bad size %d\n", size)
414 return false
415 }
416 }
417
418 func (c *Config) buildRecipes(arch string) {
419
420 type linearCombo struct {
421
422 a, b int64
423
424 cost int
425
426
427 build func(m, x, y *Value) *Value
428 }
429
430
431 var linearCombos []linearCombo
432 r := func(a, b int64, cost int, build func(m, x, y *Value) *Value) {
433 linearCombos = append(linearCombos, linearCombo{a: a, b: b, cost: cost, build: build})
434 }
435 var mulCost int
436 switch arch {
437 case "amd64":
438
439
440
441
442
443
444 mulCost = 30
445
446 r(1, 1, 10,
447 func(m, x, y *Value) *Value {
448 v := m.Block.NewValue2(m.Pos, OpAMD64ADDQ, m.Type, x, y)
449 if m.Type.Size() == 4 {
450 v.Op = OpAMD64ADDL
451 }
452 return v
453 })
454
455 r(-1, 0, 11,
456 func(m, x, y *Value) *Value {
457 v := m.Block.NewValue1(m.Pos, OpAMD64NEGQ, m.Type, x)
458 if m.Type.Size() == 4 {
459 v.Op = OpAMD64NEGL
460 }
461 return v
462 })
463
464 r(1, -1, 11,
465 func(m, x, y *Value) *Value {
466 v := m.Block.NewValue2(m.Pos, OpAMD64SUBQ, m.Type, x, y)
467 if m.Type.Size() == 4 {
468 v.Op = OpAMD64SUBL
469 }
470 return v
471 })
472
473 r(1, 2, 10,
474 func(m, x, y *Value) *Value {
475 v := m.Block.NewValue2(m.Pos, OpAMD64LEAQ2, m.Type, x, y)
476 if m.Type.Size() == 4 {
477 v.Op = OpAMD64LEAL2
478 }
479 return v
480 })
481 r(1, 4, 10,
482 func(m, x, y *Value) *Value {
483 v := m.Block.NewValue2(m.Pos, OpAMD64LEAQ4, m.Type, x, y)
484 if m.Type.Size() == 4 {
485 v.Op = OpAMD64LEAL4
486 }
487 return v
488 })
489 r(1, 8, 10,
490 func(m, x, y *Value) *Value {
491 v := m.Block.NewValue2(m.Pos, OpAMD64LEAQ8, m.Type, x, y)
492 if m.Type.Size() == 4 {
493 v.Op = OpAMD64LEAL8
494 }
495 return v
496 })
497
498 for i := 2; i < 64; i++ {
499 r(1<<i, 0, 11,
500 func(m, x, y *Value) *Value {
501 v := m.Block.NewValue1I(m.Pos, OpAMD64SHLQconst, m.Type, int64(i), x)
502 if m.Type.Size() == 4 {
503 v.Op = OpAMD64SHLLconst
504 }
505 return v
506 })
507 }
508
509 case "arm64":
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524 mulCost = 35
525
526 r(1, 1, 10,
527 func(m, x, y *Value) *Value {
528 return m.Block.NewValue2(m.Pos, OpARM64ADD, m.Type, x, y)
529 })
530
531 r(-1, 0, 10,
532 func(m, x, y *Value) *Value {
533 return m.Block.NewValue1(m.Pos, OpARM64NEG, m.Type, x)
534 })
535
536 r(1, -1, 10,
537 func(m, x, y *Value) *Value {
538 return m.Block.NewValue2(m.Pos, OpARM64SUB, m.Type, x, y)
539 })
540
541 for i := 1; i < 64; i++ {
542 c := 10
543 if i == 1 {
544
545
546
547 c--
548 }
549 r(1<<i, 0, c,
550 func(m, x, y *Value) *Value {
551 return m.Block.NewValue1I(m.Pos, OpARM64SLLconst, m.Type, int64(i), x)
552 })
553 }
554
555 for i := 1; i < 64; i++ {
556 c := 20
557 if i > 4 {
558 c++
559 }
560 r(1, 1<<i, c,
561 func(m, x, y *Value) *Value {
562 return m.Block.NewValue2I(m.Pos, OpARM64ADDshiftLL, m.Type, int64(i), x, y)
563 })
564 }
565
566 for i := 1; i < 64; i++ {
567 c := 20
568 if i > 4 {
569 c++
570 }
571 r(-1<<i, 0, c,
572 func(m, x, y *Value) *Value {
573 return m.Block.NewValue1I(m.Pos, OpARM64NEGshiftLL, m.Type, int64(i), x)
574 })
575 }
576
577 for i := 1; i < 64; i++ {
578 c := 20
579 if i > 4 {
580 c++
581 }
582 r(1, -1<<i, c,
583 func(m, x, y *Value) *Value {
584 return m.Block.NewValue2I(m.Pos, OpARM64SUBshiftLL, m.Type, int64(i), x, y)
585 })
586 }
587 case "loong64":
588
589
590
591
592 mulCost = 45
593
594
595 r(1, 1, 10,
596 func(m, x, y *Value) *Value {
597 return m.Block.NewValue2(m.Pos, OpLOONG64ADDV, m.Type, x, y)
598 })
599
600 r(-1, 0, 10,
601 func(m, x, y *Value) *Value {
602 return m.Block.NewValue1(m.Pos, OpLOONG64NEGV, m.Type, x)
603 })
604
605 r(1, -1, 10,
606 func(m, x, y *Value) *Value {
607 return m.Block.NewValue2(m.Pos, OpLOONG64SUBV, m.Type, x, y)
608 })
609
610
611 for i := 1; i < 64; i++ {
612 c := 10
613 if i == 1 {
614
615
616
617 c--
618 }
619 r(1<<i, 0, c,
620 func(m, x, y *Value) *Value {
621 return m.Block.NewValue1I(m.Pos, OpLOONG64SLLVconst, m.Type, int64(i), x)
622 })
623 }
624
625
626 for i := 1; i < 5; i++ {
627 c := 10
628 r(1, 1<<i, c,
629 func(m, x, y *Value) *Value {
630 return m.Block.NewValue2I(m.Pos, OpLOONG64ADDshiftLLV, m.Type, int64(i), x, y)
631 })
632 }
633 }
634
635 c.mulRecipes = map[int64]mulRecipe{}
636
637
638
639 for _, combo := range linearCombos {
640 x := combo.a + combo.b
641 cost := combo.cost
642 old := c.mulRecipes[x]
643 if (old.build == nil || cost < old.cost) && cost < mulCost {
644 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
645 return combo.build(m, v, v)
646 }}
647 }
648 }
649
650
651
652
653
654
655
656
657 for _, inner := range linearCombos {
658 for _, outer := range linearCombos {
659 x := (inner.a + inner.b) * (outer.a + outer.b)
660 cost := inner.cost + outer.cost
661 old := c.mulRecipes[x]
662 if (old.build == nil || cost < old.cost) && cost < mulCost {
663 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
664 v = inner.build(m, v, v)
665 return outer.build(m, v, v)
666 }}
667 }
668 }
669 }
670
671
672 for _, inner := range linearCombos {
673 for _, outer := range linearCombos {
674 x := outer.a + outer.b*(inner.a+inner.b)
675 cost := inner.cost + outer.cost
676 old := c.mulRecipes[x]
677 if (old.build == nil || cost < old.cost) && cost < mulCost {
678 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
679 return outer.build(m, v, inner.build(m, v, v))
680 }}
681 }
682 }
683 }
684
685
686 for _, inner := range linearCombos {
687 for _, outer := range linearCombos {
688 x := outer.a*(inner.a+inner.b) + outer.b
689 cost := inner.cost + outer.cost
690 old := c.mulRecipes[x]
691 if (old.build == nil || cost < old.cost) && cost < mulCost {
692 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
693 return outer.build(m, inner.build(m, v, v), v)
694 }}
695 }
696 }
697 }
698
699
700 if arch == "loong64" {
701
702
703
704
705
706 for _, first := range linearCombos {
707 for _, second := range linearCombos {
708 for _, third := range linearCombos {
709 x := third.a*(first.a+first.b) + third.b*(second.a+second.b)
710 cost := first.cost + second.cost + third.cost
711 old := c.mulRecipes[x]
712 if (old.build == nil || cost < old.cost) && cost < mulCost {
713 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
714 v1 := first.build(m, v, v)
715 v2 := second.build(m, v, v)
716 return third.build(m, v1, v2)
717 }}
718 }
719 }
720 }
721 }
722
723
724 for _, first := range linearCombos {
725 for _, second := range linearCombos {
726 for _, third := range linearCombos {
727 x := third.a*(second.a*(first.a+first.b)+second.b) + third.b
728 cost := first.cost + second.cost + third.cost
729 old := c.mulRecipes[x]
730 if (old.build == nil || cost < old.cost) && cost < mulCost {
731 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
732 v1 := first.build(m, v, v)
733 v2 := second.build(m, v1, v)
734 return third.build(m, v2, v)
735 }}
736 }
737 }
738 }
739 }
740 }
741
742
743
744 delete(c.mulRecipes, 0)
745 delete(c.mulRecipes, 1)
746
747
748
749
750
751
752
753 }
754
View as plain text