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