1
2
3
4
5 package generic
6
7 import (
8 "fmt"
9 "math"
10 "math/bits"
11 "strings"
12
13 "cmd/compile/internal/base"
14 "cmd/compile/internal/ir"
15 "cmd/compile/internal/reflectdata"
16 "cmd/compile/internal/rttype"
17 "cmd/compile/internal/ssa"
18 "cmd/compile/internal/ssa/ssaop"
19 "cmd/compile/internal/typecheck"
20 "cmd/compile/internal/types"
21 "cmd/internal/obj"
22 "cmd/internal/objabi"
23 )
24
25 func addToSub(op ssaop.Op) ssaop.Op {
26 switch op {
27 case ssaop.OpAdd64:
28 return ssaop.OpSub64
29 case ssaop.OpAdd32:
30 return ssaop.OpSub32
31 case ssaop.OpAdd16:
32 return ssaop.OpSub16
33 case ssaop.OpAdd8:
34 return ssaop.OpSub8
35 default:
36 panic(fmt.Sprintf("unexpected op %v", op))
37 }
38 }
39
40 func bitsAdd64(x, y, carry int64) (r struct{ sum, carry int64 }) {
41 s, c := bits.Add64(uint64(x), uint64(y), uint64(carry))
42 r.sum, r.carry = int64(s), int64(c)
43 return
44 }
45
46 func bitsMulU32(x, y int32) (r struct{ hi, lo int32 }) {
47 hi, lo := bits.Mul32(uint32(x), uint32(y))
48 r.hi, r.lo = int32(hi), int32(lo)
49 return
50 }
51
52 func bitsMulU64(x, y int64) (r struct{ hi, lo int64 }) {
53 hi, lo := bits.Mul64(uint64(x), uint64(y))
54 r.hi, r.lo = int64(hi), int64(lo)
55 return
56 }
57
58 func bitsDiv128u(hi, lo, y int64) (r struct{ quo, rem int64 }) {
59 q, rem := bits.Div64(uint64(hi), uint64(lo), uint64(y))
60 r.quo, r.rem = int64(q), int64(rem)
61 return
62 }
63
64
65 func bool2int(x bool) int {
66 var b int
67 if x {
68 b = 1
69 }
70 return b
71 }
72
73
74 func canLoadUnaligned(c *ssa.Config) bool {
75 return c.Ctxt.Arch.Alignment == 1
76 }
77
78
79
80 func canRotate(c *ssa.Config, bits int64) bool {
81 if bits > c.PtrSize*8 {
82
83 return false
84 }
85 switch c.Arch {
86 case "386", "amd64", "arm64", "loong64", "riscv64":
87 return true
88 case "arm", "s390x", "ppc64", "ppc64le", "wasm":
89 return bits >= 32
90 default:
91 return false
92 }
93 }
94
95 func copyCompatibleType(t1, t2 *types.Type) bool {
96 if t1.Size() != t2.Size() {
97 return false
98 }
99 if t1.IsInteger() {
100 return t2.IsInteger()
101 }
102 if ssa.IsPtr(t1) {
103 return ssa.IsPtr(t2)
104 }
105 return t1.Compare(t2) == types.CMPeq
106 }
107
108 func devirtLECall(v *ssa.Value, sym *obj.LSym) *ssa.Value {
109 v.Op = ssaop.OpStaticLECall
110 auxcall := v.Aux.(*ssa.AuxCall)
111 auxcall.Fn = sym
112
113 v.Args[0].Uses--
114 copy(v.Args[0:], v.Args[1:])
115 v.Args[len(v.Args)-1] = nil
116 v.Args = v.Args[:len(v.Args)-1]
117 if f := v.Block.Func; f.Pass.Debug > 0 {
118 f.Warnl(v.Pos, "de-virtualizing call")
119 }
120 return v
121 }
122
123
124
125 func hasSmallRotate(c *ssa.Config) bool {
126 switch c.Arch {
127 case "amd64", "386":
128 return true
129 default:
130 return false
131 }
132 }
133
134 func invertibleBool(op ssaop.Op) bool {
135 switch op {
136 case ssaop.OpLess64, ssaop.OpLess32, ssaop.OpLess16, ssaop.OpLess8,
137 ssaop.OpLeq64, ssaop.OpLeq32, ssaop.OpLeq16, ssaop.OpLeq8,
138 ssaop.OpLess64U, ssaop.OpLess32U, ssaop.OpLess16U, ssaop.OpLess8U,
139 ssaop.OpLeq64U, ssaop.OpLeq32U, ssaop.OpLeq16U, ssaop.OpLeq8U,
140 ssaop.OpEq64, ssaop.OpEq32, ssaop.OpEq16, ssaop.OpEq8,
141 ssaop.OpNeq64, ssaop.OpNeq32, ssaop.OpNeq16, ssaop.OpNeq8,
142 ssaop.OpNot:
143 return true
144 default:
145 return false
146 }
147 }
148
149 func isDictArgSym(sym ssa.Sym) bool {
150 return sym.(*ir.Name).Sym().Name == typecheck.LocalDictName
151 }
152
153
154
155
156 func isDirectAndComparableIface(v *ssa.Value) bool {
157 return isDirectAndComparableIface1(v, 9)
158 }
159
160
161 func isDirectAndComparableIface1(v *ssa.Value, depth int) bool {
162 if depth == 0 {
163 return false
164 }
165 switch v.Op {
166 case ssaop.OpITab:
167 return isDirectAndComparableIface2(v.Args[0], depth-1)
168 case ssaop.OpAddr:
169 lsym := v.Aux.(*obj.LSym)
170 if ii := lsym.ItabInfo(); ii != nil {
171 t := ii.Type.(*types.Type)
172 return types.IsDirectIface(t) && types.IsComparable(t)
173 }
174 case ssaop.OpConstNil:
175
176
177 return true
178 }
179 return false
180 }
181
182
183 func isDirectAndComparableIface2(v *ssa.Value, depth int) bool {
184 if depth == 0 {
185 return false
186 }
187 switch v.Op {
188 case ssaop.OpIMake:
189 return isDirectAndComparableIface1(v.Args[0], depth-1)
190 case ssaop.OpPhi:
191 for _, a := range v.Args {
192 if !isDirectAndComparableIface2(a, depth-1) {
193 return false
194 }
195 }
196 return true
197 }
198 return false
199 }
200
201
202
203
204 func isDirectAndComparableType(v *ssa.Value) bool {
205 return isDirectAndComparableType1(v)
206 }
207
208
209 func isDirectAndComparableType1(v *ssa.Value) bool {
210 switch v.Op {
211 case ssaop.OpITab:
212 return isDirectAndComparableType2(v.Args[0])
213 case ssaop.OpAddr:
214 lsym := v.Aux.(*obj.LSym)
215 if ti := lsym.TypeInfo(); ti != nil {
216 t := ti.Type.(*types.Type)
217 return types.IsDirectIface(t) && types.IsComparable(t)
218 }
219 }
220 return false
221 }
222
223
224 func isDirectAndComparableType2(v *ssa.Value) bool {
225 switch v.Op {
226 case ssaop.OpIMake:
227 return isDirectAndComparableType1(v.Args[0])
228 }
229 return false
230 }
231
232
233
234 func isFixedLoad(v *ssa.Value, sym ssa.Sym, off int64) bool {
235 lsym := sym.(*obj.LSym)
236 if (v.Type.IsPtrShaped() || v.Type.IsUintptr()) && lsym.Type == objabi.SRODATA {
237 for _, r := range lsym.R {
238 if (r.Type == objabi.R_ADDR || r.Type == objabi.R_WEAKADDR) && int64(r.Off) == off && r.Add == 0 {
239 return true
240 }
241 }
242 return false
243 }
244
245 if ti := lsym.TypeInfo(); ti != nil {
246
247
248
249
250 t := ti.Type.(*types.Type)
251
252 for _, f := range rttype.Type.Fields() {
253 if f.Offset == off && copyCompatibleType(v.Type, f.Type) {
254 switch f.Sym.Name {
255 case "Size_", "PtrBytes", "Hash", "Kind_", "GCData":
256 return true
257 case "TFlag":
258 return t.TFlagComputed()
259 default:
260
261 return false
262 }
263 }
264 }
265
266 if t.IsPtr() && off == rttype.PtrType.OffsetOf("Elem") {
267 return true
268 }
269
270 return false
271 }
272
273 return false
274 }
275
276 func isInlinableMemclr(c *ssa.Config, sz int64) bool {
277 if sz < 0 {
278 return false
279 }
280
281
282 switch c.Arch {
283 case "amd64", "arm64":
284 return true
285 case "ppc64le", "ppc64", "loong64":
286 return sz < 512
287 }
288 return false
289 }
290
291 func isMalloc(aux ssa.Aux) bool {
292 return ssa.IsNewObjectCall(aux) || ssa.IsSpecializedMalloc(aux)
293 }
294
295
296
297
298 func isNonNegative(v *ssa.Value) bool {
299 if !v.Type.IsInteger() {
300 v.Fatalf("isNonNegative bad type: %v", v.Type)
301 }
302
303
304
305
306 switch v.Op {
307 case ssaop.OpConst64:
308 return v.AuxInt >= 0
309
310 case ssaop.OpConst32:
311 return int32(v.AuxInt) >= 0
312
313 case ssaop.OpConst16:
314 return int16(v.AuxInt) >= 0
315
316 case ssaop.OpConst8:
317 return int8(v.AuxInt) >= 0
318
319 case ssaop.OpStringLen, ssaop.OpSliceLen, ssaop.OpSliceCap,
320 ssaop.OpZeroExt8to64, ssaop.OpZeroExt16to64, ssaop.OpZeroExt32to64,
321 ssaop.OpZeroExt8to32, ssaop.OpZeroExt16to32, ssaop.OpZeroExt8to16,
322 ssaop.OpCtz64, ssaop.OpCtz32, ssaop.OpCtz16, ssaop.OpCtz8,
323 ssaop.OpCtz64NonZero, ssaop.OpCtz32NonZero, ssaop.OpCtz16NonZero, ssaop.OpCtz8NonZero,
324 ssaop.OpBitLen64, ssaop.OpBitLen32, ssaop.OpBitLen16, ssaop.OpBitLen8:
325 return true
326
327 case ssaop.OpRsh64Ux64, ssaop.OpRsh32Ux64:
328 by := v.Args[1]
329 return by.Op == ssaop.OpConst64 && by.AuxInt > 0
330
331 case ssaop.OpRsh64x64, ssaop.OpRsh32x64, ssaop.OpRsh8x64, ssaop.OpRsh16x64, ssaop.OpRsh32x32, ssaop.OpRsh64x32,
332 ssaop.OpSignExt32to64, ssaop.OpSignExt16to64, ssaop.OpSignExt8to64, ssaop.OpSignExt16to32, ssaop.OpSignExt8to32:
333 return isNonNegative(v.Args[0])
334
335 case ssaop.OpAnd64, ssaop.OpAnd32, ssaop.OpAnd16, ssaop.OpAnd8:
336 return isNonNegative(v.Args[0]) || isNonNegative(v.Args[1])
337
338 case ssaop.OpMod64, ssaop.OpMod32, ssaop.OpMod16, ssaop.OpMod8,
339 ssaop.OpDiv64, ssaop.OpDiv32, ssaop.OpDiv16, ssaop.OpDiv8,
340 ssaop.OpOr64, ssaop.OpOr32, ssaop.OpOr16, ssaop.OpOr8,
341 ssaop.OpXor64, ssaop.OpXor32, ssaop.OpXor16, ssaop.OpXor8:
342 return isNonNegative(v.Args[0]) && isNonNegative(v.Args[1])
343
344
345
346 }
347 return false
348 }
349
350 func isStackPtr(v *ssa.Value) bool {
351 for v.Op == ssaop.OpOffPtr || v.Op == ssaop.OpAddPtr {
352 v = v.Args[0]
353 }
354 return v.Op == ssaop.OpSP || v.Op == ssaop.OpLocalAddr
355 }
356
357
358 func needRaceCleanup(sym *ssa.AuxCall, v *ssa.Value) bool {
359 f := v.Block.Func
360 if !f.Config.Race {
361 return false
362 }
363 if !ssa.IsSameCall(sym, "runtime.racefuncenter") && !ssa.IsSameCall(sym, "runtime.racefuncexit") {
364 return false
365 }
366 for _, b := range f.Blocks {
367 for _, v := range b.Values {
368 switch v.Op {
369 case ssaop.OpStaticCall, ssaop.OpStaticLECall:
370
371
372 s := v.Aux.(*ssa.AuxCall).Fn.String()
373 switch s {
374 case "runtime.racefuncenter", "runtime.racefuncexit",
375 "runtime.panicdivide", "runtime.panicwrap",
376 "runtime.panicshift":
377 continue
378 }
379
380
381 return false
382 case ssaop.OpPanicBounds, ssaop.OpPanicExtend:
383
384 case ssaop.OpClosureCall, ssaop.OpInterCall, ssaop.OpClosureLECall, ssaop.OpInterLECall:
385
386 return false
387 }
388 }
389 }
390 if ssa.IsSameCall(sym, "runtime.racefuncenter") {
391
392
393 if v.Args[0].Op != ssaop.OpStore {
394 if v.Op == ssaop.OpStaticLECall {
395
396 return true
397 }
398 return false
399 }
400 mem := v.Args[0].Args[2]
401 v.Args[0].Reset(ssaop.OpCopy)
402 v.Args[0].AddArg(mem)
403 }
404 return true
405 }
406
407 func nlz16(x int16) int { return bits.LeadingZeros16(uint16(x)) }
408
409 func nlz32(x int32) int { return bits.LeadingZeros32(uint32(x)) }
410
411
412 func nlz64(x int64) int { return bits.LeadingZeros64(uint64(x)) }
413
414 func nlz8(x int8) int { return bits.LeadingZeros8(uint8(x)) }
415
416 func ntz16(x int16) int { return bits.TrailingZeros16(uint16(x)) }
417
418 func ntz32(x int32) int { return bits.TrailingZeros32(uint32(x)) }
419
420 func ntz8(x int8) int { return bits.TrailingZeros8(uint8(x)) }
421
422
423 func reciprocalExact32(c float32) bool {
424 b := math.Float32bits(c)
425 man := b & (1<<23 - 1)
426 if man != 0 {
427 return false
428 }
429 exp := b >> 23 & (1<<8 - 1)
430
431
432 switch exp {
433 case 0:
434 return false
435 case 0xff:
436 return false
437 case 0xfe:
438 return false
439 default:
440 return true
441 }
442 }
443
444
445 func reciprocalExact64(c float64) bool {
446 b := math.Float64bits(c)
447 man := b & (1<<52 - 1)
448 if man != 0 {
449 return false
450 }
451 exp := b >> 52 & (1<<11 - 1)
452
453
454 switch exp {
455 case 0:
456 return false
457 case 0x7ff:
458 return false
459 case 0x7fe:
460 return false
461 default:
462 return true
463 }
464 }
465
466
467
468
469 func registerizable(b *ssa.Block, typ *types.Type) bool {
470 if typ.IsPtrShaped() || typ.IsFloat() || typ.IsBoolean() {
471 return true
472 }
473 if typ.IsInteger() {
474 return typ.Size() <= b.Func.Config.RegSize
475 }
476 return false
477 }
478
479
480
481 func resetCopy(v *ssa.Value, arg *ssa.Value) bool {
482 v.Reset(ssaop.OpCopy)
483 v.AddArg(arg)
484 return true
485 }
486
487
488
489 func rewriteCondSelectIntoMath(config *ssa.Config, op ssaop.Op, constant int64) bool {
490
491
492
493
494 switch config.Arch {
495 case "arm64":
496 switch op {
497 case ssaop.OpAdd64, ssaop.OpAdd32, ssaop.OpAdd16, ssaop.OpAdd8:
498 if constant == 1 {
499 return false
500 }
501 fallthrough
502 default:
503
504
505 return ssa.IsPowerOfTwo(uint64(constant))
506 }
507 default:
508 return ssa.IsPowerOfTwo(uint64(constant))
509 }
510 }
511
512
513 func rewriteFixedLoad(v *ssa.Value, sym ssa.Sym, sb *ssa.Value, off int64) *ssa.Value {
514 b := v.Block
515 f := b.Func
516
517 lsym := sym.(*obj.LSym)
518 if (v.Type.IsPtrShaped() || v.Type.IsUintptr()) && lsym.Type == objabi.SRODATA {
519 for _, r := range lsym.R {
520 if (r.Type == objabi.R_ADDR || r.Type == objabi.R_WEAKADDR) && int64(r.Off) == off && r.Add == 0 {
521 if strings.HasPrefix(r.Sym.Name, "type:") {
522
523
524
525
526
527 reflectdata.MarkTypeSymUsedInInterface(r.Sym, f.Fe.Func().Linksym())
528 } else if strings.HasPrefix(r.Sym.Name, "go:itab") {
529
530
531 reflectdata.MarkTypeSymUsedInInterface(r.Sym, f.Fe.Func().Linksym())
532 }
533 v.Reset(ssaop.OpAddr)
534 v.Aux = ssa.SymToAux(r.Sym)
535 v.AddArg(sb)
536 return v
537 }
538 }
539 base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
540 }
541
542 if ti := lsym.TypeInfo(); ti != nil {
543
544
545
546
547 t := ti.Type.(*types.Type)
548
549 ptrSizedOpConst := ssaop.OpConst64
550 if f.Config.PtrSize == 4 {
551 ptrSizedOpConst = ssaop.OpConst32
552 }
553
554 for _, f := range rttype.Type.Fields() {
555 if f.Offset == off && copyCompatibleType(v.Type, f.Type) {
556 switch f.Sym.Name {
557 case "Size_":
558 v.Reset(ptrSizedOpConst)
559 v.AuxInt = t.Size()
560 return v
561 case "PtrBytes":
562 v.Reset(ptrSizedOpConst)
563 v.AuxInt = types.PtrDataSize(t)
564 return v
565 case "Hash":
566 v.Reset(ssaop.OpConst32)
567 v.AuxInt = int64(int32(types.TypeHash(t)))
568 return v
569 case "TFlag":
570 v.Reset(ssaop.OpConst8)
571 v.AuxInt = int64(t.TFlag())
572 return v
573 case "Kind_":
574 v.Reset(ssaop.OpConst8)
575 v.AuxInt = int64(int8(reflectdata.ABIKindOfType(t)))
576 return v
577 case "GCData":
578 gcdata, _ := reflectdata.GCSym(t, true)
579 v.Reset(ssaop.OpAddr)
580 v.Aux = ssa.SymToAux(gcdata)
581 v.AddArg(sb)
582 return v
583 default:
584 base.Fatalf("unknown field %s for fixedLoad of %s at offset %d", f.Sym.Name, lsym.Name, off)
585 }
586 }
587 }
588
589 if t.IsPtr() && off == rttype.PtrType.OffsetOf("Elem") {
590 elemSym := reflectdata.TypeLinksym(t.Elem())
591 reflectdata.MarkTypeSymUsedInInterface(elemSym, f.Fe.Func().Linksym())
592 v.Reset(ssaop.OpAddr)
593 v.Aux = ssa.SymToAux(elemSym)
594 v.AddArg(sb)
595 return v
596 }
597
598 base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
599 }
600
601 base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
602 return nil
603 }
604
605 func rewriteStructLoad(v *ssa.Value) *ssa.Value {
606 b := v.Block
607 ptr := v.Args[0]
608 mem := v.Args[1]
609
610 t := v.Type
611 args := make([]*ssa.Value, t.NumFields())
612 for i := range args {
613 ft := t.FieldType(i)
614 addr := b.NewValue1I(v.Pos, ssaop.OpOffPtr, ft.PtrTo(), t.FieldOff(i), ptr)
615 args[i] = b.NewValue2(v.Pos, ssaop.OpLoad, ft, addr, mem)
616 }
617
618 v.Reset(ssaop.OpStructMake)
619 v.AddArgs(args...)
620 return v
621 }
622
623
624 func symIsROZero(sym ssa.Sym) bool {
625 lsym := sym.(*obj.LSym)
626 if lsym.Type != objabi.SRODATA || len(lsym.R) != 0 {
627 return false
628 }
629 for _, b := range lsym.P {
630 if b != 0 {
631 return false
632 }
633 }
634 return true
635 }
636
637
638 func uaddOvf(a, b int64) bool {
639 return uint64(a)+uint64(b) < uint64(a)
640 }
641
642
643
644 func warnRule(cond bool, v *ssa.Value, s string) bool {
645 if pos := v.Pos; pos.Line() > 1 && cond {
646 v.Block.Func.Warnl(pos, s)
647 }
648 return true
649 }
650
651 func bitsSub64(x, y, borrow int64) (r struct{ diff, borrow int64 }) {
652 d, b := bits.Sub64(uint64(x), uint64(y), uint64(borrow))
653 r.diff, r.borrow = int64(d), int64(b)
654 return
655 }
656
657 func modularMultiplicativeInverse(x uint64) (y uint64) {
658 if x%2 != 1 {
659 panic("even numbers in a power-of-two modulus do not have a multiplicative inverse")
660 }
661
662 y = x
663
664
665 y *= 2 - x*y
666 y *= 2 - x*y
667 y *= 2 - x*y
668 y *= 2 - x*y
669 y *= 2 - x*y
670 return
671 }
672
View as plain text