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.registers = registersMIPS64[:]
275 c.gpRegMask = gpRegMaskMIPS64
276 c.fpRegMask = fpRegMaskMIPS64
277 c.specialRegMask = specialRegMaskMIPS64
278 c.FPReg = framepointerRegMIPS64
279 c.LinkReg = linkRegMIPS64
280 c.hasGReg = true
281 case "loong64":
282 c.PtrSize = 8
283 c.RegSize = 8
284 c.lowerBlock = rewriteBlockLOONG64
285 c.lowerValue = rewriteValueLOONG64
286 c.lateLowerBlock = rewriteBlockLOONG64latelower
287 c.lateLowerValue = rewriteValueLOONG64latelower
288 c.registers = registersLOONG64[:]
289 c.gpRegMask = gpRegMaskLOONG64
290 c.fpRegMask = fpRegMaskLOONG64
291 c.intParamRegs = paramIntRegLOONG64
292 c.floatParamRegs = paramFloatRegLOONG64
293 c.FPReg = framepointerRegLOONG64
294 c.LinkReg = linkRegLOONG64
295 c.hasGReg = true
296 c.unalignedOK = true
297 case "s390x":
298 c.PtrSize = 8
299 c.RegSize = 8
300 c.lowerBlock = rewriteBlockS390X
301 c.lowerValue = rewriteValueS390X
302 c.registers = registersS390X[:]
303 c.gpRegMask = gpRegMaskS390X
304 c.fpRegMask = fpRegMaskS390X
305 c.FPReg = framepointerRegS390X
306 c.LinkReg = linkRegS390X
307 c.hasGReg = true
308 c.BigEndian = true
309 c.unalignedOK = true
310 c.haveBswap64 = true
311 c.haveBswap32 = true
312 c.haveBswap16 = true
313 case "mips":
314 c.BigEndian = true
315 fallthrough
316 case "mipsle":
317 c.PtrSize = 4
318 c.RegSize = 4
319 c.lowerBlock = rewriteBlockMIPS
320 c.lowerValue = rewriteValueMIPS
321 c.registers = registersMIPS[:]
322 c.gpRegMask = gpRegMaskMIPS
323 c.fpRegMask = fpRegMaskMIPS
324 c.specialRegMask = specialRegMaskMIPS
325 c.FPReg = framepointerRegMIPS
326 c.LinkReg = linkRegMIPS
327 c.hasGReg = true
328 case "riscv64":
329 c.PtrSize = 8
330 c.RegSize = 8
331 c.lowerBlock = rewriteBlockRISCV64
332 c.lowerValue = rewriteValueRISCV64
333 c.lateLowerBlock = rewriteBlockRISCV64latelower
334 c.lateLowerValue = rewriteValueRISCV64latelower
335 c.registers = registersRISCV64[:]
336 c.gpRegMask = gpRegMaskRISCV64
337 c.fpRegMask = fpRegMaskRISCV64
338 c.intParamRegs = paramIntRegRISCV64
339 c.floatParamRegs = paramFloatRegRISCV64
340 c.FPReg = framepointerRegRISCV64
341 c.hasGReg = true
342 case "wasm":
343 c.PtrSize = 8
344 c.RegSize = 8
345 c.lowerBlock = rewriteBlockWasm
346 c.lowerValue = rewriteValueWasm
347 c.registers = registersWasm[:]
348 c.gpRegMask = gpRegMaskWasm
349 c.fpRegMask = fpRegMaskWasm
350 c.fp32RegMask = fp32RegMaskWasm
351 c.fp64RegMask = fp64RegMaskWasm
352 c.FPReg = framepointerRegWasm
353 c.LinkReg = linkRegWasm
354 c.hasGReg = true
355 c.useAvg = false
356 c.useHmul = false
357 default:
358 ctxt.Diag("arch %s not implemented", arch)
359 }
360 c.ctxt = ctxt
361 c.optimize = optimize
362 c.SoftFloat = softfloat
363 if softfloat {
364 c.floatParamRegs = nil
365 }
366
367 c.ABI0 = abi.NewABIConfig(0, 0, ctxt.Arch.FixedFrameSize, 0)
368 c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs), ctxt.Arch.FixedFrameSize, 1)
369
370 if ctxt.Flag_shared {
371
372
373
374 opcodeTable[Op386LoweredWB].reg.clobbers |= 1 << 3
375 }
376
377 c.buildRecipes(arch)
378
379 return c
380 }
381
382 func (c *Config) Ctxt() *obj.Link { return c.ctxt }
383
384 func (c *Config) haveByteSwap(size int64) bool {
385 switch size {
386 case 8:
387 return c.haveBswap64
388 case 4:
389 return c.haveBswap32
390 case 2:
391 return c.haveBswap16
392 default:
393 base.Fatalf("bad size %d\n", size)
394 return false
395 }
396 }
397
398 func (c *Config) buildRecipes(arch string) {
399
400 type linearCombo struct {
401
402 a, b int64
403
404 cost int
405
406
407 build func(m, x, y *Value) *Value
408 }
409
410
411 var linearCombos []linearCombo
412 r := func(a, b int64, cost int, build func(m, x, y *Value) *Value) {
413 linearCombos = append(linearCombos, linearCombo{a: a, b: b, cost: cost, build: build})
414 }
415 var mulCost int
416 switch arch {
417 case "amd64":
418
419
420
421
422
423
424 mulCost = 30
425
426 r(1, 1, 10,
427 func(m, x, y *Value) *Value {
428 v := m.Block.NewValue2(m.Pos, OpAMD64ADDQ, m.Type, x, y)
429 if m.Type.Size() == 4 {
430 v.Op = OpAMD64ADDL
431 }
432 return v
433 })
434
435 r(-1, 0, 11,
436 func(m, x, y *Value) *Value {
437 v := m.Block.NewValue1(m.Pos, OpAMD64NEGQ, m.Type, x)
438 if m.Type.Size() == 4 {
439 v.Op = OpAMD64NEGL
440 }
441 return v
442 })
443
444 r(1, -1, 11,
445 func(m, x, y *Value) *Value {
446 v := m.Block.NewValue2(m.Pos, OpAMD64SUBQ, m.Type, x, y)
447 if m.Type.Size() == 4 {
448 v.Op = OpAMD64SUBL
449 }
450 return v
451 })
452
453 r(1, 2, 10,
454 func(m, x, y *Value) *Value {
455 v := m.Block.NewValue2(m.Pos, OpAMD64LEAQ2, m.Type, x, y)
456 if m.Type.Size() == 4 {
457 v.Op = OpAMD64LEAL2
458 }
459 return v
460 })
461 r(1, 4, 10,
462 func(m, x, y *Value) *Value {
463 v := m.Block.NewValue2(m.Pos, OpAMD64LEAQ4, m.Type, x, y)
464 if m.Type.Size() == 4 {
465 v.Op = OpAMD64LEAL4
466 }
467 return v
468 })
469 r(1, 8, 10,
470 func(m, x, y *Value) *Value {
471 v := m.Block.NewValue2(m.Pos, OpAMD64LEAQ8, m.Type, x, y)
472 if m.Type.Size() == 4 {
473 v.Op = OpAMD64LEAL8
474 }
475 return v
476 })
477
478 for i := 2; i < 64; i++ {
479 r(1<<i, 0, 11,
480 func(m, x, y *Value) *Value {
481 v := m.Block.NewValue1I(m.Pos, OpAMD64SHLQconst, m.Type, int64(i), x)
482 if m.Type.Size() == 4 {
483 v.Op = OpAMD64SHLLconst
484 }
485 return v
486 })
487 }
488
489 case "arm64":
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504 mulCost = 35
505
506 r(1, 1, 10,
507 func(m, x, y *Value) *Value {
508 return m.Block.NewValue2(m.Pos, OpARM64ADD, m.Type, x, y)
509 })
510
511 r(-1, 0, 10,
512 func(m, x, y *Value) *Value {
513 return m.Block.NewValue1(m.Pos, OpARM64NEG, m.Type, x)
514 })
515
516 r(1, -1, 10,
517 func(m, x, y *Value) *Value {
518 return m.Block.NewValue2(m.Pos, OpARM64SUB, m.Type, x, y)
519 })
520
521 for i := 1; i < 64; i++ {
522 c := 10
523 if i == 1 {
524
525
526
527 c--
528 }
529 r(1<<i, 0, c,
530 func(m, x, y *Value) *Value {
531 return m.Block.NewValue1I(m.Pos, OpARM64SLLconst, m.Type, int64(i), x)
532 })
533 }
534
535 for i := 1; i < 64; i++ {
536 c := 20
537 if i > 4 {
538 c++
539 }
540 r(1, 1<<i, c,
541 func(m, x, y *Value) *Value {
542 return m.Block.NewValue2I(m.Pos, OpARM64ADDshiftLL, m.Type, int64(i), x, y)
543 })
544 }
545
546 for i := 1; i < 64; i++ {
547 c := 20
548 if i > 4 {
549 c++
550 }
551 r(-1<<i, 0, c,
552 func(m, x, y *Value) *Value {
553 return m.Block.NewValue1I(m.Pos, OpARM64NEGshiftLL, m.Type, int64(i), x)
554 })
555 }
556
557 for i := 1; i < 64; i++ {
558 c := 20
559 if i > 4 {
560 c++
561 }
562 r(1, -1<<i, c,
563 func(m, x, y *Value) *Value {
564 return m.Block.NewValue2I(m.Pos, OpARM64SUBshiftLL, m.Type, int64(i), x, y)
565 })
566 }
567 case "loong64":
568
569
570
571
572 mulCost = 45
573
574
575 r(1, 1, 10,
576 func(m, x, y *Value) *Value {
577 return m.Block.NewValue2(m.Pos, OpLOONG64ADDV, m.Type, x, y)
578 })
579
580 r(-1, 0, 10,
581 func(m, x, y *Value) *Value {
582 return m.Block.NewValue1(m.Pos, OpLOONG64NEGV, m.Type, x)
583 })
584
585 r(1, -1, 10,
586 func(m, x, y *Value) *Value {
587 return m.Block.NewValue2(m.Pos, OpLOONG64SUBV, m.Type, x, y)
588 })
589
590
591 for i := 1; i < 64; i++ {
592 c := 10
593 if i == 1 {
594
595
596
597 c--
598 }
599 r(1<<i, 0, c,
600 func(m, x, y *Value) *Value {
601 return m.Block.NewValue1I(m.Pos, OpLOONG64SLLVconst, m.Type, int64(i), x)
602 })
603 }
604 }
605
606 c.mulRecipes = map[int64]mulRecipe{}
607
608
609
610 for _, combo := range linearCombos {
611 x := combo.a + combo.b
612 cost := combo.cost
613 old := c.mulRecipes[x]
614 if (old.build == nil || cost < old.cost) && cost < mulCost {
615 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
616 return combo.build(m, v, v)
617 }}
618 }
619 }
620
621
622
623
624
625
626
627
628 for _, inner := range linearCombos {
629 for _, outer := range linearCombos {
630 x := (inner.a + inner.b) * (outer.a + outer.b)
631 cost := inner.cost + outer.cost
632 old := c.mulRecipes[x]
633 if (old.build == nil || cost < old.cost) && cost < mulCost {
634 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
635 v = inner.build(m, v, v)
636 return outer.build(m, v, v)
637 }}
638 }
639 }
640 }
641
642
643 for _, inner := range linearCombos {
644 for _, outer := range linearCombos {
645 x := outer.a + outer.b*(inner.a+inner.b)
646 cost := inner.cost + outer.cost
647 old := c.mulRecipes[x]
648 if (old.build == nil || cost < old.cost) && cost < mulCost {
649 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
650 return outer.build(m, v, inner.build(m, v, v))
651 }}
652 }
653 }
654 }
655
656
657 for _, inner := range linearCombos {
658 for _, outer := range linearCombos {
659 x := outer.a*(inner.a+inner.b) + 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 return outer.build(m, inner.build(m, v, v), v)
665 }}
666 }
667 }
668 }
669
670
671 if arch == "loong64" {
672
673
674
675
676
677 for _, first := range linearCombos {
678 for _, second := range linearCombos {
679 for _, third := range linearCombos {
680 x := third.a*(first.a+first.b) + third.b*(second.a+second.b)
681 cost := first.cost + second.cost + third.cost
682 old := c.mulRecipes[x]
683 if (old.build == nil || cost < old.cost) && cost < mulCost {
684 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
685 v1 := first.build(m, v, v)
686 v2 := second.build(m, v, v)
687 return third.build(m, v1, v2)
688 }}
689 }
690 }
691 }
692 }
693
694
695 for _, first := range linearCombos {
696 for _, second := range linearCombos {
697 for _, third := range linearCombos {
698 x := third.a*(second.a*(first.a+first.b)+second.b) + third.b
699 cost := first.cost + second.cost + third.cost
700 old := c.mulRecipes[x]
701 if (old.build == nil || cost < old.cost) && cost < mulCost {
702 c.mulRecipes[x] = mulRecipe{cost: cost, build: func(m, v *Value) *Value {
703 v1 := first.build(m, v, v)
704 v2 := second.build(m, v1, v)
705 return third.build(m, v2, v)
706 }}
707 }
708 }
709 }
710 }
711 }
712
713
714
715 delete(c.mulRecipes, 0)
716 delete(c.mulRecipes, 1)
717
718
719
720
721
722
723
724 }
725
View as plain text