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