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