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