1
2
3
4
5 package ssagen
6
7 import (
8 "bufio"
9 "bytes"
10 "cmp"
11 "fmt"
12 "go/constant"
13 "html"
14 "internal/buildcfg"
15 "internal/goexperiment"
16 "internal/runtime/gc"
17 "os"
18 "path/filepath"
19 "slices"
20 "strings"
21
22 "cmd/compile/internal/abi"
23 "cmd/compile/internal/base"
24 "cmd/compile/internal/ir"
25 "cmd/compile/internal/liveness"
26 "cmd/compile/internal/objw"
27 "cmd/compile/internal/reflectdata"
28 "cmd/compile/internal/rttype"
29 "cmd/compile/internal/ssa"
30 "cmd/compile/internal/staticdata"
31 "cmd/compile/internal/typecheck"
32 "cmd/compile/internal/types"
33 "cmd/internal/obj"
34 "cmd/internal/objabi"
35 "cmd/internal/src"
36 "cmd/internal/sys"
37
38 rtabi "internal/abi"
39 )
40
41 var ssaConfig *ssa.Config
42 var ssaCaches []ssa.Cache
43
44 var ssaDump string
45 var ssaDir string
46 var ssaDumpStdout bool
47 var ssaDumpCFG string
48 const ssaDumpFile = "ssa.html"
49
50
51 var ssaDumpInlined []*ir.Func
52
53
54
55
56 const maxAggregatedHeapAllocation = 16
57
58 func DumpInline(fn *ir.Func) {
59 if ssaDump != "" && ssaDump == ir.FuncName(fn) {
60 ssaDumpInlined = append(ssaDumpInlined, fn)
61 }
62 }
63
64 func InitEnv() {
65 ssaDump = os.Getenv("GOSSAFUNC")
66 ssaDir = os.Getenv("GOSSADIR")
67 if ssaDump != "" {
68 if strings.HasSuffix(ssaDump, "+") {
69 ssaDump = ssaDump[:len(ssaDump)-1]
70 ssaDumpStdout = true
71 }
72 spl := strings.Split(ssaDump, ":")
73 if len(spl) > 1 {
74 ssaDump = spl[0]
75 ssaDumpCFG = spl[1]
76 }
77 }
78 }
79
80 func InitConfig() {
81 types_ := ssa.NewTypes()
82
83 if Arch.SoftFloat {
84 softfloatInit()
85 }
86
87
88
89 _ = types.NewPtr(types.Types[types.TINTER])
90 _ = types.NewPtr(types.NewPtr(types.Types[types.TSTRING]))
91 _ = types.NewPtr(types.NewSlice(types.Types[types.TINTER]))
92 _ = types.NewPtr(types.NewPtr(types.ByteType))
93 _ = types.NewPtr(types.NewSlice(types.ByteType))
94 _ = types.NewPtr(types.NewSlice(types.Types[types.TSTRING]))
95 _ = types.NewPtr(types.NewPtr(types.NewPtr(types.Types[types.TUINT8])))
96 _ = types.NewPtr(types.Types[types.TINT16])
97 _ = types.NewPtr(types.Types[types.TINT64])
98 _ = types.NewPtr(types.ErrorType)
99 _ = types.NewPtr(reflectdata.MapType())
100 _ = types.NewPtr(deferstruct())
101 types.NewPtrCacheEnabled = false
102 ssaConfig = ssa.NewConfig(base.Ctxt.Arch.Name, *types_, base.Ctxt, base.Flag.N == 0, Arch.SoftFloat)
103 ssaConfig.Race = base.Flag.Race
104 ssaCaches = make([]ssa.Cache, base.Flag.LowerC)
105
106
107 ir.Syms.AssertE2I = typecheck.LookupRuntimeFunc("assertE2I")
108 ir.Syms.AssertE2I2 = typecheck.LookupRuntimeFunc("assertE2I2")
109 ir.Syms.CgoCheckMemmove = typecheck.LookupRuntimeFunc("cgoCheckMemmove")
110 ir.Syms.CgoCheckPtrWrite = typecheck.LookupRuntimeFunc("cgoCheckPtrWrite")
111 ir.Syms.CheckPtrAlignment = typecheck.LookupRuntimeFunc("checkptrAlignment")
112 ir.Syms.Deferproc = typecheck.LookupRuntimeFunc("deferproc")
113 ir.Syms.Deferprocat = typecheck.LookupRuntimeFunc("deferprocat")
114 ir.Syms.DeferprocStack = typecheck.LookupRuntimeFunc("deferprocStack")
115 ir.Syms.Deferreturn = typecheck.LookupRuntimeFunc("deferreturn")
116 ir.Syms.Duffcopy = typecheck.LookupRuntimeFunc("duffcopy")
117 ir.Syms.Duffzero = typecheck.LookupRuntimeFunc("duffzero")
118 ir.Syms.GCWriteBarrier[0] = typecheck.LookupRuntimeFunc("gcWriteBarrier1")
119 ir.Syms.GCWriteBarrier[1] = typecheck.LookupRuntimeFunc("gcWriteBarrier2")
120 ir.Syms.GCWriteBarrier[2] = typecheck.LookupRuntimeFunc("gcWriteBarrier3")
121 ir.Syms.GCWriteBarrier[3] = typecheck.LookupRuntimeFunc("gcWriteBarrier4")
122 ir.Syms.GCWriteBarrier[4] = typecheck.LookupRuntimeFunc("gcWriteBarrier5")
123 ir.Syms.GCWriteBarrier[5] = typecheck.LookupRuntimeFunc("gcWriteBarrier6")
124 ir.Syms.GCWriteBarrier[6] = typecheck.LookupRuntimeFunc("gcWriteBarrier7")
125 ir.Syms.GCWriteBarrier[7] = typecheck.LookupRuntimeFunc("gcWriteBarrier8")
126 ir.Syms.Goschedguarded = typecheck.LookupRuntimeFunc("goschedguarded")
127 ir.Syms.Growslice = typecheck.LookupRuntimeFunc("growslice")
128 ir.Syms.GrowsliceBuf = typecheck.LookupRuntimeFunc("growsliceBuf")
129 ir.Syms.GrowsliceBufNoAlias = typecheck.LookupRuntimeFunc("growsliceBufNoAlias")
130 ir.Syms.GrowsliceNoAlias = typecheck.LookupRuntimeFunc("growsliceNoAlias")
131 ir.Syms.MoveSlice = typecheck.LookupRuntimeFunc("moveSlice")
132 ir.Syms.MoveSliceNoScan = typecheck.LookupRuntimeFunc("moveSliceNoScan")
133 ir.Syms.MoveSliceNoCap = typecheck.LookupRuntimeFunc("moveSliceNoCap")
134 ir.Syms.MoveSliceNoCapNoScan = typecheck.LookupRuntimeFunc("moveSliceNoCapNoScan")
135 ir.Syms.InterfaceSwitch = typecheck.LookupRuntimeFunc("interfaceSwitch")
136 for i := 1; i < len(ir.Syms.MallocGCSmallNoScan); i++ {
137 ir.Syms.MallocGCSmallNoScan[i] = typecheck.LookupRuntimeFunc(fmt.Sprintf("mallocgcSmallNoScanSC%d", i))
138 }
139 for i := 1; i < len(ir.Syms.MallocGCSmallScanNoHeader); i++ {
140 ir.Syms.MallocGCSmallScanNoHeader[i] = typecheck.LookupRuntimeFunc(fmt.Sprintf("mallocgcSmallScanNoHeaderSC%d", i))
141 }
142 ir.Syms.MallocGCTiny = typecheck.LookupRuntimeFunc("mallocgcTinySC2")
143 ir.Syms.MallocGC = typecheck.LookupRuntimeFunc("mallocgc")
144 ir.Syms.Memmove = typecheck.LookupRuntimeFunc("memmove")
145 ir.Syms.Memequal = typecheck.LookupRuntimeFunc("memequal")
146 ir.Syms.Msanread = typecheck.LookupRuntimeFunc("msanread")
147 ir.Syms.Msanwrite = typecheck.LookupRuntimeFunc("msanwrite")
148 ir.Syms.Msanmove = typecheck.LookupRuntimeFunc("msanmove")
149 ir.Syms.Asanread = typecheck.LookupRuntimeFunc("asanread")
150 ir.Syms.Asanwrite = typecheck.LookupRuntimeFunc("asanwrite")
151 ir.Syms.Newobject = typecheck.LookupRuntimeFunc("newobject")
152 ir.Syms.Newproc = typecheck.LookupRuntimeFunc("newproc")
153 ir.Syms.PanicBounds = typecheck.LookupRuntimeFunc("panicBounds")
154 ir.Syms.PanicExtend = typecheck.LookupRuntimeFunc("panicExtend")
155 ir.Syms.Panicdivide = typecheck.LookupRuntimeFunc("panicdivide")
156 ir.Syms.PanicdottypeE = typecheck.LookupRuntimeFunc("panicdottypeE")
157 ir.Syms.PanicdottypeI = typecheck.LookupRuntimeFunc("panicdottypeI")
158 ir.Syms.Panicnildottype = typecheck.LookupRuntimeFunc("panicnildottype")
159 ir.Syms.Panicoverflow = typecheck.LookupRuntimeFunc("panicoverflow")
160 ir.Syms.Panicshift = typecheck.LookupRuntimeFunc("panicshift")
161 ir.Syms.PanicSimdImm = typecheck.LookupRuntimeFunc("panicSimdImm")
162 ir.Syms.Racefuncenter = typecheck.LookupRuntimeFunc("racefuncenter")
163 ir.Syms.Racefuncexit = typecheck.LookupRuntimeFunc("racefuncexit")
164 ir.Syms.Raceread = typecheck.LookupRuntimeFunc("raceread")
165 ir.Syms.Racereadrange = typecheck.LookupRuntimeFunc("racereadrange")
166 ir.Syms.Racewrite = typecheck.LookupRuntimeFunc("racewrite")
167 ir.Syms.Racewriterange = typecheck.LookupRuntimeFunc("racewriterange")
168 ir.Syms.TypeAssert = typecheck.LookupRuntimeFunc("typeAssert")
169 ir.Syms.WBZero = typecheck.LookupRuntimeFunc("wbZero")
170 ir.Syms.WBMove = typecheck.LookupRuntimeFunc("wbMove")
171 ir.Syms.X86HasAVX = typecheck.LookupRuntimeVar("x86HasAVX")
172 ir.Syms.X86HasFMA = typecheck.LookupRuntimeVar("x86HasFMA")
173 ir.Syms.X86HasPOPCNT = typecheck.LookupRuntimeVar("x86HasPOPCNT")
174 ir.Syms.X86HasSSE41 = typecheck.LookupRuntimeVar("x86HasSSE41")
175 ir.Syms.ARMHasVFPv4 = typecheck.LookupRuntimeVar("armHasVFPv4")
176 ir.Syms.ARM64HasATOMICS = typecheck.LookupRuntimeVar("arm64HasATOMICS")
177 ir.Syms.Loong64HasLAMCAS = typecheck.LookupRuntimeVar("loong64HasLAMCAS")
178 ir.Syms.Loong64HasLAM_BH = typecheck.LookupRuntimeVar("loong64HasLAM_BH")
179 ir.Syms.Loong64HasDBAR_HINTS = typecheck.LookupRuntimeVar("loong64HasDBAR_HINTS")
180 ir.Syms.Loong64HasLSX = typecheck.LookupRuntimeVar("loong64HasLSX")
181 ir.Syms.RISCV64HasZbb = typecheck.LookupRuntimeVar("riscv64HasZbb")
182 ir.Syms.Staticuint64s = typecheck.LookupRuntimeVar("staticuint64s")
183 ir.Syms.Typedmemmove = typecheck.LookupRuntimeFunc("typedmemmove")
184 ir.Syms.Udiv = typecheck.LookupRuntimeVar("udiv")
185 ir.Syms.WriteBarrier = typecheck.LookupRuntimeVar("writeBarrier")
186 ir.Syms.Zerobase = typecheck.LookupRuntimeVar("zerobase")
187 ir.Syms.ZeroVal = typecheck.LookupRuntimeVar("zeroVal")
188
189 if Arch.LinkArch.Family == sys.Wasm {
190 BoundsCheckFunc[ssa.BoundsIndex] = typecheck.LookupRuntimeFunc("goPanicIndex")
191 BoundsCheckFunc[ssa.BoundsIndexU] = typecheck.LookupRuntimeFunc("goPanicIndexU")
192 BoundsCheckFunc[ssa.BoundsSliceAlen] = typecheck.LookupRuntimeFunc("goPanicSliceAlen")
193 BoundsCheckFunc[ssa.BoundsSliceAlenU] = typecheck.LookupRuntimeFunc("goPanicSliceAlenU")
194 BoundsCheckFunc[ssa.BoundsSliceAcap] = typecheck.LookupRuntimeFunc("goPanicSliceAcap")
195 BoundsCheckFunc[ssa.BoundsSliceAcapU] = typecheck.LookupRuntimeFunc("goPanicSliceAcapU")
196 BoundsCheckFunc[ssa.BoundsSliceB] = typecheck.LookupRuntimeFunc("goPanicSliceB")
197 BoundsCheckFunc[ssa.BoundsSliceBU] = typecheck.LookupRuntimeFunc("goPanicSliceBU")
198 BoundsCheckFunc[ssa.BoundsSlice3Alen] = typecheck.LookupRuntimeFunc("goPanicSlice3Alen")
199 BoundsCheckFunc[ssa.BoundsSlice3AlenU] = typecheck.LookupRuntimeFunc("goPanicSlice3AlenU")
200 BoundsCheckFunc[ssa.BoundsSlice3Acap] = typecheck.LookupRuntimeFunc("goPanicSlice3Acap")
201 BoundsCheckFunc[ssa.BoundsSlice3AcapU] = typecheck.LookupRuntimeFunc("goPanicSlice3AcapU")
202 BoundsCheckFunc[ssa.BoundsSlice3B] = typecheck.LookupRuntimeFunc("goPanicSlice3B")
203 BoundsCheckFunc[ssa.BoundsSlice3BU] = typecheck.LookupRuntimeFunc("goPanicSlice3BU")
204 BoundsCheckFunc[ssa.BoundsSlice3C] = typecheck.LookupRuntimeFunc("goPanicSlice3C")
205 BoundsCheckFunc[ssa.BoundsSlice3CU] = typecheck.LookupRuntimeFunc("goPanicSlice3CU")
206 BoundsCheckFunc[ssa.BoundsConvert] = typecheck.LookupRuntimeFunc("goPanicSliceConvert")
207 }
208
209
210 ir.Syms.WasmDiv = typecheck.LookupRuntimeVar("wasmDiv")
211 ir.Syms.WasmTruncS = typecheck.LookupRuntimeVar("wasmTruncS")
212 ir.Syms.WasmTruncU = typecheck.LookupRuntimeVar("wasmTruncU")
213 ir.Syms.SigPanic = typecheck.LookupRuntimeFunc("sigpanic")
214 }
215
216 func InitTables() {
217 initIntrinsics(nil)
218 }
219
220
221
222
223
224
225
226
227 func AbiForBodylessFuncStackMap(fn *ir.Func) *abi.ABIConfig {
228 return ssaConfig.ABI0.Copy()
229 }
230
231
232
233 func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig {
234 if buildcfg.Experiment.RegabiArgs {
235
236 if fn == nil {
237 return abi1
238 }
239 switch fn.ABI {
240 case obj.ABI0:
241 return abi0
242 case obj.ABIInternal:
243
244
245 return abi1
246 }
247 base.Fatalf("function %v has unknown ABI %v", fn, fn.ABI)
248 panic("not reachable")
249 }
250
251 a := abi0
252 if fn != nil {
253 if fn.Pragma&ir.RegisterParams != 0 {
254 a = abi1
255 }
256 }
257 return a
258 }
259
260
261
262
263
264
265
266
267
268
269
270
271 func (s *state) emitOpenDeferInfo() {
272 firstOffset := s.openDefers[0].closureNode.FrameOffset()
273
274
275 for i, r := range s.openDefers {
276 have := r.closureNode.FrameOffset()
277 want := firstOffset + int64(i)*int64(types.PtrSize)
278 if have != want {
279 base.FatalfAt(s.curfn.Pos(), "unexpected frame offset for open-coded defer slot #%v: have %v, want %v", i, have, want)
280 }
281 }
282
283 x := base.Ctxt.Lookup(s.curfn.LSym.Name + ".opendefer")
284 x.Set(obj.AttrContentAddressable, true)
285 x.Align = 1
286 s.curfn.LSym.Func().OpenCodedDeferInfo = x
287
288 off := 0
289 off = objw.Uvarint(x, off, uint64(-s.deferBitsTemp.FrameOffset()))
290 off = objw.Uvarint(x, off, uint64(-firstOffset))
291 }
292
293
294
295 func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func {
296 name := ir.FuncName(fn)
297
298 abiSelf := abiForFunc(fn, ssaConfig.ABI0, ssaConfig.ABI1)
299
300 printssa := false
301
302
303 if strings.Contains(ssaDump, name) {
304 nameOptABI := name
305 if l := len(ssaDump); l > 1 && ssaDump[l-2] == ',' {
306 nameOptABI = ssa.FuncNameABI(name, abiSelf.Which())
307 } else if strings.HasSuffix(ssaDump, ">") {
308 l := len(ssaDump)
309 if l >= 3 && ssaDump[l-3] == '<' {
310 nameOptABI = ssa.FuncNameABI(name, abiSelf.Which())
311 ssaDump = ssaDump[:l-3] + "," + ssaDump[l-2:l-1]
312 }
313 }
314 pkgDotName := base.Ctxt.Pkgpath + "." + nameOptABI
315 printssa = nameOptABI == ssaDump ||
316 pkgDotName == ssaDump ||
317 strings.HasSuffix(pkgDotName, ssaDump) && strings.HasSuffix(pkgDotName, "/"+ssaDump)
318 }
319
320 var astBuf *bytes.Buffer
321 if printssa {
322 astBuf = &bytes.Buffer{}
323 ir.FDumpList(astBuf, "buildssa-body", fn.Body)
324 if ssaDumpStdout {
325 fmt.Println("generating SSA for", name)
326 fmt.Print(astBuf.String())
327 }
328 }
329
330 var s state
331 s.pushLine(fn.Pos())
332 defer s.popLine()
333
334 s.hasdefer = fn.HasDefer()
335 if fn.Pragma&ir.CgoUnsafeArgs != 0 {
336 s.cgoUnsafeArgs = true
337 }
338 s.checkPtrEnabled = ir.ShouldCheckPtr(fn, 1)
339
340 if base.Flag.Cfg.Instrumenting && fn.Pragma&ir.Norace == 0 && !fn.Linksym().ABIWrapper() {
341 if !base.Flag.Race || !objabi.LookupPkgSpecial(fn.Sym().Pkg.Path).NoRaceFunc {
342 s.instrumentMemory = true
343 if base.Flag.Race {
344 s.instrumentEnterExit = true
345 }
346 }
347 }
348
349 fe := ssafn{
350 curfn: fn,
351 log: printssa && ssaDumpStdout,
352 }
353 s.curfn = fn
354
355 cache := &ssaCaches[worker]
356 cache.Reset()
357
358 s.f = ssaConfig.NewFunc(&fe, cache)
359 s.config = ssaConfig
360 s.f.Type = fn.Type()
361 s.f.Name = name
362 s.f.PrintOrHtmlSSA = printssa
363 if fn.Pragma&ir.Nosplit != 0 {
364 s.f.NoSplit = true
365 }
366 s.f.ABI0 = ssaConfig.ABI0
367 s.f.ABI1 = ssaConfig.ABI1
368 s.f.ABIDefault = abiForFunc(nil, ssaConfig.ABI0, ssaConfig.ABI1)
369 s.f.ABISelf = abiSelf
370
371 s.panics = map[funcLine]*ssa.Block{}
372 s.softFloat = s.config.SoftFloat
373
374
375 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
376 s.f.Entry.Pos = fn.Pos()
377 s.f.IsPgoHot = isPgoHot
378
379 if printssa {
380 ssaDF := ssaDumpFile
381 if ssaDir != "" {
382 ssaDF = filepath.Join(ssaDir, base.Ctxt.Pkgpath+"."+s.f.NameABI()+".html")
383 ssaD := filepath.Dir(ssaDF)
384 os.MkdirAll(ssaD, 0755)
385 }
386 s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDF, s.f, ssaDumpCFG)
387
388 dumpSourcesColumn(s.f.HTMLWriter, fn)
389 s.f.HTMLWriter.WriteAST("AST", astBuf)
390 }
391
392
393 s.labels = map[string]*ssaLabel{}
394 s.fwdVars = map[ir.Node]*ssa.Value{}
395 s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem)
396
397 s.hasOpenDefers = base.Flag.N == 0 && s.hasdefer && !s.curfn.OpenCodedDeferDisallowed()
398 switch {
399 case base.Debug.NoOpenDefer != 0:
400 s.hasOpenDefers = false
401 case s.hasOpenDefers && (base.Ctxt.Flag_shared || base.Ctxt.Flag_dynlink) && base.Ctxt.Arch.Name == "386":
402
403
404
405
406
407 s.hasOpenDefers = false
408 }
409 if s.hasOpenDefers && s.instrumentEnterExit {
410
411
412
413 s.hasOpenDefers = false
414 }
415 if s.hasOpenDefers {
416
417
418 for _, f := range s.curfn.Type().Results() {
419 if !f.Nname.(*ir.Name).OnStack() {
420 s.hasOpenDefers = false
421 break
422 }
423 }
424 }
425 if s.hasOpenDefers &&
426 s.curfn.NumReturns*s.curfn.NumDefers > 15 {
427
428
429
430
431
432 s.hasOpenDefers = false
433 }
434
435 s.sp = s.entryNewValue0(ssa.OpSP, types.Types[types.TUINTPTR])
436 s.sb = s.entryNewValue0(ssa.OpSB, types.Types[types.TUINTPTR])
437
438 s.startBlock(s.f.Entry)
439 s.vars[memVar] = s.startmem
440 if s.hasOpenDefers {
441
442
443
444 deferBitsTemp := typecheck.TempAt(src.NoXPos, s.curfn, types.Types[types.TUINT8])
445 deferBitsTemp.SetAddrtaken(true)
446 s.deferBitsTemp = deferBitsTemp
447
448 startDeferBits := s.entryNewValue0(ssa.OpConst8, types.Types[types.TUINT8])
449 s.vars[deferBitsVar] = startDeferBits
450 s.deferBitsAddr = s.addr(deferBitsTemp)
451 s.store(types.Types[types.TUINT8], s.deferBitsAddr, startDeferBits)
452
453
454
455
456
457 s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, deferBitsTemp, s.mem(), false)
458 }
459
460 var params *abi.ABIParamResultInfo
461 params = s.f.ABISelf.ABIAnalyze(fn.Type(), true)
462
463
464
465
466
467
468 var debugInfo ssa.FuncDebug
469 for _, n := range fn.Dcl {
470 if n.Class == ir.PPARAMOUT && n.IsOutputParamInRegisters() {
471 debugInfo.RegOutputParams = append(debugInfo.RegOutputParams, n)
472 }
473 }
474 fn.DebugInfo = &debugInfo
475
476
477 s.decladdrs = map[*ir.Name]*ssa.Value{}
478 for _, n := range fn.Dcl {
479 switch n.Class {
480 case ir.PPARAM:
481
482 s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type()), n, s.sp, s.startmem)
483 case ir.PPARAMOUT:
484 s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type()), n, s.sp, s.startmem)
485 case ir.PAUTO:
486
487
488 default:
489 s.Fatalf("local variable with class %v unimplemented", n.Class)
490 }
491 }
492
493 s.f.OwnAux = ssa.OwnAuxCall(fn.LSym, params)
494
495
496 for _, n := range fn.Dcl {
497 if n.Class == ir.PPARAM {
498 if s.canSSA(n) {
499 v := s.newValue0A(ssa.OpArg, n.Type(), n)
500 s.vars[n] = v
501 s.addNamedValue(n, v)
502 } else {
503 paramAssignment := ssa.ParamAssignmentForArgName(s.f, n)
504 if len(paramAssignment.Registers) > 0 {
505 if ssa.CanSSA(n.Type()) {
506 v := s.newValue0A(ssa.OpArg, n.Type(), n)
507 s.store(n.Type(), s.decladdrs[n], v)
508 } else {
509
510
511 s.storeParameterRegsToStack(s.f.ABISelf, paramAssignment, n, s.decladdrs[n], false)
512 }
513 }
514 }
515 }
516 }
517
518
519 if fn.Needctxt() {
520 clo := s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr)
521 if fn.RangeParent != nil && base.Flag.N != 0 {
522
523
524
525 sym := &types.Sym{Name: ".closureptr", Pkg: types.LocalPkg}
526 cloSlot := s.curfn.NewLocal(src.NoXPos, sym, s.f.Config.Types.BytePtr)
527 cloSlot.SetUsed(true)
528 cloSlot.SetEsc(ir.EscNever)
529 cloSlot.SetAddrtaken(true)
530 s.f.CloSlot = cloSlot
531 s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, cloSlot, s.mem(), false)
532 addr := s.addr(cloSlot)
533 s.store(s.f.Config.Types.BytePtr, addr, clo)
534
535 s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, cloSlot, s.mem(), false)
536 }
537 csiter := typecheck.NewClosureStructIter(fn.ClosureVars)
538 for {
539 n, typ, offset := csiter.Next()
540 if n == nil {
541 break
542 }
543
544 ptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(typ), offset, clo)
545
546
547
548
549
550
551
552
553
554 if n.Byval() && !n.Addrtaken() && ssa.CanSSA(n.Type()) {
555 n.Class = ir.PAUTO
556 fn.Dcl = append(fn.Dcl, n)
557 s.assign(n, s.load(n.Type(), ptr), false, 0)
558 continue
559 }
560
561 if !n.Byval() {
562 ptr = s.load(typ, ptr)
563 }
564 s.setHeapaddr(fn.Pos(), n, ptr)
565 }
566 }
567
568
569 if s.instrumentEnterExit {
570 s.rtcall(ir.Syms.Racefuncenter, true, nil, s.newValue0(ssa.OpGetCallerPC, types.Types[types.TUINTPTR]))
571 }
572 s.zeroResults()
573 s.paramsToHeap()
574 s.stmtList(fn.Body)
575
576
577 if s.curBlock != nil {
578 s.pushLine(fn.Endlineno)
579 s.exit()
580 s.popLine()
581 }
582
583 for _, b := range s.f.Blocks {
584 if b.Pos != src.NoXPos {
585 s.updateUnsetPredPos(b)
586 }
587 }
588
589 s.f.HTMLWriter.WritePhase("before insert phis", "before insert phis")
590
591 s.insertPhis()
592
593
594 ssa.Compile(s.f)
595
596 fe.AllocFrame(s.f)
597
598 if len(s.openDefers) != 0 {
599 s.emitOpenDeferInfo()
600 }
601
602
603
604
605
606
607 for _, p := range params.InParams() {
608 typs, offs := p.RegisterTypesAndOffsets()
609 if len(offs) < len(typs) {
610 s.Fatalf("len(offs)=%d < len(typs)=%d, params=\n%s", len(offs), len(typs), params)
611 }
612 for i, t := range typs {
613 o := offs[i]
614 fo := p.FrameOffset(params)
615 reg := ssa.ObjRegForAbiReg(p.Registers[i], s.f.Config)
616 s.f.RegArgs = append(s.f.RegArgs, ssa.Spill{Reg: reg, Offset: fo + o, Type: t})
617 }
618 }
619
620 return s.f
621 }
622
623 func (s *state) storeParameterRegsToStack(abi *abi.ABIConfig, paramAssignment *abi.ABIParamAssignment, n *ir.Name, addr *ssa.Value, pointersOnly bool) {
624 typs, offs := paramAssignment.RegisterTypesAndOffsets()
625 for i, t := range typs {
626 if pointersOnly && !t.IsPtrShaped() {
627 continue
628 }
629 r := paramAssignment.Registers[i]
630 o := offs[i]
631 op, reg := ssa.ArgOpAndRegisterFor(r, abi)
632 aux := &ssa.AuxNameOffset{Name: n, Offset: o}
633 v := s.newValue0I(op, t, reg)
634 v.Aux = aux
635 p := s.newValue1I(ssa.OpOffPtr, types.NewPtr(t), o, addr)
636 s.store(t, p, v)
637 }
638 }
639
640
641
642
643
644
645
646 func (s *state) zeroResults() {
647 for _, f := range s.curfn.Type().Results() {
648 n := f.Nname.(*ir.Name)
649 if !n.OnStack() {
650
651
652
653 continue
654 }
655
656 if typ := n.Type(); ssa.CanSSA(typ) {
657 s.assign(n, s.zeroVal(typ), false, 0)
658 } else {
659 if typ.HasPointers() || ssa.IsMergeCandidate(n) {
660 s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, n, s.mem())
661 }
662 s.zero(n.Type(), s.decladdrs[n])
663 }
664 }
665 }
666
667
668
669 func (s *state) paramsToHeap() {
670 do := func(params []*types.Field) {
671 for _, f := range params {
672 if f.Nname == nil {
673 continue
674 }
675 n := f.Nname.(*ir.Name)
676 if ir.IsBlank(n) || n.OnStack() {
677 continue
678 }
679 s.newHeapaddr(n)
680 if n.Class == ir.PPARAM {
681 s.move(n.Type(), s.expr(n.Heapaddr), s.decladdrs[n])
682 }
683 }
684 }
685
686 typ := s.curfn.Type()
687 do(typ.Recvs())
688 do(typ.Params())
689 do(typ.Results())
690 }
691
692
693
694
695 func allocSizeAndAlign(t *types.Type) (int64, int64) {
696 size, align := t.Size(), t.Alignment()
697 if types.PtrSize == 4 && align == 4 && size >= 8 {
698
699 size = types.RoundUp(size, 8)
700 align = 8
701 }
702 return size, align
703 }
704 func allocSize(t *types.Type) int64 {
705 size, _ := allocSizeAndAlign(t)
706 return size
707 }
708 func allocAlign(t *types.Type) int64 {
709 _, align := allocSizeAndAlign(t)
710 return align
711 }
712
713
714 func (s *state) newHeapaddr(n *ir.Name) {
715 size := allocSize(n.Type())
716 if n.Type().HasPointers() || size >= maxAggregatedHeapAllocation || size == 0 {
717 s.setHeapaddr(n.Pos(), n, s.newObject(n.Type()))
718 return
719 }
720
721
722
723 var used int64
724 for _, v := range s.pendingHeapAllocations {
725 used += allocSize(v.Type.Elem())
726 }
727 if used+size > maxAggregatedHeapAllocation {
728 s.flushPendingHeapAllocations()
729 }
730
731 var allocCall *ssa.Value
732 if len(s.pendingHeapAllocations) == 0 {
733
734
735
736 allocCall = s.newObjectNonSpecialized(n.Type(), nil)
737 } else {
738 allocCall = s.pendingHeapAllocations[0].Args[0]
739 }
740
741 v := s.newValue1I(ssa.OpOffPtr, n.Type().PtrTo(), 0, allocCall)
742
743
744 s.pendingHeapAllocations = append(s.pendingHeapAllocations, v)
745
746
747 s.setHeapaddr(n.Pos(), n, v)
748 }
749
750 func (s *state) flushPendingHeapAllocations() {
751 pending := s.pendingHeapAllocations
752 if len(pending) == 0 {
753 return
754 }
755 s.pendingHeapAllocations = nil
756 ptr := pending[0].Args[0]
757 call := ptr.Args[0]
758
759 if len(pending) == 1 {
760
761 v := pending[0]
762 v.Op = ssa.OpCopy
763 return
764 }
765
766
767
768
769 slices.SortStableFunc(pending, func(x, y *ssa.Value) int {
770 return cmp.Compare(allocAlign(y.Type.Elem()), allocAlign(x.Type.Elem()))
771 })
772
773
774 var size int64
775 for _, v := range pending {
776 v.AuxInt = size
777 size += allocSize(v.Type.Elem())
778 }
779 align := allocAlign(pending[0].Type.Elem())
780 size = types.RoundUp(size, align)
781
782
783 args := []*ssa.Value{
784 s.constInt(types.Types[types.TUINTPTR], size),
785 s.constNil(call.Args[0].Type),
786 s.constBool(true),
787 call.Args[1],
788 }
789 mallocSym := ir.Syms.MallocGC
790 if specialMallocSym := s.specializedMallocSym(size, false); specialMallocSym != nil {
791 mallocSym = specialMallocSym
792 }
793 call.Aux = ssa.StaticAuxCall(mallocSym, s.f.ABIDefault.ABIAnalyzeTypes(
794 []*types.Type{args[0].Type, args[1].Type, args[2].Type},
795 []*types.Type{types.Types[types.TUNSAFEPTR]},
796 ))
797 call.AuxInt = 4 * s.config.PtrSize
798 call.SetArgs4(args[0], args[1], args[2], args[3])
799
800
801 call.Type = types.NewTuple(types.Types[types.TUNSAFEPTR], types.TypeMem)
802 ptr.Type = types.Types[types.TUNSAFEPTR]
803 }
804
805 func (s *state) specializedMallocSym(size int64, hasPointers bool) *obj.LSym {
806 if !s.sizeSpecializedMallocEnabled() {
807 return nil
808 }
809 const specializedMallocMax = 80
810 if size > specializedMallocMax {
811 return nil
812 }
813 divRoundUp := func(n, a uintptr) uintptr { return (n + a - 1) / a }
814 sizeClass := gc.SizeToSizeClass8[divRoundUp(uintptr(size), gc.SmallSizeDiv)]
815 if hasPointers {
816 return ir.Syms.MallocGCSmallScanNoHeader[sizeClass]
817 }
818 if size < gc.TinySize {
819 return ir.Syms.MallocGCTiny
820 }
821 return ir.Syms.MallocGCSmallNoScan[sizeClass]
822 }
823
824 func (s *state) sizeSpecializedMallocEnabled() bool {
825 if base.Flag.CompilingRuntime {
826
827
828
829
830
831
832
833 return false
834 }
835
836 return buildcfg.Experiment.SizeSpecializedMalloc && !base.Flag.Cfg.Instrumenting
837 }
838
839
840
841 func (s *state) setHeapaddr(pos src.XPos, n *ir.Name, ptr *ssa.Value) {
842 if !ptr.Type.IsPtr() || !types.Identical(n.Type(), ptr.Type.Elem()) {
843 base.FatalfAt(n.Pos(), "setHeapaddr %L with type %v", n, ptr.Type)
844 }
845
846
847 sym := &types.Sym{Name: "&" + n.Sym().Name, Pkg: types.LocalPkg}
848 addr := s.curfn.NewLocal(pos, sym, types.NewPtr(n.Type()))
849 addr.SetUsed(true)
850 types.CalcSize(addr.Type())
851
852 if n.Class == ir.PPARAMOUT {
853 addr.SetIsOutputParamHeapAddr(true)
854 }
855
856 n.Heapaddr = addr
857 s.assign(addr, ptr, false, 0)
858 }
859
860
861 func (s *state) newObject(typ *types.Type) *ssa.Value {
862 if typ.Size() == 0 {
863 return s.newValue1A(ssa.OpAddr, types.NewPtr(typ), ir.Syms.Zerobase, s.sb)
864 }
865 rtype := s.reflectType(typ)
866 if specialMallocSym := s.specializedMallocSym(typ.Size(), typ.HasPointers()); specialMallocSym != nil {
867 return s.rtcall(specialMallocSym, true, []*types.Type{types.NewPtr(typ)},
868 s.constInt(types.Types[types.TUINTPTR], typ.Size()),
869 rtype,
870 s.constBool(true),
871 )[0]
872 }
873 return s.rtcall(ir.Syms.Newobject, true, []*types.Type{types.NewPtr(typ)}, rtype)[0]
874 }
875
876
877
878 func (s *state) newObjectNonSpecialized(typ *types.Type, rtype *ssa.Value) *ssa.Value {
879 if typ.Size() == 0 {
880 return s.newValue1A(ssa.OpAddr, types.NewPtr(typ), ir.Syms.Zerobase, s.sb)
881 }
882 if rtype == nil {
883 rtype = s.reflectType(typ)
884 }
885 return s.rtcall(ir.Syms.Newobject, true, []*types.Type{types.NewPtr(typ)}, rtype)[0]
886 }
887
888 func (s *state) checkPtrAlignment(n *ir.ConvExpr, v *ssa.Value, count *ssa.Value) {
889 if !n.Type().IsPtr() {
890 s.Fatalf("expected pointer type: %v", n.Type())
891 }
892 elem, rtypeExpr := n.Type().Elem(), n.ElemRType
893 if count != nil {
894 if !elem.IsArray() {
895 s.Fatalf("expected array type: %v", elem)
896 }
897 elem, rtypeExpr = elem.Elem(), n.ElemElemRType
898 }
899 size := elem.Size()
900
901 if elem.Alignment() == 1 && (size == 0 || size == 1 || count == nil) {
902 return
903 }
904 if count == nil {
905 count = s.constInt(types.Types[types.TUINTPTR], 1)
906 }
907 if count.Type.Size() != s.config.PtrSize {
908 s.Fatalf("expected count fit to a uintptr size, have: %d, want: %d", count.Type.Size(), s.config.PtrSize)
909 }
910 var rtype *ssa.Value
911 if rtypeExpr != nil {
912 rtype = s.expr(rtypeExpr)
913 } else {
914 rtype = s.reflectType(elem)
915 }
916 s.rtcall(ir.Syms.CheckPtrAlignment, true, nil, v, rtype, count)
917 }
918
919
920
921 func (s *state) reflectType(typ *types.Type) *ssa.Value {
922
923
924 lsym := reflectdata.TypeLinksym(typ)
925 return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(types.Types[types.TUINT8]), lsym, s.sb)
926 }
927
928 func dumpSourcesColumn(writer *ssa.HTMLWriter, fn *ir.Func) {
929
930 fname := base.Ctxt.PosTable.Pos(fn.Pos()).Filename()
931 targetFn, err := readFuncLines(fname, fn.Pos().Line(), fn.Endlineno.Line())
932 if err != nil {
933 writer.Logf("cannot read sources for function %v: %v", fn, err)
934 }
935
936
937 var inlFns []*ssa.FuncLines
938 for _, fi := range ssaDumpInlined {
939 elno := fi.Endlineno
940 fname := base.Ctxt.PosTable.Pos(fi.Pos()).Filename()
941 fnLines, err := readFuncLines(fname, fi.Pos().Line(), elno.Line())
942 if err != nil {
943 writer.Logf("cannot read sources for inlined function %v: %v", fi, err)
944 continue
945 }
946 inlFns = append(inlFns, fnLines)
947 }
948
949 slices.SortFunc(inlFns, ssa.ByTopoCmp)
950 if targetFn != nil {
951 inlFns = append([]*ssa.FuncLines{targetFn}, inlFns...)
952 }
953
954 writer.WriteSources("sources", inlFns)
955 }
956
957 func readFuncLines(file string, start, end uint) (*ssa.FuncLines, error) {
958 f, err := os.Open(os.ExpandEnv(file))
959 if err != nil {
960 return nil, err
961 }
962 defer f.Close()
963 var lines []string
964 ln := uint(1)
965 scanner := bufio.NewScanner(f)
966 for scanner.Scan() && ln <= end {
967 if ln >= start {
968 lines = append(lines, scanner.Text())
969 }
970 ln++
971 }
972 return &ssa.FuncLines{Filename: file, StartLineno: start, Lines: lines}, nil
973 }
974
975
976
977
978 func (s *state) updateUnsetPredPos(b *ssa.Block) {
979 if b.Pos == src.NoXPos {
980 s.Fatalf("Block %s should have a position", b)
981 }
982 bestPos := src.NoXPos
983 for _, e := range b.Preds {
984 p := e.Block()
985 if !p.LackingPos() {
986 continue
987 }
988 if bestPos == src.NoXPos {
989 bestPos = b.Pos
990 for _, v := range b.Values {
991 if v.LackingPos() {
992 continue
993 }
994 if v.Pos != src.NoXPos {
995
996
997 bestPos = v.Pos
998 break
999 }
1000 }
1001 }
1002 p.Pos = bestPos
1003 s.updateUnsetPredPos(p)
1004 }
1005 }
1006
1007
1008 type openDeferInfo struct {
1009
1010 n *ir.CallExpr
1011
1012
1013 closure *ssa.Value
1014
1015
1016
1017 closureNode *ir.Name
1018 }
1019
1020 type state struct {
1021
1022 config *ssa.Config
1023
1024
1025 f *ssa.Func
1026
1027
1028 curfn *ir.Func
1029
1030
1031 labels map[string]*ssaLabel
1032
1033
1034 breakTo *ssa.Block
1035 continueTo *ssa.Block
1036
1037
1038 curBlock *ssa.Block
1039
1040
1041
1042
1043 vars map[ir.Node]*ssa.Value
1044
1045
1046
1047
1048 fwdVars map[ir.Node]*ssa.Value
1049
1050
1051 defvars []map[ir.Node]*ssa.Value
1052
1053
1054 decladdrs map[*ir.Name]*ssa.Value
1055
1056
1057 startmem *ssa.Value
1058 sp *ssa.Value
1059 sb *ssa.Value
1060
1061 deferBitsAddr *ssa.Value
1062 deferBitsTemp *ir.Name
1063
1064
1065 line []src.XPos
1066
1067 lastPos src.XPos
1068
1069
1070
1071 panics map[funcLine]*ssa.Block
1072
1073 cgoUnsafeArgs bool
1074 hasdefer bool
1075 softFloat bool
1076 hasOpenDefers bool
1077 checkPtrEnabled bool
1078 instrumentEnterExit bool
1079 instrumentMemory bool
1080
1081
1082
1083
1084 openDefers []*openDeferInfo
1085
1086
1087
1088
1089 lastDeferExit *ssa.Block
1090 lastDeferFinalBlock *ssa.Block
1091 lastDeferCount int
1092
1093 prevCall *ssa.Value
1094
1095
1096
1097
1098 pendingHeapAllocations []*ssa.Value
1099
1100
1101 appendTargets map[ir.Node]bool
1102
1103
1104 blockStarts []src.XPos
1105
1106
1107
1108 backingStores map[ir.Node]*backingStoreInfo
1109 }
1110
1111 type backingStoreInfo struct {
1112
1113 K int64
1114
1115 store *ir.Name
1116
1117 used *ir.Name
1118
1119
1120
1121 usedStatic bool
1122 }
1123
1124 type funcLine struct {
1125 f *obj.LSym
1126 base *src.PosBase
1127 line uint
1128 }
1129
1130 type ssaLabel struct {
1131 target *ssa.Block
1132 breakTarget *ssa.Block
1133 continueTarget *ssa.Block
1134 }
1135
1136
1137 func (s *state) label(sym *types.Sym) *ssaLabel {
1138 lab := s.labels[sym.Name]
1139 if lab == nil {
1140 lab = new(ssaLabel)
1141 s.labels[sym.Name] = lab
1142 }
1143 return lab
1144 }
1145
1146 func (s *state) Logf(msg string, args ...any) { s.f.Logf(msg, args...) }
1147 func (s *state) Log() bool { return s.f.Log() }
1148 func (s *state) Fatalf(msg string, args ...any) {
1149 s.f.Frontend().Fatalf(s.peekPos(), msg, args...)
1150 }
1151 func (s *state) Warnl(pos src.XPos, msg string, args ...any) { s.f.Warnl(pos, msg, args...) }
1152 func (s *state) Debug_checknil() bool { return s.f.Frontend().Debug_checknil() }
1153
1154 func ssaMarker(name string) *ir.Name {
1155 return ir.NewNameAt(base.Pos, &types.Sym{Name: name}, nil)
1156 }
1157
1158 var (
1159
1160 memVar = ssaMarker("mem")
1161
1162
1163 ptrVar = ssaMarker("ptr")
1164 lenVar = ssaMarker("len")
1165 capVar = ssaMarker("cap")
1166 typVar = ssaMarker("typ")
1167 okVar = ssaMarker("ok")
1168 deferBitsVar = ssaMarker("deferBits")
1169 hashVar = ssaMarker("hash")
1170 )
1171
1172
1173 func (s *state) startBlock(b *ssa.Block) {
1174 if s.curBlock != nil {
1175 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
1176 }
1177 s.curBlock = b
1178 s.vars = map[ir.Node]*ssa.Value{}
1179 clear(s.fwdVars)
1180 for len(s.blockStarts) <= int(b.ID) {
1181 s.blockStarts = append(s.blockStarts, src.NoXPos)
1182 }
1183 }
1184
1185
1186
1187
1188 func (s *state) endBlock() *ssa.Block {
1189 b := s.curBlock
1190 if b == nil {
1191 return nil
1192 }
1193
1194 s.flushPendingHeapAllocations()
1195
1196 for len(s.defvars) <= int(b.ID) {
1197 s.defvars = append(s.defvars, nil)
1198 }
1199 s.defvars[b.ID] = s.vars
1200 s.curBlock = nil
1201 s.vars = nil
1202 if b.LackingPos() {
1203
1204
1205
1206 b.Pos = src.NoXPos
1207 } else {
1208 b.Pos = s.lastPos
1209 if s.blockStarts[b.ID] == src.NoXPos {
1210 s.blockStarts[b.ID] = s.lastPos
1211 }
1212 }
1213 return b
1214 }
1215
1216
1217 func (s *state) pushLine(line src.XPos) {
1218 if !line.IsKnown() {
1219
1220
1221 line = s.peekPos()
1222 if base.Flag.K != 0 {
1223 base.Warn("buildssa: unknown position (line 0)")
1224 }
1225 } else {
1226 s.lastPos = line
1227 }
1228
1229
1230 if b := s.curBlock; b != nil && s.blockStarts[b.ID] == src.NoXPos {
1231 s.blockStarts[b.ID] = line
1232 }
1233
1234 s.line = append(s.line, line)
1235 }
1236
1237
1238 func (s *state) popLine() {
1239 s.line = s.line[:len(s.line)-1]
1240 }
1241
1242
1243 func (s *state) peekPos() src.XPos {
1244 return s.line[len(s.line)-1]
1245 }
1246
1247
1248 func (s *state) newValue0(op ssa.Op, t *types.Type) *ssa.Value {
1249 return s.curBlock.NewValue0(s.peekPos(), op, t)
1250 }
1251
1252
1253 func (s *state) newValue0A(op ssa.Op, t *types.Type, aux ssa.Aux) *ssa.Value {
1254 return s.curBlock.NewValue0A(s.peekPos(), op, t, aux)
1255 }
1256
1257
1258 func (s *state) newValue0I(op ssa.Op, t *types.Type, auxint int64) *ssa.Value {
1259 return s.curBlock.NewValue0I(s.peekPos(), op, t, auxint)
1260 }
1261
1262
1263 func (s *state) newValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value {
1264 return s.curBlock.NewValue1(s.peekPos(), op, t, arg)
1265 }
1266
1267
1268 func (s *state) newValue1A(op ssa.Op, t *types.Type, aux ssa.Aux, arg *ssa.Value) *ssa.Value {
1269 return s.curBlock.NewValue1A(s.peekPos(), op, t, aux, arg)
1270 }
1271
1272
1273
1274
1275 func (s *state) newValue1Apos(op ssa.Op, t *types.Type, aux ssa.Aux, arg *ssa.Value, isStmt bool) *ssa.Value {
1276 if isStmt {
1277 return s.curBlock.NewValue1A(s.peekPos(), op, t, aux, arg)
1278 }
1279 return s.curBlock.NewValue1A(s.peekPos().WithNotStmt(), op, t, aux, arg)
1280 }
1281
1282
1283 func (s *state) newValue1I(op ssa.Op, t *types.Type, aux int64, arg *ssa.Value) *ssa.Value {
1284 return s.curBlock.NewValue1I(s.peekPos(), op, t, aux, arg)
1285 }
1286
1287
1288 func (s *state) newValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value {
1289 return s.curBlock.NewValue2(s.peekPos(), op, t, arg0, arg1)
1290 }
1291
1292
1293 func (s *state) newValue2A(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1 *ssa.Value) *ssa.Value {
1294 return s.curBlock.NewValue2A(s.peekPos(), op, t, aux, arg0, arg1)
1295 }
1296
1297
1298
1299
1300 func (s *state) newValue2Apos(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1 *ssa.Value, isStmt bool) *ssa.Value {
1301 if isStmt {
1302 return s.curBlock.NewValue2A(s.peekPos(), op, t, aux, arg0, arg1)
1303 }
1304 return s.curBlock.NewValue2A(s.peekPos().WithNotStmt(), op, t, aux, arg0, arg1)
1305 }
1306
1307
1308 func (s *state) newValue2I(op ssa.Op, t *types.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
1309 return s.curBlock.NewValue2I(s.peekPos(), op, t, aux, arg0, arg1)
1310 }
1311
1312
1313 func (s *state) newValue3(op ssa.Op, t *types.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
1314 return s.curBlock.NewValue3(s.peekPos(), op, t, arg0, arg1, arg2)
1315 }
1316
1317
1318 func (s *state) newValue3I(op ssa.Op, t *types.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
1319 return s.curBlock.NewValue3I(s.peekPos(), op, t, aux, arg0, arg1, arg2)
1320 }
1321
1322
1323 func (s *state) newValue3A(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
1324 return s.curBlock.NewValue3A(s.peekPos(), op, t, aux, arg0, arg1, arg2)
1325 }
1326
1327
1328
1329
1330 func (s *state) newValue3Apos(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1, arg2 *ssa.Value, isStmt bool) *ssa.Value {
1331 if isStmt {
1332 return s.curBlock.NewValue3A(s.peekPos(), op, t, aux, arg0, arg1, arg2)
1333 }
1334 return s.curBlock.NewValue3A(s.peekPos().WithNotStmt(), op, t, aux, arg0, arg1, arg2)
1335 }
1336
1337
1338 func (s *state) newValue4(op ssa.Op, t *types.Type, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value {
1339 return s.curBlock.NewValue4(s.peekPos(), op, t, arg0, arg1, arg2, arg3)
1340 }
1341
1342
1343 func (s *state) newValue4A(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value {
1344 return s.curBlock.NewValue4A(s.peekPos(), op, t, aux, arg0, arg1, arg2, arg3)
1345 }
1346
1347
1348 func (s *state) newValue4I(op ssa.Op, t *types.Type, aux int64, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value {
1349 return s.curBlock.NewValue4I(s.peekPos(), op, t, aux, arg0, arg1, arg2, arg3)
1350 }
1351
1352 func (s *state) entryBlock() *ssa.Block {
1353 b := s.f.Entry
1354 if base.Flag.N > 0 && s.curBlock != nil {
1355
1356
1357
1358
1359 b = s.curBlock
1360 }
1361 return b
1362 }
1363
1364
1365 func (s *state) entryNewValue0(op ssa.Op, t *types.Type) *ssa.Value {
1366 return s.entryBlock().NewValue0(src.NoXPos, op, t)
1367 }
1368
1369
1370 func (s *state) entryNewValue0A(op ssa.Op, t *types.Type, aux ssa.Aux) *ssa.Value {
1371 return s.entryBlock().NewValue0A(src.NoXPos, op, t, aux)
1372 }
1373
1374
1375 func (s *state) entryNewValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value {
1376 return s.entryBlock().NewValue1(src.NoXPos, op, t, arg)
1377 }
1378
1379
1380 func (s *state) entryNewValue1I(op ssa.Op, t *types.Type, auxint int64, arg *ssa.Value) *ssa.Value {
1381 return s.entryBlock().NewValue1I(src.NoXPos, op, t, auxint, arg)
1382 }
1383
1384
1385 func (s *state) entryNewValue1A(op ssa.Op, t *types.Type, aux ssa.Aux, arg *ssa.Value) *ssa.Value {
1386 return s.entryBlock().NewValue1A(src.NoXPos, op, t, aux, arg)
1387 }
1388
1389
1390 func (s *state) entryNewValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value {
1391 return s.entryBlock().NewValue2(src.NoXPos, op, t, arg0, arg1)
1392 }
1393
1394
1395 func (s *state) entryNewValue2A(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1 *ssa.Value) *ssa.Value {
1396 return s.entryBlock().NewValue2A(src.NoXPos, op, t, aux, arg0, arg1)
1397 }
1398
1399
1400 func (s *state) constSlice(t *types.Type) *ssa.Value {
1401 return s.f.ConstSlice(t)
1402 }
1403 func (s *state) constInterface(t *types.Type) *ssa.Value {
1404 return s.f.ConstInterface(t)
1405 }
1406 func (s *state) constNil(t *types.Type) *ssa.Value { return s.f.ConstNil(t) }
1407 func (s *state) constEmptyString(t *types.Type) *ssa.Value {
1408 return s.f.ConstEmptyString(t)
1409 }
1410 func (s *state) constBool(c bool) *ssa.Value {
1411 return s.f.ConstBool(types.Types[types.TBOOL], c)
1412 }
1413 func (s *state) constInt8(t *types.Type, c int8) *ssa.Value {
1414 return s.f.ConstInt8(t, c)
1415 }
1416 func (s *state) constInt16(t *types.Type, c int16) *ssa.Value {
1417 return s.f.ConstInt16(t, c)
1418 }
1419 func (s *state) constInt32(t *types.Type, c int32) *ssa.Value {
1420 return s.f.ConstInt32(t, c)
1421 }
1422 func (s *state) constInt64(t *types.Type, c int64) *ssa.Value {
1423 return s.f.ConstInt64(t, c)
1424 }
1425 func (s *state) constFloat32(t *types.Type, c float64) *ssa.Value {
1426 return s.f.ConstFloat32(t, c)
1427 }
1428 func (s *state) constFloat64(t *types.Type, c float64) *ssa.Value {
1429 return s.f.ConstFloat64(t, c)
1430 }
1431 func (s *state) constInt(t *types.Type, c int64) *ssa.Value {
1432 if s.config.PtrSize == 8 {
1433 return s.constInt64(t, c)
1434 }
1435 if int64(int32(c)) != c {
1436 s.Fatalf("integer constant too big %d", c)
1437 }
1438 return s.constInt32(t, int32(c))
1439 }
1440
1441
1442
1443 func (s *state) newValueOrSfCall1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value {
1444 if s.softFloat {
1445 if c, ok := s.sfcall(op, arg); ok {
1446 return c
1447 }
1448 }
1449 return s.newValue1(op, t, arg)
1450 }
1451 func (s *state) newValueOrSfCall2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value {
1452 if s.softFloat {
1453 if c, ok := s.sfcall(op, arg0, arg1); ok {
1454 return c
1455 }
1456 }
1457 return s.newValue2(op, t, arg0, arg1)
1458 }
1459
1460 type instrumentKind uint8
1461
1462 const (
1463 instrumentRead = iota
1464 instrumentWrite
1465 instrumentMove
1466 )
1467
1468 func (s *state) instrument(t *types.Type, addr *ssa.Value, kind instrumentKind) {
1469 s.instrument2(t, addr, nil, kind)
1470 }
1471
1472
1473
1474
1475 func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrumentKind) {
1476 if !(base.Flag.MSan || base.Flag.ASan) || !isStructNotSIMD(t) {
1477 s.instrument(t, addr, kind)
1478 return
1479 }
1480 for _, f := range t.Fields() {
1481 if f.Sym.IsBlank() {
1482 continue
1483 }
1484 offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), f.Offset, addr)
1485 s.instrumentFields(f.Type, offptr, kind)
1486 }
1487 }
1488
1489 func (s *state) instrumentMove(t *types.Type, dst, src *ssa.Value) {
1490 if base.Flag.MSan {
1491 s.instrument2(t, dst, src, instrumentMove)
1492 } else {
1493 s.instrument(t, src, instrumentRead)
1494 s.instrument(t, dst, instrumentWrite)
1495 }
1496 }
1497
1498 func (s *state) instrument2(t *types.Type, addr, addr2 *ssa.Value, kind instrumentKind) {
1499 if !s.instrumentMemory {
1500 return
1501 }
1502
1503 w := t.Size()
1504 if w == 0 {
1505 return
1506 }
1507
1508 if ssa.IsSanitizerSafeAddr(addr) {
1509 return
1510 }
1511
1512 var fn *obj.LSym
1513 needWidth := false
1514
1515 if addr2 != nil && kind != instrumentMove {
1516 panic("instrument2: non-nil addr2 for non-move instrumentation")
1517 }
1518
1519 if base.Flag.MSan {
1520 switch kind {
1521 case instrumentRead:
1522 fn = ir.Syms.Msanread
1523 case instrumentWrite:
1524 fn = ir.Syms.Msanwrite
1525 case instrumentMove:
1526 fn = ir.Syms.Msanmove
1527 default:
1528 panic("unreachable")
1529 }
1530 needWidth = true
1531 } else if base.Flag.Race && t.NumComponents(types.CountBlankFields) > 1 {
1532
1533
1534
1535 switch kind {
1536 case instrumentRead:
1537 fn = ir.Syms.Racereadrange
1538 case instrumentWrite:
1539 fn = ir.Syms.Racewriterange
1540 default:
1541 panic("unreachable")
1542 }
1543 needWidth = true
1544 } else if base.Flag.Race {
1545
1546
1547 switch kind {
1548 case instrumentRead:
1549 fn = ir.Syms.Raceread
1550 case instrumentWrite:
1551 fn = ir.Syms.Racewrite
1552 default:
1553 panic("unreachable")
1554 }
1555 } else if base.Flag.ASan {
1556 switch kind {
1557 case instrumentRead:
1558 fn = ir.Syms.Asanread
1559 case instrumentWrite:
1560 fn = ir.Syms.Asanwrite
1561 default:
1562 panic("unreachable")
1563 }
1564 needWidth = true
1565 } else {
1566 panic("unreachable")
1567 }
1568
1569 args := []*ssa.Value{addr}
1570 if addr2 != nil {
1571 args = append(args, addr2)
1572 }
1573 if needWidth {
1574 args = append(args, s.constInt(types.Types[types.TUINTPTR], w))
1575 }
1576 s.rtcall(fn, true, nil, args...)
1577 }
1578
1579 func (s *state) load(t *types.Type, src *ssa.Value) *ssa.Value {
1580 s.instrumentFields(t, src, instrumentRead)
1581 return s.rawLoad(t, src)
1582 }
1583
1584 func (s *state) rawLoad(t *types.Type, src *ssa.Value) *ssa.Value {
1585 return s.newValue2(ssa.OpLoad, t, src, s.mem())
1586 }
1587
1588 func (s *state) store(t *types.Type, dst, val *ssa.Value) {
1589 s.vars[memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, t, dst, val, s.mem())
1590 }
1591
1592 func (s *state) zero(t *types.Type, dst *ssa.Value) {
1593 s.instrument(t, dst, instrumentWrite)
1594 store := s.newValue2I(ssa.OpZero, types.TypeMem, t.Size(), dst, s.mem())
1595 store.Aux = t
1596 s.vars[memVar] = store
1597 }
1598
1599 func (s *state) move(t *types.Type, dst, src *ssa.Value) {
1600 s.moveWhichMayOverlap(t, dst, src, false)
1601 }
1602 func (s *state) moveWhichMayOverlap(t *types.Type, dst, src *ssa.Value, mayOverlap bool) {
1603 s.instrumentMove(t, dst, src)
1604 if mayOverlap && t.IsArray() && t.NumElem() > 1 && !ssa.IsInlinableMemmove(dst, src, t.Size(), s.f.Config) {
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628 if t.HasPointers() {
1629 s.rtcall(ir.Syms.Typedmemmove, true, nil, s.reflectType(t), dst, src)
1630
1631
1632
1633
1634 s.curfn.SetWBPos(s.peekPos())
1635 } else {
1636 s.rtcall(ir.Syms.Memmove, true, nil, dst, src, s.constInt(types.Types[types.TUINTPTR], t.Size()))
1637 }
1638 ssa.LogLargeCopy(s.f.Name, s.peekPos(), t.Size())
1639 return
1640 }
1641 store := s.newValue3I(ssa.OpMove, types.TypeMem, t.Size(), dst, src, s.mem())
1642 store.Aux = t
1643 s.vars[memVar] = store
1644 }
1645
1646
1647 func (s *state) stmtList(l ir.Nodes) {
1648 for _, n := range l {
1649 s.stmt(n)
1650 }
1651 }
1652
1653 func peelConvNop(n ir.Node) ir.Node {
1654 if n == nil {
1655 return n
1656 }
1657 for n.Op() == ir.OCONVNOP {
1658 n = n.(*ir.ConvExpr).X
1659 }
1660 return n
1661 }
1662
1663
1664 func (s *state) stmt(n ir.Node) {
1665 s.pushLine(n.Pos())
1666 defer s.popLine()
1667
1668
1669
1670 if s.curBlock == nil && n.Op() != ir.OLABEL {
1671 return
1672 }
1673
1674 s.stmtList(n.Init())
1675 switch n.Op() {
1676
1677 case ir.OBLOCK:
1678 n := n.(*ir.BlockStmt)
1679 s.stmtList(n.List)
1680
1681 case ir.OFALL:
1682
1683
1684 case ir.OCALLFUNC:
1685 n := n.(*ir.CallExpr)
1686 if ir.IsIntrinsicCall(n) {
1687 s.intrinsicCall(n)
1688 return
1689 }
1690 fallthrough
1691
1692 case ir.OCALLINTER:
1693 n := n.(*ir.CallExpr)
1694 s.callResult(n, callNormal)
1695 if n.Op() == ir.OCALLFUNC && n.Fun.Op() == ir.ONAME && n.Fun.(*ir.Name).Class == ir.PFUNC {
1696 if fn := n.Fun.Sym().Name; base.Flag.CompilingRuntime && fn == "throw" ||
1697 n.Fun.Sym().Pkg == ir.Pkgs.Runtime &&
1698 (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" ||
1699 fn == "panicmakeslicelen" || fn == "panicmakeslicecap" || fn == "panicunsafeslicelen" ||
1700 fn == "panicunsafeslicenilptr" || fn == "panicunsafestringlen" || fn == "panicunsafestringnilptr" ||
1701 fn == "panicrangestate") {
1702 m := s.mem()
1703 b := s.endBlock()
1704 b.Kind = ssa.BlockExit
1705 b.SetControl(m)
1706
1707
1708
1709 }
1710 }
1711 case ir.ODEFER:
1712 n := n.(*ir.GoDeferStmt)
1713 if base.Debug.Defer > 0 {
1714 var defertype string
1715 if s.hasOpenDefers {
1716 defertype = "open-coded"
1717 } else if n.Esc() == ir.EscNever {
1718 defertype = "stack-allocated"
1719 } else {
1720 defertype = "heap-allocated"
1721 }
1722 base.WarnfAt(n.Pos(), "%s defer", defertype)
1723 }
1724 if s.hasOpenDefers {
1725 s.openDeferRecord(n.Call.(*ir.CallExpr))
1726 } else {
1727 d := callDefer
1728 if n.Esc() == ir.EscNever && n.DeferAt == nil {
1729 d = callDeferStack
1730 }
1731 s.call(n.Call.(*ir.CallExpr), d, false, n.DeferAt)
1732 }
1733 case ir.OGO:
1734 n := n.(*ir.GoDeferStmt)
1735 s.callResult(n.Call.(*ir.CallExpr), callGo)
1736
1737 case ir.OAS2DOTTYPE:
1738 n := n.(*ir.AssignListStmt)
1739 var res, resok *ssa.Value
1740 if n.Rhs[0].Op() == ir.ODOTTYPE2 {
1741 res, resok = s.dottype(n.Rhs[0].(*ir.TypeAssertExpr), true)
1742 } else {
1743 res, resok = s.dynamicDottype(n.Rhs[0].(*ir.DynamicTypeAssertExpr), true)
1744 }
1745 deref := false
1746 if !ssa.CanSSA(n.Rhs[0].Type()) {
1747 if res.Op != ssa.OpLoad {
1748 s.Fatalf("dottype of non-load")
1749 }
1750 mem := s.mem()
1751 if res.Args[1] != mem {
1752 s.Fatalf("memory no longer live from 2-result dottype load")
1753 }
1754 deref = true
1755 res = res.Args[0]
1756 }
1757 s.assign(n.Lhs[0], res, deref, 0)
1758 s.assign(n.Lhs[1], resok, false, 0)
1759 return
1760
1761 case ir.OAS2FUNC:
1762
1763 n := n.(*ir.AssignListStmt)
1764 call := n.Rhs[0].(*ir.CallExpr)
1765 if !ir.IsIntrinsicCall(call) {
1766 s.Fatalf("non-intrinsic AS2FUNC not expanded %v", call)
1767 }
1768 v := s.intrinsicCall(call)
1769 v1 := s.newValue1(ssa.OpSelect0, n.Lhs[0].Type(), v)
1770 v2 := s.newValue1(ssa.OpSelect1, n.Lhs[1].Type(), v)
1771 s.assign(n.Lhs[0], v1, false, 0)
1772 s.assign(n.Lhs[1], v2, false, 0)
1773 return
1774
1775 case ir.ODCL:
1776 n := n.(*ir.Decl)
1777 if v := n.X; v.Esc() == ir.EscHeap {
1778 s.newHeapaddr(v)
1779 }
1780
1781 case ir.OLABEL:
1782 n := n.(*ir.LabelStmt)
1783 sym := n.Label
1784 if sym.IsBlank() {
1785
1786 break
1787 }
1788 lab := s.label(sym)
1789
1790
1791 if lab.target == nil {
1792 lab.target = s.f.NewBlock(ssa.BlockPlain)
1793 }
1794
1795
1796
1797 if s.curBlock != nil {
1798 b := s.endBlock()
1799 b.AddEdgeTo(lab.target)
1800 }
1801 s.startBlock(lab.target)
1802
1803 case ir.OGOTO:
1804 n := n.(*ir.BranchStmt)
1805 sym := n.Label
1806
1807 lab := s.label(sym)
1808 if lab.target == nil {
1809 lab.target = s.f.NewBlock(ssa.BlockPlain)
1810 }
1811
1812 b := s.endBlock()
1813 b.Pos = s.lastPos.WithIsStmt()
1814 b.AddEdgeTo(lab.target)
1815
1816 case ir.OAS:
1817 n := n.(*ir.AssignStmt)
1818 if n.X == n.Y && n.X.Op() == ir.ONAME {
1819
1820
1821
1822
1823
1824
1825
1826 return
1827 }
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838 ny := peelConvNop(n.Y)
1839 mayOverlap := n.X.Op() == ir.ODEREF && (n.Y != nil && ny.Op() == ir.ODEREF)
1840 if ny != nil && ny.Op() == ir.ODEREF {
1841 p := peelConvNop(ny.(*ir.StarExpr).X)
1842 if p.Op() == ir.OSPTR && p.(*ir.UnaryExpr).X.Type().IsString() {
1843
1844
1845 mayOverlap = false
1846 }
1847 }
1848
1849
1850 rhs := n.Y
1851 if rhs != nil {
1852 switch rhs.Op() {
1853 case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT:
1854
1855
1856
1857 if !ir.IsZero(rhs) {
1858 s.Fatalf("literal with nonzero value in SSA: %v", rhs)
1859 }
1860 rhs = nil
1861 case ir.OAPPEND:
1862 rhs := rhs.(*ir.CallExpr)
1863
1864
1865
1866 if !ir.SameSafeExpr(n.X, rhs.Args[0]) || base.Flag.N != 0 {
1867 break
1868 }
1869
1870
1871
1872 if s.canSSA(n.X) {
1873 if base.Debug.Append > 0 {
1874 base.WarnfAt(n.Pos(), "append: len-only update (in local slice)")
1875 }
1876 break
1877 }
1878 if base.Debug.Append > 0 {
1879 base.WarnfAt(n.Pos(), "append: len-only update")
1880 }
1881 s.append(rhs, true)
1882 return
1883 }
1884 }
1885
1886 if ir.IsBlank(n.X) {
1887
1888
1889 if rhs != nil {
1890 s.expr(rhs)
1891 }
1892 return
1893 }
1894
1895 var t *types.Type
1896 if n.Y != nil {
1897 t = n.Y.Type()
1898 } else {
1899 t = n.X.Type()
1900 }
1901
1902 var r *ssa.Value
1903 deref := !ssa.CanSSA(t)
1904 if deref {
1905 if rhs == nil {
1906 r = nil
1907 } else {
1908 r = s.addr(rhs)
1909 }
1910 } else {
1911 if rhs == nil {
1912 r = s.zeroVal(t)
1913 } else {
1914 r = s.expr(rhs)
1915 }
1916 }
1917
1918 var skip skipMask
1919 if rhs != nil && (rhs.Op() == ir.OSLICE || rhs.Op() == ir.OSLICE3 || rhs.Op() == ir.OSLICESTR) && ir.SameSafeExpr(rhs.(*ir.SliceExpr).X, n.X) {
1920
1921
1922 rhs := rhs.(*ir.SliceExpr)
1923 i, j, k := rhs.Low, rhs.High, rhs.Max
1924 if i != nil && (i.Op() == ir.OLITERAL && i.Val().Kind() == constant.Int && ir.Int64Val(i) == 0) {
1925
1926 i = nil
1927 }
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938 if i == nil {
1939 skip |= skipPtr
1940 if j == nil {
1941 skip |= skipLen
1942 }
1943 if k == nil {
1944 skip |= skipCap
1945 }
1946 }
1947 }
1948
1949 s.assignWhichMayOverlap(n.X, r, deref, skip, mayOverlap)
1950
1951 case ir.OIF:
1952 n := n.(*ir.IfStmt)
1953 if ir.IsConst(n.Cond, constant.Bool) {
1954 s.stmtList(n.Cond.Init())
1955 if ir.BoolVal(n.Cond) {
1956 s.stmtList(n.Body)
1957 } else {
1958 s.stmtList(n.Else)
1959 }
1960 break
1961 }
1962
1963 bEnd := s.f.NewBlock(ssa.BlockPlain)
1964 var likely int8
1965 if n.Likely {
1966 likely = 1
1967 }
1968 var bThen *ssa.Block
1969 if len(n.Body) != 0 {
1970 bThen = s.f.NewBlock(ssa.BlockPlain)
1971 } else {
1972 bThen = bEnd
1973 }
1974 var bElse *ssa.Block
1975 if len(n.Else) != 0 {
1976 bElse = s.f.NewBlock(ssa.BlockPlain)
1977 } else {
1978 bElse = bEnd
1979 }
1980 s.condBranch(n.Cond, bThen, bElse, likely)
1981
1982 if len(n.Body) != 0 {
1983 s.startBlock(bThen)
1984 s.stmtList(n.Body)
1985 if b := s.endBlock(); b != nil {
1986 b.AddEdgeTo(bEnd)
1987 }
1988 }
1989 if len(n.Else) != 0 {
1990 s.startBlock(bElse)
1991 s.stmtList(n.Else)
1992 if b := s.endBlock(); b != nil {
1993 b.AddEdgeTo(bEnd)
1994 }
1995 }
1996 s.startBlock(bEnd)
1997
1998 case ir.ORETURN:
1999 n := n.(*ir.ReturnStmt)
2000 s.stmtList(n.Results)
2001 b := s.exit()
2002 b.Pos = s.lastPos.WithIsStmt()
2003
2004 case ir.OTAILCALL:
2005 n := n.(*ir.TailCallStmt)
2006 s.callResult(n.Call, callTail)
2007 call := s.mem()
2008 b := s.endBlock()
2009 b.Kind = ssa.BlockRetJmp
2010 b.SetControl(call)
2011
2012 case ir.OCONTINUE, ir.OBREAK:
2013 n := n.(*ir.BranchStmt)
2014 var to *ssa.Block
2015 if n.Label == nil {
2016
2017 switch n.Op() {
2018 case ir.OCONTINUE:
2019 to = s.continueTo
2020 case ir.OBREAK:
2021 to = s.breakTo
2022 }
2023 } else {
2024
2025 sym := n.Label
2026 lab := s.label(sym)
2027 switch n.Op() {
2028 case ir.OCONTINUE:
2029 to = lab.continueTarget
2030 case ir.OBREAK:
2031 to = lab.breakTarget
2032 }
2033 }
2034
2035 b := s.endBlock()
2036 b.Pos = s.lastPos.WithIsStmt()
2037 b.AddEdgeTo(to)
2038
2039 case ir.OFOR:
2040
2041
2042 n := n.(*ir.ForStmt)
2043 base.Assert(!n.DistinctVars)
2044 bCond := s.f.NewBlock(ssa.BlockPlain)
2045 bBody := s.f.NewBlock(ssa.BlockPlain)
2046 bIncr := s.f.NewBlock(ssa.BlockPlain)
2047 bEnd := s.f.NewBlock(ssa.BlockPlain)
2048
2049
2050 bBody.Pos = n.Pos()
2051
2052
2053 b := s.endBlock()
2054 b.AddEdgeTo(bCond)
2055
2056
2057 s.startBlock(bCond)
2058 if n.Cond != nil {
2059 s.condBranch(n.Cond, bBody, bEnd, 1)
2060 } else {
2061 b := s.endBlock()
2062 b.Kind = ssa.BlockPlain
2063 b.AddEdgeTo(bBody)
2064 }
2065
2066
2067 prevContinue := s.continueTo
2068 prevBreak := s.breakTo
2069 s.continueTo = bIncr
2070 s.breakTo = bEnd
2071 var lab *ssaLabel
2072 if sym := n.Label; sym != nil {
2073
2074 lab = s.label(sym)
2075 lab.continueTarget = bIncr
2076 lab.breakTarget = bEnd
2077 }
2078
2079
2080 s.startBlock(bBody)
2081 s.stmtList(n.Body)
2082
2083
2084 s.continueTo = prevContinue
2085 s.breakTo = prevBreak
2086 if lab != nil {
2087 lab.continueTarget = nil
2088 lab.breakTarget = nil
2089 }
2090
2091
2092 if b := s.endBlock(); b != nil {
2093 b.AddEdgeTo(bIncr)
2094 }
2095
2096
2097 s.startBlock(bIncr)
2098 if n.Post != nil {
2099 s.stmt(n.Post)
2100 }
2101 if b := s.endBlock(); b != nil {
2102 b.AddEdgeTo(bCond)
2103
2104
2105 if b.Pos == src.NoXPos {
2106 b.Pos = bCond.Pos
2107 }
2108 }
2109
2110 s.startBlock(bEnd)
2111
2112 case ir.OSWITCH, ir.OSELECT:
2113
2114
2115 bEnd := s.f.NewBlock(ssa.BlockPlain)
2116
2117 prevBreak := s.breakTo
2118 s.breakTo = bEnd
2119 var sym *types.Sym
2120 var body ir.Nodes
2121 if n.Op() == ir.OSWITCH {
2122 n := n.(*ir.SwitchStmt)
2123 sym = n.Label
2124 body = n.Compiled
2125 } else {
2126 n := n.(*ir.SelectStmt)
2127 sym = n.Label
2128 body = n.Compiled
2129 }
2130
2131 var lab *ssaLabel
2132 if sym != nil {
2133
2134 lab = s.label(sym)
2135 lab.breakTarget = bEnd
2136 }
2137
2138
2139 s.stmtList(body)
2140
2141 s.breakTo = prevBreak
2142 if lab != nil {
2143 lab.breakTarget = nil
2144 }
2145
2146
2147
2148 if s.curBlock != nil {
2149 m := s.mem()
2150 b := s.endBlock()
2151 b.Kind = ssa.BlockExit
2152 b.SetControl(m)
2153 }
2154 s.startBlock(bEnd)
2155
2156 case ir.OJUMPTABLE:
2157 n := n.(*ir.JumpTableStmt)
2158
2159
2160 jt := s.f.NewBlock(ssa.BlockJumpTable)
2161 bEnd := s.f.NewBlock(ssa.BlockPlain)
2162
2163
2164 idx := s.expr(n.Idx)
2165 unsigned := idx.Type.IsUnsigned()
2166
2167
2168 t := types.Types[types.TUINTPTR]
2169 idx = s.conv(nil, idx, idx.Type, t)
2170
2171
2172
2173
2174
2175
2176
2177 var min, max uint64
2178 if unsigned {
2179 min, _ = constant.Uint64Val(n.Cases[0])
2180 max, _ = constant.Uint64Val(n.Cases[len(n.Cases)-1])
2181 } else {
2182 mn, _ := constant.Int64Val(n.Cases[0])
2183 mx, _ := constant.Int64Val(n.Cases[len(n.Cases)-1])
2184 min = uint64(mn)
2185 max = uint64(mx)
2186 }
2187
2188 idx = s.newValue2(s.ssaOp(ir.OSUB, t), t, idx, s.uintptrConstant(min))
2189 width := s.uintptrConstant(max - min)
2190 cmp := s.newValue2(s.ssaOp(ir.OLE, t), types.Types[types.TBOOL], idx, width)
2191 b := s.endBlock()
2192 b.Kind = ssa.BlockIf
2193 b.SetControl(cmp)
2194 b.AddEdgeTo(jt)
2195 b.AddEdgeTo(bEnd)
2196 b.Likely = ssa.BranchLikely
2197
2198
2199 s.startBlock(jt)
2200 jt.Pos = n.Pos()
2201 if base.Flag.Cfg.SpectreIndex {
2202 idx = s.newValue2(ssa.OpSpectreSliceIndex, t, idx, width)
2203 }
2204 jt.SetControl(idx)
2205
2206
2207 table := make([]*ssa.Block, max-min+1)
2208 for i := range table {
2209 table[i] = bEnd
2210 }
2211 for i := range n.Targets {
2212 c := n.Cases[i]
2213 lab := s.label(n.Targets[i])
2214 if lab.target == nil {
2215 lab.target = s.f.NewBlock(ssa.BlockPlain)
2216 }
2217 var val uint64
2218 if unsigned {
2219 val, _ = constant.Uint64Val(c)
2220 } else {
2221 vl, _ := constant.Int64Val(c)
2222 val = uint64(vl)
2223 }
2224
2225 table[val-min] = lab.target
2226 }
2227 for _, t := range table {
2228 jt.AddEdgeTo(t)
2229 }
2230 s.endBlock()
2231
2232 s.startBlock(bEnd)
2233
2234 case ir.OINTERFACESWITCH:
2235 n := n.(*ir.InterfaceSwitchStmt)
2236 typs := s.f.Config.Types
2237
2238 t := s.expr(n.RuntimeType)
2239 h := s.expr(n.Hash)
2240 d := s.newValue1A(ssa.OpAddr, typs.BytePtr, n.Descriptor, s.sb)
2241
2242
2243 var merge *ssa.Block
2244 if base.Flag.N == 0 && rtabi.UseInterfaceSwitchCache(Arch.LinkArch.Family) {
2245
2246
2247 if intrinsics.lookup(Arch.LinkArch.Arch, "internal/runtime/atomic", "Loadp") == nil {
2248 s.Fatalf("atomic load not available")
2249 }
2250 merge = s.f.NewBlock(ssa.BlockPlain)
2251 cacheHit := s.f.NewBlock(ssa.BlockPlain)
2252 cacheMiss := s.f.NewBlock(ssa.BlockPlain)
2253 loopHead := s.f.NewBlock(ssa.BlockPlain)
2254 loopBody := s.f.NewBlock(ssa.BlockPlain)
2255
2256
2257 var mul, and, add, zext ssa.Op
2258 if s.config.PtrSize == 4 {
2259 mul = ssa.OpMul32
2260 and = ssa.OpAnd32
2261 add = ssa.OpAdd32
2262 zext = ssa.OpCopy
2263 } else {
2264 mul = ssa.OpMul64
2265 and = ssa.OpAnd64
2266 add = ssa.OpAdd64
2267 zext = ssa.OpZeroExt32to64
2268 }
2269
2270
2271
2272 atomicLoad := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(typs.BytePtr, types.TypeMem), d, s.mem())
2273 cache := s.newValue1(ssa.OpSelect0, typs.BytePtr, atomicLoad)
2274 s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, atomicLoad)
2275
2276
2277 s.vars[hashVar] = s.newValue1(zext, typs.Uintptr, h)
2278
2279
2280 mask := s.newValue2(ssa.OpLoad, typs.Uintptr, cache, s.mem())
2281
2282 b := s.endBlock()
2283 b.AddEdgeTo(loopHead)
2284
2285
2286
2287 s.startBlock(loopHead)
2288 entries := s.newValue2(ssa.OpAddPtr, typs.UintptrPtr, cache, s.uintptrConstant(uint64(s.config.PtrSize)))
2289 idx := s.newValue2(and, typs.Uintptr, s.variable(hashVar, typs.Uintptr), mask)
2290 idx = s.newValue2(mul, typs.Uintptr, idx, s.uintptrConstant(uint64(3*s.config.PtrSize)))
2291 e := s.newValue2(ssa.OpAddPtr, typs.UintptrPtr, entries, idx)
2292
2293 s.vars[hashVar] = s.newValue2(add, typs.Uintptr, s.variable(hashVar, typs.Uintptr), s.uintptrConstant(1))
2294
2295
2296
2297 eTyp := s.newValue2(ssa.OpLoad, typs.Uintptr, e, s.mem())
2298 cmp1 := s.newValue2(ssa.OpEqPtr, typs.Bool, t, eTyp)
2299 b = s.endBlock()
2300 b.Kind = ssa.BlockIf
2301 b.SetControl(cmp1)
2302 b.AddEdgeTo(cacheHit)
2303 b.AddEdgeTo(loopBody)
2304
2305
2306
2307 s.startBlock(loopBody)
2308 cmp2 := s.newValue2(ssa.OpEqPtr, typs.Bool, eTyp, s.constNil(typs.BytePtr))
2309 b = s.endBlock()
2310 b.Kind = ssa.BlockIf
2311 b.SetControl(cmp2)
2312 b.AddEdgeTo(cacheMiss)
2313 b.AddEdgeTo(loopHead)
2314
2315
2316
2317
2318 s.startBlock(cacheHit)
2319 eCase := s.newValue2(ssa.OpLoad, typs.Int, s.newValue1I(ssa.OpOffPtr, typs.IntPtr, s.config.PtrSize, e), s.mem())
2320 eItab := s.newValue2(ssa.OpLoad, typs.BytePtr, s.newValue1I(ssa.OpOffPtr, typs.BytePtrPtr, 2*s.config.PtrSize, e), s.mem())
2321 s.assign(n.Case, eCase, false, 0)
2322 s.assign(n.Itab, eItab, false, 0)
2323 b = s.endBlock()
2324 b.AddEdgeTo(merge)
2325
2326
2327 s.startBlock(cacheMiss)
2328 }
2329
2330 r := s.rtcall(ir.Syms.InterfaceSwitch, true, []*types.Type{typs.Int, typs.BytePtr}, d, t)
2331 s.assign(n.Case, r[0], false, 0)
2332 s.assign(n.Itab, r[1], false, 0)
2333
2334 if merge != nil {
2335
2336 b := s.endBlock()
2337 b.Kind = ssa.BlockPlain
2338 b.AddEdgeTo(merge)
2339 s.startBlock(merge)
2340 }
2341
2342 case ir.OCHECKNIL:
2343 n := n.(*ir.UnaryExpr)
2344 p := s.expr(n.X)
2345 _ = s.nilCheck(p)
2346
2347
2348 case ir.OINLMARK:
2349 n := n.(*ir.InlineMarkStmt)
2350 s.newValue1I(ssa.OpInlMark, types.TypeVoid, n.Index, s.mem())
2351
2352 default:
2353 s.Fatalf("unhandled stmt %v", n.Op())
2354 }
2355 }
2356
2357
2358
2359 const shareDeferExits = false
2360
2361
2362
2363
2364 func (s *state) exit() *ssa.Block {
2365 if s.hasdefer {
2366 if s.hasOpenDefers {
2367 if shareDeferExits && s.lastDeferExit != nil && len(s.openDefers) == s.lastDeferCount {
2368 if s.curBlock.Kind != ssa.BlockPlain {
2369 panic("Block for an exit should be BlockPlain")
2370 }
2371 s.curBlock.AddEdgeTo(s.lastDeferExit)
2372 s.endBlock()
2373 return s.lastDeferFinalBlock
2374 }
2375 s.openDeferExit()
2376 } else {
2377
2378
2379
2380
2381
2382
2383
2384
2385 s.pushLine(s.curfn.Endlineno)
2386 s.rtcall(ir.Syms.Deferreturn, true, nil)
2387 s.popLine()
2388 }
2389 }
2390
2391
2392
2393 resultFields := s.curfn.Type().Results()
2394 results := make([]*ssa.Value, len(resultFields)+1, len(resultFields)+1)
2395
2396 for i, f := range resultFields {
2397 n := f.Nname.(*ir.Name)
2398 if s.canSSA(n) {
2399 if !n.IsOutputParamInRegisters() && n.Type().HasPointers() {
2400
2401 s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, n, s.mem())
2402 }
2403 results[i] = s.variable(n, n.Type())
2404 } else if !n.OnStack() {
2405
2406 if n.Type().HasPointers() {
2407 s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, n, s.mem())
2408 }
2409 ha := s.expr(n.Heapaddr)
2410 s.instrumentFields(n.Type(), ha, instrumentRead)
2411 results[i] = s.newValue2(ssa.OpDereference, n.Type(), ha, s.mem())
2412 } else {
2413
2414
2415
2416 results[i] = s.newValue2(ssa.OpDereference, n.Type(), s.addr(n), s.mem())
2417 }
2418 }
2419
2420
2421
2422
2423 if s.instrumentEnterExit {
2424 s.rtcall(ir.Syms.Racefuncexit, true, nil)
2425 }
2426
2427 results[len(results)-1] = s.mem()
2428 m := s.newValue0(ssa.OpMakeResult, s.f.OwnAux.LateExpansionResultType())
2429 m.AddArgs(results...)
2430
2431 b := s.endBlock()
2432 b.Kind = ssa.BlockRet
2433 b.SetControl(m)
2434 if s.hasdefer && s.hasOpenDefers {
2435 s.lastDeferFinalBlock = b
2436 }
2437 return b
2438 }
2439
2440 type opAndType struct {
2441 op ir.Op
2442 etype types.Kind
2443 }
2444
2445 var opToSSA = map[opAndType]ssa.Op{
2446 {ir.OADD, types.TINT8}: ssa.OpAdd8,
2447 {ir.OADD, types.TUINT8}: ssa.OpAdd8,
2448 {ir.OADD, types.TINT16}: ssa.OpAdd16,
2449 {ir.OADD, types.TUINT16}: ssa.OpAdd16,
2450 {ir.OADD, types.TINT32}: ssa.OpAdd32,
2451 {ir.OADD, types.TUINT32}: ssa.OpAdd32,
2452 {ir.OADD, types.TINT64}: ssa.OpAdd64,
2453 {ir.OADD, types.TUINT64}: ssa.OpAdd64,
2454 {ir.OADD, types.TFLOAT32}: ssa.OpAdd32F,
2455 {ir.OADD, types.TFLOAT64}: ssa.OpAdd64F,
2456
2457 {ir.OSUB, types.TINT8}: ssa.OpSub8,
2458 {ir.OSUB, types.TUINT8}: ssa.OpSub8,
2459 {ir.OSUB, types.TINT16}: ssa.OpSub16,
2460 {ir.OSUB, types.TUINT16}: ssa.OpSub16,
2461 {ir.OSUB, types.TINT32}: ssa.OpSub32,
2462 {ir.OSUB, types.TUINT32}: ssa.OpSub32,
2463 {ir.OSUB, types.TINT64}: ssa.OpSub64,
2464 {ir.OSUB, types.TUINT64}: ssa.OpSub64,
2465 {ir.OSUB, types.TFLOAT32}: ssa.OpSub32F,
2466 {ir.OSUB, types.TFLOAT64}: ssa.OpSub64F,
2467
2468 {ir.ONOT, types.TBOOL}: ssa.OpNot,
2469
2470 {ir.ONEG, types.TINT8}: ssa.OpNeg8,
2471 {ir.ONEG, types.TUINT8}: ssa.OpNeg8,
2472 {ir.ONEG, types.TINT16}: ssa.OpNeg16,
2473 {ir.ONEG, types.TUINT16}: ssa.OpNeg16,
2474 {ir.ONEG, types.TINT32}: ssa.OpNeg32,
2475 {ir.ONEG, types.TUINT32}: ssa.OpNeg32,
2476 {ir.ONEG, types.TINT64}: ssa.OpNeg64,
2477 {ir.ONEG, types.TUINT64}: ssa.OpNeg64,
2478 {ir.ONEG, types.TFLOAT32}: ssa.OpNeg32F,
2479 {ir.ONEG, types.TFLOAT64}: ssa.OpNeg64F,
2480
2481 {ir.OBITNOT, types.TINT8}: ssa.OpCom8,
2482 {ir.OBITNOT, types.TUINT8}: ssa.OpCom8,
2483 {ir.OBITNOT, types.TINT16}: ssa.OpCom16,
2484 {ir.OBITNOT, types.TUINT16}: ssa.OpCom16,
2485 {ir.OBITNOT, types.TINT32}: ssa.OpCom32,
2486 {ir.OBITNOT, types.TUINT32}: ssa.OpCom32,
2487 {ir.OBITNOT, types.TINT64}: ssa.OpCom64,
2488 {ir.OBITNOT, types.TUINT64}: ssa.OpCom64,
2489
2490 {ir.OIMAG, types.TCOMPLEX64}: ssa.OpComplexImag,
2491 {ir.OIMAG, types.TCOMPLEX128}: ssa.OpComplexImag,
2492 {ir.OREAL, types.TCOMPLEX64}: ssa.OpComplexReal,
2493 {ir.OREAL, types.TCOMPLEX128}: ssa.OpComplexReal,
2494
2495 {ir.OMUL, types.TINT8}: ssa.OpMul8,
2496 {ir.OMUL, types.TUINT8}: ssa.OpMul8,
2497 {ir.OMUL, types.TINT16}: ssa.OpMul16,
2498 {ir.OMUL, types.TUINT16}: ssa.OpMul16,
2499 {ir.OMUL, types.TINT32}: ssa.OpMul32,
2500 {ir.OMUL, types.TUINT32}: ssa.OpMul32,
2501 {ir.OMUL, types.TINT64}: ssa.OpMul64,
2502 {ir.OMUL, types.TUINT64}: ssa.OpMul64,
2503 {ir.OMUL, types.TFLOAT32}: ssa.OpMul32F,
2504 {ir.OMUL, types.TFLOAT64}: ssa.OpMul64F,
2505
2506 {ir.ODIV, types.TFLOAT32}: ssa.OpDiv32F,
2507 {ir.ODIV, types.TFLOAT64}: ssa.OpDiv64F,
2508
2509 {ir.ODIV, types.TINT8}: ssa.OpDiv8,
2510 {ir.ODIV, types.TUINT8}: ssa.OpDiv8u,
2511 {ir.ODIV, types.TINT16}: ssa.OpDiv16,
2512 {ir.ODIV, types.TUINT16}: ssa.OpDiv16u,
2513 {ir.ODIV, types.TINT32}: ssa.OpDiv32,
2514 {ir.ODIV, types.TUINT32}: ssa.OpDiv32u,
2515 {ir.ODIV, types.TINT64}: ssa.OpDiv64,
2516 {ir.ODIV, types.TUINT64}: ssa.OpDiv64u,
2517
2518 {ir.OMOD, types.TINT8}: ssa.OpMod8,
2519 {ir.OMOD, types.TUINT8}: ssa.OpMod8u,
2520 {ir.OMOD, types.TINT16}: ssa.OpMod16,
2521 {ir.OMOD, types.TUINT16}: ssa.OpMod16u,
2522 {ir.OMOD, types.TINT32}: ssa.OpMod32,
2523 {ir.OMOD, types.TUINT32}: ssa.OpMod32u,
2524 {ir.OMOD, types.TINT64}: ssa.OpMod64,
2525 {ir.OMOD, types.TUINT64}: ssa.OpMod64u,
2526
2527 {ir.OAND, types.TINT8}: ssa.OpAnd8,
2528 {ir.OAND, types.TUINT8}: ssa.OpAnd8,
2529 {ir.OAND, types.TINT16}: ssa.OpAnd16,
2530 {ir.OAND, types.TUINT16}: ssa.OpAnd16,
2531 {ir.OAND, types.TINT32}: ssa.OpAnd32,
2532 {ir.OAND, types.TUINT32}: ssa.OpAnd32,
2533 {ir.OAND, types.TINT64}: ssa.OpAnd64,
2534 {ir.OAND, types.TUINT64}: ssa.OpAnd64,
2535
2536 {ir.OOR, types.TINT8}: ssa.OpOr8,
2537 {ir.OOR, types.TUINT8}: ssa.OpOr8,
2538 {ir.OOR, types.TINT16}: ssa.OpOr16,
2539 {ir.OOR, types.TUINT16}: ssa.OpOr16,
2540 {ir.OOR, types.TINT32}: ssa.OpOr32,
2541 {ir.OOR, types.TUINT32}: ssa.OpOr32,
2542 {ir.OOR, types.TINT64}: ssa.OpOr64,
2543 {ir.OOR, types.TUINT64}: ssa.OpOr64,
2544
2545 {ir.OXOR, types.TINT8}: ssa.OpXor8,
2546 {ir.OXOR, types.TUINT8}: ssa.OpXor8,
2547 {ir.OXOR, types.TINT16}: ssa.OpXor16,
2548 {ir.OXOR, types.TUINT16}: ssa.OpXor16,
2549 {ir.OXOR, types.TINT32}: ssa.OpXor32,
2550 {ir.OXOR, types.TUINT32}: ssa.OpXor32,
2551 {ir.OXOR, types.TINT64}: ssa.OpXor64,
2552 {ir.OXOR, types.TUINT64}: ssa.OpXor64,
2553
2554 {ir.OEQ, types.TBOOL}: ssa.OpEqB,
2555 {ir.OEQ, types.TINT8}: ssa.OpEq8,
2556 {ir.OEQ, types.TUINT8}: ssa.OpEq8,
2557 {ir.OEQ, types.TINT16}: ssa.OpEq16,
2558 {ir.OEQ, types.TUINT16}: ssa.OpEq16,
2559 {ir.OEQ, types.TINT32}: ssa.OpEq32,
2560 {ir.OEQ, types.TUINT32}: ssa.OpEq32,
2561 {ir.OEQ, types.TINT64}: ssa.OpEq64,
2562 {ir.OEQ, types.TUINT64}: ssa.OpEq64,
2563 {ir.OEQ, types.TINTER}: ssa.OpEqInter,
2564 {ir.OEQ, types.TSLICE}: ssa.OpEqSlice,
2565 {ir.OEQ, types.TFUNC}: ssa.OpEqPtr,
2566 {ir.OEQ, types.TMAP}: ssa.OpEqPtr,
2567 {ir.OEQ, types.TCHAN}: ssa.OpEqPtr,
2568 {ir.OEQ, types.TPTR}: ssa.OpEqPtr,
2569 {ir.OEQ, types.TUINTPTR}: ssa.OpEqPtr,
2570 {ir.OEQ, types.TUNSAFEPTR}: ssa.OpEqPtr,
2571 {ir.OEQ, types.TFLOAT64}: ssa.OpEq64F,
2572 {ir.OEQ, types.TFLOAT32}: ssa.OpEq32F,
2573
2574 {ir.ONE, types.TBOOL}: ssa.OpNeqB,
2575 {ir.ONE, types.TINT8}: ssa.OpNeq8,
2576 {ir.ONE, types.TUINT8}: ssa.OpNeq8,
2577 {ir.ONE, types.TINT16}: ssa.OpNeq16,
2578 {ir.ONE, types.TUINT16}: ssa.OpNeq16,
2579 {ir.ONE, types.TINT32}: ssa.OpNeq32,
2580 {ir.ONE, types.TUINT32}: ssa.OpNeq32,
2581 {ir.ONE, types.TINT64}: ssa.OpNeq64,
2582 {ir.ONE, types.TUINT64}: ssa.OpNeq64,
2583 {ir.ONE, types.TINTER}: ssa.OpNeqInter,
2584 {ir.ONE, types.TSLICE}: ssa.OpNeqSlice,
2585 {ir.ONE, types.TFUNC}: ssa.OpNeqPtr,
2586 {ir.ONE, types.TMAP}: ssa.OpNeqPtr,
2587 {ir.ONE, types.TCHAN}: ssa.OpNeqPtr,
2588 {ir.ONE, types.TPTR}: ssa.OpNeqPtr,
2589 {ir.ONE, types.TUINTPTR}: ssa.OpNeqPtr,
2590 {ir.ONE, types.TUNSAFEPTR}: ssa.OpNeqPtr,
2591 {ir.ONE, types.TFLOAT64}: ssa.OpNeq64F,
2592 {ir.ONE, types.TFLOAT32}: ssa.OpNeq32F,
2593
2594 {ir.OLT, types.TINT8}: ssa.OpLess8,
2595 {ir.OLT, types.TUINT8}: ssa.OpLess8U,
2596 {ir.OLT, types.TINT16}: ssa.OpLess16,
2597 {ir.OLT, types.TUINT16}: ssa.OpLess16U,
2598 {ir.OLT, types.TINT32}: ssa.OpLess32,
2599 {ir.OLT, types.TUINT32}: ssa.OpLess32U,
2600 {ir.OLT, types.TINT64}: ssa.OpLess64,
2601 {ir.OLT, types.TUINT64}: ssa.OpLess64U,
2602 {ir.OLT, types.TFLOAT64}: ssa.OpLess64F,
2603 {ir.OLT, types.TFLOAT32}: ssa.OpLess32F,
2604
2605 {ir.OLE, types.TINT8}: ssa.OpLeq8,
2606 {ir.OLE, types.TUINT8}: ssa.OpLeq8U,
2607 {ir.OLE, types.TINT16}: ssa.OpLeq16,
2608 {ir.OLE, types.TUINT16}: ssa.OpLeq16U,
2609 {ir.OLE, types.TINT32}: ssa.OpLeq32,
2610 {ir.OLE, types.TUINT32}: ssa.OpLeq32U,
2611 {ir.OLE, types.TINT64}: ssa.OpLeq64,
2612 {ir.OLE, types.TUINT64}: ssa.OpLeq64U,
2613 {ir.OLE, types.TFLOAT64}: ssa.OpLeq64F,
2614 {ir.OLE, types.TFLOAT32}: ssa.OpLeq32F,
2615 }
2616
2617 func (s *state) concreteEtype(t *types.Type) types.Kind {
2618 e := t.Kind()
2619 switch e {
2620 default:
2621 return e
2622 case types.TINT:
2623 if s.config.PtrSize == 8 {
2624 return types.TINT64
2625 }
2626 return types.TINT32
2627 case types.TUINT:
2628 if s.config.PtrSize == 8 {
2629 return types.TUINT64
2630 }
2631 return types.TUINT32
2632 case types.TUINTPTR:
2633 if s.config.PtrSize == 8 {
2634 return types.TUINT64
2635 }
2636 return types.TUINT32
2637 }
2638 }
2639
2640 func (s *state) ssaOp(op ir.Op, t *types.Type) ssa.Op {
2641 etype := s.concreteEtype(t)
2642 x, ok := opToSSA[opAndType{op, etype}]
2643 if !ok {
2644 s.Fatalf("unhandled binary op %v %s", op, etype)
2645 }
2646 return x
2647 }
2648
2649 type opAndTwoTypes struct {
2650 op ir.Op
2651 etype1 types.Kind
2652 etype2 types.Kind
2653 }
2654
2655 type twoTypes struct {
2656 etype1 types.Kind
2657 etype2 types.Kind
2658 }
2659
2660 type twoOpsAndType struct {
2661 op1 ssa.Op
2662 op2 ssa.Op
2663 intermediateType types.Kind
2664 }
2665
2666 var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
2667
2668 {types.TINT8, types.TFLOAT32}: {ssa.OpSignExt8to32, ssa.OpCvt32to32F, types.TINT32},
2669 {types.TINT16, types.TFLOAT32}: {ssa.OpSignExt16to32, ssa.OpCvt32to32F, types.TINT32},
2670 {types.TINT32, types.TFLOAT32}: {ssa.OpCopy, ssa.OpCvt32to32F, types.TINT32},
2671 {types.TINT64, types.TFLOAT32}: {ssa.OpCopy, ssa.OpCvt64to32F, types.TINT64},
2672
2673 {types.TINT8, types.TFLOAT64}: {ssa.OpSignExt8to32, ssa.OpCvt32to64F, types.TINT32},
2674 {types.TINT16, types.TFLOAT64}: {ssa.OpSignExt16to32, ssa.OpCvt32to64F, types.TINT32},
2675 {types.TINT32, types.TFLOAT64}: {ssa.OpCopy, ssa.OpCvt32to64F, types.TINT32},
2676 {types.TINT64, types.TFLOAT64}: {ssa.OpCopy, ssa.OpCvt64to64F, types.TINT64},
2677
2678 {types.TFLOAT32, types.TINT8}: {ssa.OpCvt32Fto32, ssa.OpTrunc32to8, types.TINT32},
2679 {types.TFLOAT32, types.TINT16}: {ssa.OpCvt32Fto32, ssa.OpTrunc32to16, types.TINT32},
2680 {types.TFLOAT32, types.TINT32}: {ssa.OpCvt32Fto32, ssa.OpCopy, types.TINT32},
2681 {types.TFLOAT32, types.TINT64}: {ssa.OpCvt32Fto64, ssa.OpCopy, types.TINT64},
2682
2683 {types.TFLOAT64, types.TINT8}: {ssa.OpCvt64Fto32, ssa.OpTrunc32to8, types.TINT32},
2684 {types.TFLOAT64, types.TINT16}: {ssa.OpCvt64Fto32, ssa.OpTrunc32to16, types.TINT32},
2685 {types.TFLOAT64, types.TINT32}: {ssa.OpCvt64Fto32, ssa.OpCopy, types.TINT32},
2686 {types.TFLOAT64, types.TINT64}: {ssa.OpCvt64Fto64, ssa.OpCopy, types.TINT64},
2687
2688 {types.TUINT8, types.TFLOAT32}: {ssa.OpZeroExt8to32, ssa.OpCvt32to32F, types.TINT32},
2689 {types.TUINT16, types.TFLOAT32}: {ssa.OpZeroExt16to32, ssa.OpCvt32to32F, types.TINT32},
2690 {types.TUINT32, types.TFLOAT32}: {ssa.OpZeroExt32to64, ssa.OpCvt64to32F, types.TINT64},
2691 {types.TUINT64, types.TFLOAT32}: {ssa.OpCopy, ssa.OpInvalid, types.TUINT64},
2692
2693 {types.TUINT8, types.TFLOAT64}: {ssa.OpZeroExt8to32, ssa.OpCvt32to64F, types.TINT32},
2694 {types.TUINT16, types.TFLOAT64}: {ssa.OpZeroExt16to32, ssa.OpCvt32to64F, types.TINT32},
2695 {types.TUINT32, types.TFLOAT64}: {ssa.OpZeroExt32to64, ssa.OpCvt64to64F, types.TINT64},
2696 {types.TUINT64, types.TFLOAT64}: {ssa.OpCopy, ssa.OpInvalid, types.TUINT64},
2697
2698 {types.TFLOAT32, types.TUINT8}: {ssa.OpCvt32Fto32, ssa.OpTrunc32to8, types.TINT32},
2699 {types.TFLOAT32, types.TUINT16}: {ssa.OpCvt32Fto32, ssa.OpTrunc32to16, types.TINT32},
2700 {types.TFLOAT32, types.TUINT32}: {ssa.OpInvalid, ssa.OpCopy, types.TINT64},
2701 {types.TFLOAT32, types.TUINT64}: {ssa.OpInvalid, ssa.OpCopy, types.TUINT64},
2702
2703 {types.TFLOAT64, types.TUINT8}: {ssa.OpCvt64Fto32, ssa.OpTrunc32to8, types.TINT32},
2704 {types.TFLOAT64, types.TUINT16}: {ssa.OpCvt64Fto32, ssa.OpTrunc32to16, types.TINT32},
2705 {types.TFLOAT64, types.TUINT32}: {ssa.OpInvalid, ssa.OpCopy, types.TINT64},
2706 {types.TFLOAT64, types.TUINT64}: {ssa.OpInvalid, ssa.OpCopy, types.TUINT64},
2707
2708
2709 {types.TFLOAT64, types.TFLOAT32}: {ssa.OpCvt64Fto32F, ssa.OpCopy, types.TFLOAT32},
2710 {types.TFLOAT64, types.TFLOAT64}: {ssa.OpRound64F, ssa.OpCopy, types.TFLOAT64},
2711 {types.TFLOAT32, types.TFLOAT32}: {ssa.OpRound32F, ssa.OpCopy, types.TFLOAT32},
2712 {types.TFLOAT32, types.TFLOAT64}: {ssa.OpCvt32Fto64F, ssa.OpCopy, types.TFLOAT64},
2713 }
2714
2715
2716
2717 var fpConvOpToSSA32 = map[twoTypes]twoOpsAndType{
2718 {types.TUINT32, types.TFLOAT32}: {ssa.OpCopy, ssa.OpCvt32Uto32F, types.TUINT32},
2719 {types.TUINT32, types.TFLOAT64}: {ssa.OpCopy, ssa.OpCvt32Uto64F, types.TUINT32},
2720 {types.TFLOAT32, types.TUINT32}: {ssa.OpCvt32Fto32U, ssa.OpCopy, types.TUINT32},
2721 {types.TFLOAT64, types.TUINT32}: {ssa.OpCvt64Fto32U, ssa.OpCopy, types.TUINT32},
2722 }
2723
2724
2725 var uint64fpConvOpToSSA = map[twoTypes]twoOpsAndType{
2726 {types.TUINT64, types.TFLOAT32}: {ssa.OpCopy, ssa.OpCvt64Uto32F, types.TUINT64},
2727 {types.TUINT64, types.TFLOAT64}: {ssa.OpCopy, ssa.OpCvt64Uto64F, types.TUINT64},
2728 {types.TFLOAT32, types.TUINT64}: {ssa.OpCvt32Fto64U, ssa.OpCopy, types.TUINT64},
2729 {types.TFLOAT64, types.TUINT64}: {ssa.OpCvt64Fto64U, ssa.OpCopy, types.TUINT64},
2730 }
2731
2732 var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
2733 {ir.OLSH, types.TINT8, types.TUINT8}: ssa.OpLsh8x8,
2734 {ir.OLSH, types.TUINT8, types.TUINT8}: ssa.OpLsh8x8,
2735 {ir.OLSH, types.TINT8, types.TUINT16}: ssa.OpLsh8x16,
2736 {ir.OLSH, types.TUINT8, types.TUINT16}: ssa.OpLsh8x16,
2737 {ir.OLSH, types.TINT8, types.TUINT32}: ssa.OpLsh8x32,
2738 {ir.OLSH, types.TUINT8, types.TUINT32}: ssa.OpLsh8x32,
2739 {ir.OLSH, types.TINT8, types.TUINT64}: ssa.OpLsh8x64,
2740 {ir.OLSH, types.TUINT8, types.TUINT64}: ssa.OpLsh8x64,
2741
2742 {ir.OLSH, types.TINT16, types.TUINT8}: ssa.OpLsh16x8,
2743 {ir.OLSH, types.TUINT16, types.TUINT8}: ssa.OpLsh16x8,
2744 {ir.OLSH, types.TINT16, types.TUINT16}: ssa.OpLsh16x16,
2745 {ir.OLSH, types.TUINT16, types.TUINT16}: ssa.OpLsh16x16,
2746 {ir.OLSH, types.TINT16, types.TUINT32}: ssa.OpLsh16x32,
2747 {ir.OLSH, types.TUINT16, types.TUINT32}: ssa.OpLsh16x32,
2748 {ir.OLSH, types.TINT16, types.TUINT64}: ssa.OpLsh16x64,
2749 {ir.OLSH, types.TUINT16, types.TUINT64}: ssa.OpLsh16x64,
2750
2751 {ir.OLSH, types.TINT32, types.TUINT8}: ssa.OpLsh32x8,
2752 {ir.OLSH, types.TUINT32, types.TUINT8}: ssa.OpLsh32x8,
2753 {ir.OLSH, types.TINT32, types.TUINT16}: ssa.OpLsh32x16,
2754 {ir.OLSH, types.TUINT32, types.TUINT16}: ssa.OpLsh32x16,
2755 {ir.OLSH, types.TINT32, types.TUINT32}: ssa.OpLsh32x32,
2756 {ir.OLSH, types.TUINT32, types.TUINT32}: ssa.OpLsh32x32,
2757 {ir.OLSH, types.TINT32, types.TUINT64}: ssa.OpLsh32x64,
2758 {ir.OLSH, types.TUINT32, types.TUINT64}: ssa.OpLsh32x64,
2759
2760 {ir.OLSH, types.TINT64, types.TUINT8}: ssa.OpLsh64x8,
2761 {ir.OLSH, types.TUINT64, types.TUINT8}: ssa.OpLsh64x8,
2762 {ir.OLSH, types.TINT64, types.TUINT16}: ssa.OpLsh64x16,
2763 {ir.OLSH, types.TUINT64, types.TUINT16}: ssa.OpLsh64x16,
2764 {ir.OLSH, types.TINT64, types.TUINT32}: ssa.OpLsh64x32,
2765 {ir.OLSH, types.TUINT64, types.TUINT32}: ssa.OpLsh64x32,
2766 {ir.OLSH, types.TINT64, types.TUINT64}: ssa.OpLsh64x64,
2767 {ir.OLSH, types.TUINT64, types.TUINT64}: ssa.OpLsh64x64,
2768
2769 {ir.ORSH, types.TINT8, types.TUINT8}: ssa.OpRsh8x8,
2770 {ir.ORSH, types.TUINT8, types.TUINT8}: ssa.OpRsh8Ux8,
2771 {ir.ORSH, types.TINT8, types.TUINT16}: ssa.OpRsh8x16,
2772 {ir.ORSH, types.TUINT8, types.TUINT16}: ssa.OpRsh8Ux16,
2773 {ir.ORSH, types.TINT8, types.TUINT32}: ssa.OpRsh8x32,
2774 {ir.ORSH, types.TUINT8, types.TUINT32}: ssa.OpRsh8Ux32,
2775 {ir.ORSH, types.TINT8, types.TUINT64}: ssa.OpRsh8x64,
2776 {ir.ORSH, types.TUINT8, types.TUINT64}: ssa.OpRsh8Ux64,
2777
2778 {ir.ORSH, types.TINT16, types.TUINT8}: ssa.OpRsh16x8,
2779 {ir.ORSH, types.TUINT16, types.TUINT8}: ssa.OpRsh16Ux8,
2780 {ir.ORSH, types.TINT16, types.TUINT16}: ssa.OpRsh16x16,
2781 {ir.ORSH, types.TUINT16, types.TUINT16}: ssa.OpRsh16Ux16,
2782 {ir.ORSH, types.TINT16, types.TUINT32}: ssa.OpRsh16x32,
2783 {ir.ORSH, types.TUINT16, types.TUINT32}: ssa.OpRsh16Ux32,
2784 {ir.ORSH, types.TINT16, types.TUINT64}: ssa.OpRsh16x64,
2785 {ir.ORSH, types.TUINT16, types.TUINT64}: ssa.OpRsh16Ux64,
2786
2787 {ir.ORSH, types.TINT32, types.TUINT8}: ssa.OpRsh32x8,
2788 {ir.ORSH, types.TUINT32, types.TUINT8}: ssa.OpRsh32Ux8,
2789 {ir.ORSH, types.TINT32, types.TUINT16}: ssa.OpRsh32x16,
2790 {ir.ORSH, types.TUINT32, types.TUINT16}: ssa.OpRsh32Ux16,
2791 {ir.ORSH, types.TINT32, types.TUINT32}: ssa.OpRsh32x32,
2792 {ir.ORSH, types.TUINT32, types.TUINT32}: ssa.OpRsh32Ux32,
2793 {ir.ORSH, types.TINT32, types.TUINT64}: ssa.OpRsh32x64,
2794 {ir.ORSH, types.TUINT32, types.TUINT64}: ssa.OpRsh32Ux64,
2795
2796 {ir.ORSH, types.TINT64, types.TUINT8}: ssa.OpRsh64x8,
2797 {ir.ORSH, types.TUINT64, types.TUINT8}: ssa.OpRsh64Ux8,
2798 {ir.ORSH, types.TINT64, types.TUINT16}: ssa.OpRsh64x16,
2799 {ir.ORSH, types.TUINT64, types.TUINT16}: ssa.OpRsh64Ux16,
2800 {ir.ORSH, types.TINT64, types.TUINT32}: ssa.OpRsh64x32,
2801 {ir.ORSH, types.TUINT64, types.TUINT32}: ssa.OpRsh64Ux32,
2802 {ir.ORSH, types.TINT64, types.TUINT64}: ssa.OpRsh64x64,
2803 {ir.ORSH, types.TUINT64, types.TUINT64}: ssa.OpRsh64Ux64,
2804 }
2805
2806 func (s *state) ssaShiftOp(op ir.Op, t *types.Type, u *types.Type) ssa.Op {
2807 etype1 := s.concreteEtype(t)
2808 etype2 := s.concreteEtype(u)
2809 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
2810 if !ok {
2811 s.Fatalf("unhandled shift op %v etype=%s/%s", op, etype1, etype2)
2812 }
2813 return x
2814 }
2815
2816 func (s *state) uintptrConstant(v uint64) *ssa.Value {
2817 if s.config.PtrSize == 4 {
2818 return s.newValue0I(ssa.OpConst32, types.Types[types.TUINTPTR], int64(v))
2819 }
2820 return s.newValue0I(ssa.OpConst64, types.Types[types.TUINTPTR], int64(v))
2821 }
2822
2823 func (s *state) conv(n ir.Node, v *ssa.Value, ft, tt *types.Type) *ssa.Value {
2824 if ft.IsBoolean() && tt.IsKind(types.TUINT8) {
2825
2826 return s.newValue1(ssa.OpCvtBoolToUint8, tt, v)
2827 }
2828 if ft.IsInteger() && tt.IsInteger() {
2829 var op ssa.Op
2830 if tt.Size() == ft.Size() {
2831 op = ssa.OpCopy
2832 } else if tt.Size() < ft.Size() {
2833
2834 switch 10*ft.Size() + tt.Size() {
2835 case 21:
2836 op = ssa.OpTrunc16to8
2837 case 41:
2838 op = ssa.OpTrunc32to8
2839 case 42:
2840 op = ssa.OpTrunc32to16
2841 case 81:
2842 op = ssa.OpTrunc64to8
2843 case 82:
2844 op = ssa.OpTrunc64to16
2845 case 84:
2846 op = ssa.OpTrunc64to32
2847 default:
2848 s.Fatalf("weird integer truncation %v -> %v", ft, tt)
2849 }
2850 } else if ft.IsSigned() {
2851
2852 switch 10*ft.Size() + tt.Size() {
2853 case 12:
2854 op = ssa.OpSignExt8to16
2855 case 14:
2856 op = ssa.OpSignExt8to32
2857 case 18:
2858 op = ssa.OpSignExt8to64
2859 case 24:
2860 op = ssa.OpSignExt16to32
2861 case 28:
2862 op = ssa.OpSignExt16to64
2863 case 48:
2864 op = ssa.OpSignExt32to64
2865 default:
2866 s.Fatalf("bad integer sign extension %v -> %v", ft, tt)
2867 }
2868 } else {
2869
2870 switch 10*ft.Size() + tt.Size() {
2871 case 12:
2872 op = ssa.OpZeroExt8to16
2873 case 14:
2874 op = ssa.OpZeroExt8to32
2875 case 18:
2876 op = ssa.OpZeroExt8to64
2877 case 24:
2878 op = ssa.OpZeroExt16to32
2879 case 28:
2880 op = ssa.OpZeroExt16to64
2881 case 48:
2882 op = ssa.OpZeroExt32to64
2883 default:
2884 s.Fatalf("weird integer sign extension %v -> %v", ft, tt)
2885 }
2886 }
2887 return s.newValue1(op, tt, v)
2888 }
2889
2890 if ft.IsComplex() && tt.IsComplex() {
2891 var op ssa.Op
2892 if ft.Size() == tt.Size() {
2893 switch ft.Size() {
2894 case 8:
2895 op = ssa.OpRound32F
2896 case 16:
2897 op = ssa.OpRound64F
2898 default:
2899 s.Fatalf("weird complex conversion %v -> %v", ft, tt)
2900 }
2901 } else if ft.Size() == 8 && tt.Size() == 16 {
2902 op = ssa.OpCvt32Fto64F
2903 } else if ft.Size() == 16 && tt.Size() == 8 {
2904 op = ssa.OpCvt64Fto32F
2905 } else {
2906 s.Fatalf("weird complex conversion %v -> %v", ft, tt)
2907 }
2908 ftp := types.FloatForComplex(ft)
2909 ttp := types.FloatForComplex(tt)
2910 return s.newValue2(ssa.OpComplexMake, tt,
2911 s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, v)),
2912 s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, v)))
2913 }
2914
2915 if tt.IsComplex() {
2916
2917 et := types.FloatForComplex(tt)
2918 v = s.conv(n, v, ft, et)
2919 return s.newValue2(ssa.OpComplexMake, tt, v, s.zeroVal(et))
2920 }
2921
2922 if ft.IsFloat() || tt.IsFloat() {
2923 cft, ctt := s.concreteEtype(ft), s.concreteEtype(tt)
2924 conv, ok := fpConvOpToSSA[twoTypes{cft, ctt}]
2925
2926
2927 if ctt == types.TUINT32 && ft.IsFloat() && !base.ConvertHash.MatchPosWithInfo(n.Pos(), "U", nil) {
2928
2929 conv.op1 = ssa.OpCvt64Fto64
2930 if cft == types.TFLOAT32 {
2931 conv.op1 = ssa.OpCvt32Fto64
2932 }
2933 conv.op2 = ssa.OpTrunc64to32
2934
2935 }
2936 if s.config.RegSize == 4 && Arch.LinkArch.Family != sys.MIPS && !s.softFloat {
2937 if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
2938 conv = conv1
2939 }
2940 }
2941 if Arch.LinkArch.Family == sys.ARM64 || Arch.LinkArch.Family == sys.Wasm || Arch.LinkArch.Family == sys.S390X || s.softFloat {
2942 if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
2943 conv = conv1
2944 }
2945 }
2946
2947 if Arch.LinkArch.Family == sys.MIPS && !s.softFloat {
2948 if ft.Size() == 4 && ft.IsInteger() && !ft.IsSigned() {
2949
2950 if tt.Size() == 4 {
2951 return s.uint32Tofloat32(n, v, ft, tt)
2952 }
2953 if tt.Size() == 8 {
2954 return s.uint32Tofloat64(n, v, ft, tt)
2955 }
2956 } else if tt.Size() == 4 && tt.IsInteger() && !tt.IsSigned() {
2957
2958 if ft.Size() == 4 {
2959 return s.float32ToUint32(n, v, ft, tt)
2960 }
2961 if ft.Size() == 8 {
2962 return s.float64ToUint32(n, v, ft, tt)
2963 }
2964 }
2965 }
2966
2967 if !ok {
2968 s.Fatalf("weird float conversion %v -> %v", ft, tt)
2969 }
2970 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
2971
2972 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
2973
2974 if op1 == ssa.OpCopy {
2975 if op2 == ssa.OpCopy {
2976 return v
2977 }
2978 return s.newValueOrSfCall1(op2, tt, v)
2979 }
2980 if op2 == ssa.OpCopy {
2981 return s.newValueOrSfCall1(op1, tt, v)
2982 }
2983 return s.newValueOrSfCall1(op2, tt, s.newValueOrSfCall1(op1, types.Types[it], v))
2984 }
2985
2986 if ft.IsInteger() {
2987
2988 if tt.Size() == 4 {
2989 return s.uint64Tofloat32(n, v, ft, tt)
2990 }
2991 if tt.Size() == 8 {
2992 return s.uint64Tofloat64(n, v, ft, tt)
2993 }
2994 s.Fatalf("weird unsigned integer to float conversion %v -> %v", ft, tt)
2995 }
2996
2997 if ft.Size() == 4 {
2998 switch tt.Size() {
2999 case 8:
3000 return s.float32ToUint64(n, v, ft, tt)
3001 case 4, 2, 1:
3002
3003 return s.float32ToUint32(n, v, ft, tt)
3004 }
3005 }
3006 if ft.Size() == 8 {
3007 switch tt.Size() {
3008 case 8:
3009 return s.float64ToUint64(n, v, ft, tt)
3010 case 4, 2, 1:
3011
3012 return s.float64ToUint32(n, v, ft, tt)
3013 }
3014
3015 }
3016 s.Fatalf("weird float to unsigned integer conversion %v -> %v", ft, tt)
3017 return nil
3018 }
3019
3020 s.Fatalf("unhandled OCONV %s -> %s", ft.Kind(), tt.Kind())
3021 return nil
3022 }
3023
3024
3025 func (s *state) expr(n ir.Node) *ssa.Value {
3026 return s.exprCheckPtr(n, true)
3027 }
3028
3029 func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
3030 if ir.HasUniquePos(n) {
3031
3032
3033 s.pushLine(n.Pos())
3034 defer s.popLine()
3035 }
3036
3037 s.stmtList(n.Init())
3038 switch n.Op() {
3039 case ir.OBYTES2STRTMP:
3040 n := n.(*ir.ConvExpr)
3041 slice := s.expr(n.X)
3042 ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice)
3043 len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
3044 return s.newValue2(ssa.OpStringMake, n.Type(), ptr, len)
3045 case ir.OSTR2BYTESTMP:
3046 n := n.(*ir.ConvExpr)
3047 str := s.expr(n.X)
3048 ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, str)
3049 if !n.NonNil() {
3050
3051
3052
3053 cond := s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], ptr, s.constNil(ptr.Type))
3054 zerobase := s.newValue1A(ssa.OpAddr, ptr.Type, ir.Syms.Zerobase, s.sb)
3055 ptr = s.ternary(cond, ptr, zerobase)
3056 }
3057 len := s.newValue1(ssa.OpStringLen, types.Types[types.TINT], str)
3058 return s.newValue3(ssa.OpSliceMake, n.Type(), ptr, len, len)
3059 case ir.OCFUNC:
3060 n := n.(*ir.UnaryExpr)
3061 aux := n.X.(*ir.Name).Linksym()
3062
3063
3064 if aux.ABI() != obj.ABIInternal {
3065 s.Fatalf("expected ABIInternal: %v", aux.ABI())
3066 }
3067 return s.entryNewValue1A(ssa.OpAddr, n.Type(), aux, s.sb)
3068 case ir.ONAME:
3069 n := n.(*ir.Name)
3070 if n.Class == ir.PFUNC {
3071
3072 sym := staticdata.FuncLinksym(n)
3073 return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type()), sym, s.sb)
3074 }
3075 if s.canSSA(n) {
3076 return s.variable(n, n.Type())
3077 }
3078 return s.load(n.Type(), s.addr(n))
3079 case ir.OLINKSYMOFFSET:
3080 n := n.(*ir.LinksymOffsetExpr)
3081 return s.load(n.Type(), s.addr(n))
3082 case ir.ONIL:
3083 n := n.(*ir.NilExpr)
3084 t := n.Type()
3085 switch {
3086 case t.IsSlice():
3087 return s.constSlice(t)
3088 case t.IsInterface():
3089 return s.constInterface(t)
3090 default:
3091 return s.constNil(t)
3092 }
3093 case ir.OLITERAL:
3094 switch u := n.Val(); u.Kind() {
3095 case constant.Int:
3096 i := ir.IntVal(n.Type(), u)
3097 switch n.Type().Size() {
3098 case 1:
3099 return s.constInt8(n.Type(), int8(i))
3100 case 2:
3101 return s.constInt16(n.Type(), int16(i))
3102 case 4:
3103 return s.constInt32(n.Type(), int32(i))
3104 case 8:
3105 return s.constInt64(n.Type(), i)
3106 default:
3107 s.Fatalf("bad integer size %d", n.Type().Size())
3108 return nil
3109 }
3110 case constant.String:
3111 i := constant.StringVal(u)
3112 if i == "" {
3113 return s.constEmptyString(n.Type())
3114 }
3115 return s.entryNewValue0A(ssa.OpConstString, n.Type(), ssa.StringToAux(i))
3116 case constant.Bool:
3117 return s.constBool(constant.BoolVal(u))
3118 case constant.Float:
3119 f, _ := constant.Float64Val(u)
3120 switch n.Type().Size() {
3121 case 4:
3122 return s.constFloat32(n.Type(), f)
3123 case 8:
3124 return s.constFloat64(n.Type(), f)
3125 default:
3126 s.Fatalf("bad float size %d", n.Type().Size())
3127 return nil
3128 }
3129 case constant.Complex:
3130 re, _ := constant.Float64Val(constant.Real(u))
3131 im, _ := constant.Float64Val(constant.Imag(u))
3132 switch n.Type().Size() {
3133 case 8:
3134 pt := types.Types[types.TFLOAT32]
3135 return s.newValue2(ssa.OpComplexMake, n.Type(),
3136 s.constFloat32(pt, re),
3137 s.constFloat32(pt, im))
3138 case 16:
3139 pt := types.Types[types.TFLOAT64]
3140 return s.newValue2(ssa.OpComplexMake, n.Type(),
3141 s.constFloat64(pt, re),
3142 s.constFloat64(pt, im))
3143 default:
3144 s.Fatalf("bad complex size %d", n.Type().Size())
3145 return nil
3146 }
3147 default:
3148 s.Fatalf("unhandled OLITERAL %v", u.Kind())
3149 return nil
3150 }
3151 case ir.OCONVNOP:
3152 n := n.(*ir.ConvExpr)
3153 to := n.Type()
3154 from := n.X.Type()
3155
3156
3157
3158 x := s.expr(n.X)
3159 if to == from {
3160 return x
3161 }
3162
3163
3164
3165
3166
3167 if to.IsPtrShaped() != from.IsPtrShaped() {
3168 return s.newValue2(ssa.OpConvert, to, x, s.mem())
3169 }
3170
3171 v := s.newValue1(ssa.OpCopy, to, x)
3172
3173
3174 if to.Kind() == types.TFUNC && from.IsPtrShaped() {
3175 return v
3176 }
3177
3178
3179 if from.Kind() == to.Kind() {
3180 return v
3181 }
3182
3183
3184 if to.IsUnsafePtr() && from.IsPtrShaped() || from.IsUnsafePtr() && to.IsPtrShaped() {
3185 if s.checkPtrEnabled && checkPtrOK && to.IsPtr() && from.IsUnsafePtr() {
3186 s.checkPtrAlignment(n, v, nil)
3187 }
3188 return v
3189 }
3190
3191
3192 mt := types.NewPtr(reflectdata.MapType())
3193 if to.Kind() == types.TMAP && from == mt {
3194 return v
3195 }
3196
3197 types.CalcSize(from)
3198 types.CalcSize(to)
3199 if from.Size() != to.Size() {
3200 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Size(), to, to.Size())
3201 return nil
3202 }
3203 if etypesign(from.Kind()) != etypesign(to.Kind()) {
3204 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, from.Kind(), to, to.Kind())
3205 return nil
3206 }
3207
3208 if base.Flag.Cfg.Instrumenting {
3209
3210
3211
3212 return v
3213 }
3214
3215 if etypesign(from.Kind()) == 0 {
3216 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
3217 return nil
3218 }
3219
3220
3221 return v
3222
3223 case ir.OCONV:
3224 n := n.(*ir.ConvExpr)
3225 x := s.expr(n.X)
3226 return s.conv(n, x, n.X.Type(), n.Type())
3227
3228 case ir.ODOTTYPE:
3229 n := n.(*ir.TypeAssertExpr)
3230 res, _ := s.dottype(n, false)
3231 return res
3232
3233 case ir.ODYNAMICDOTTYPE:
3234 n := n.(*ir.DynamicTypeAssertExpr)
3235 res, _ := s.dynamicDottype(n, false)
3236 return res
3237
3238
3239 case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
3240 n := n.(*ir.BinaryExpr)
3241 a := s.expr(n.X)
3242 b := s.expr(n.Y)
3243 if n.X.Type().IsComplex() {
3244 pt := types.FloatForComplex(n.X.Type())
3245 op := s.ssaOp(ir.OEQ, pt)
3246 r := s.newValueOrSfCall2(op, types.Types[types.TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
3247 i := s.newValueOrSfCall2(op, types.Types[types.TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
3248 c := s.newValue2(ssa.OpAndB, types.Types[types.TBOOL], r, i)
3249 switch n.Op() {
3250 case ir.OEQ:
3251 return c
3252 case ir.ONE:
3253 return s.newValue1(ssa.OpNot, types.Types[types.TBOOL], c)
3254 default:
3255 s.Fatalf("ordered complex compare %v", n.Op())
3256 }
3257 }
3258
3259
3260 op := n.Op()
3261 switch op {
3262 case ir.OGE:
3263 op, a, b = ir.OLE, b, a
3264 case ir.OGT:
3265 op, a, b = ir.OLT, b, a
3266 }
3267 if n.X.Type().IsFloat() {
3268
3269 return s.newValueOrSfCall2(s.ssaOp(op, n.X.Type()), types.Types[types.TBOOL], a, b)
3270 }
3271
3272 return s.newValue2(s.ssaOp(op, n.X.Type()), types.Types[types.TBOOL], a, b)
3273 case ir.OMUL:
3274 n := n.(*ir.BinaryExpr)
3275 a := s.expr(n.X)
3276 b := s.expr(n.Y)
3277 if n.Type().IsComplex() {
3278 mulop := ssa.OpMul64F
3279 addop := ssa.OpAdd64F
3280 subop := ssa.OpSub64F
3281 pt := types.FloatForComplex(n.Type())
3282 wt := types.Types[types.TFLOAT64]
3283
3284 areal := s.newValue1(ssa.OpComplexReal, pt, a)
3285 breal := s.newValue1(ssa.OpComplexReal, pt, b)
3286 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
3287 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
3288
3289 if pt != wt {
3290 areal = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, areal)
3291 breal = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, breal)
3292 aimag = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, aimag)
3293 bimag = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, bimag)
3294 }
3295
3296 xreal := s.newValueOrSfCall2(subop, wt, s.newValueOrSfCall2(mulop, wt, areal, breal), s.newValueOrSfCall2(mulop, wt, aimag, bimag))
3297 ximag := s.newValueOrSfCall2(addop, wt, s.newValueOrSfCall2(mulop, wt, areal, bimag), s.newValueOrSfCall2(mulop, wt, aimag, breal))
3298
3299 if pt != wt {
3300 xreal = s.newValueOrSfCall1(ssa.OpCvt64Fto32F, pt, xreal)
3301 ximag = s.newValueOrSfCall1(ssa.OpCvt64Fto32F, pt, ximag)
3302 }
3303
3304 return s.newValue2(ssa.OpComplexMake, n.Type(), xreal, ximag)
3305 }
3306
3307 if n.Type().IsFloat() {
3308 return s.newValueOrSfCall2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3309 }
3310
3311 return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3312
3313 case ir.ODIV:
3314 n := n.(*ir.BinaryExpr)
3315 a := s.expr(n.X)
3316 b := s.expr(n.Y)
3317 if n.Type().IsComplex() {
3318
3319
3320
3321 mulop := ssa.OpMul64F
3322 addop := ssa.OpAdd64F
3323 subop := ssa.OpSub64F
3324 divop := ssa.OpDiv64F
3325 pt := types.FloatForComplex(n.Type())
3326 wt := types.Types[types.TFLOAT64]
3327
3328 areal := s.newValue1(ssa.OpComplexReal, pt, a)
3329 breal := s.newValue1(ssa.OpComplexReal, pt, b)
3330 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
3331 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
3332
3333 if pt != wt {
3334 areal = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, areal)
3335 breal = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, breal)
3336 aimag = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, aimag)
3337 bimag = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, bimag)
3338 }
3339
3340 denom := s.newValueOrSfCall2(addop, wt, s.newValueOrSfCall2(mulop, wt, breal, breal), s.newValueOrSfCall2(mulop, wt, bimag, bimag))
3341 xreal := s.newValueOrSfCall2(addop, wt, s.newValueOrSfCall2(mulop, wt, areal, breal), s.newValueOrSfCall2(mulop, wt, aimag, bimag))
3342 ximag := s.newValueOrSfCall2(subop, wt, s.newValueOrSfCall2(mulop, wt, aimag, breal), s.newValueOrSfCall2(mulop, wt, areal, bimag))
3343
3344
3345
3346
3347
3348 xreal = s.newValueOrSfCall2(divop, wt, xreal, denom)
3349 ximag = s.newValueOrSfCall2(divop, wt, ximag, denom)
3350
3351 if pt != wt {
3352 xreal = s.newValueOrSfCall1(ssa.OpCvt64Fto32F, pt, xreal)
3353 ximag = s.newValueOrSfCall1(ssa.OpCvt64Fto32F, pt, ximag)
3354 }
3355 return s.newValue2(ssa.OpComplexMake, n.Type(), xreal, ximag)
3356 }
3357 if n.Type().IsFloat() {
3358 return s.newValueOrSfCall2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3359 }
3360 return s.intDivide(n, a, b)
3361 case ir.OMOD:
3362 n := n.(*ir.BinaryExpr)
3363 a := s.expr(n.X)
3364 b := s.expr(n.Y)
3365 return s.intDivide(n, a, b)
3366 case ir.OADD, ir.OSUB:
3367 n := n.(*ir.BinaryExpr)
3368 a := s.expr(n.X)
3369 b := s.expr(n.Y)
3370 if n.Type().IsComplex() {
3371 pt := types.FloatForComplex(n.Type())
3372 op := s.ssaOp(n.Op(), pt)
3373 return s.newValue2(ssa.OpComplexMake, n.Type(),
3374 s.newValueOrSfCall2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
3375 s.newValueOrSfCall2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
3376 }
3377 if n.Type().IsFloat() {
3378 return s.newValueOrSfCall2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3379 }
3380 return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3381 case ir.OAND, ir.OOR, ir.OXOR:
3382 n := n.(*ir.BinaryExpr)
3383 a := s.expr(n.X)
3384 b := s.expr(n.Y)
3385 return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3386 case ir.OANDNOT:
3387 n := n.(*ir.BinaryExpr)
3388 a := s.expr(n.X)
3389 b := s.expr(n.Y)
3390 b = s.newValue1(s.ssaOp(ir.OBITNOT, b.Type), b.Type, b)
3391 return s.newValue2(s.ssaOp(ir.OAND, n.Type()), a.Type, a, b)
3392 case ir.OLSH, ir.ORSH:
3393 n := n.(*ir.BinaryExpr)
3394 a := s.expr(n.X)
3395 b := s.expr(n.Y)
3396 bt := b.Type
3397 if bt.IsSigned() {
3398 cmp := s.newValue2(s.ssaOp(ir.OLE, bt), types.Types[types.TBOOL], s.zeroVal(bt), b)
3399 s.check(cmp, ir.Syms.Panicshift)
3400 bt = bt.ToUnsigned()
3401 }
3402 return s.newValue2(s.ssaShiftOp(n.Op(), n.Type(), bt), a.Type, a, b)
3403 case ir.OANDAND, ir.OOROR:
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417 n := n.(*ir.LogicalExpr)
3418 el := s.expr(n.X)
3419 s.vars[n] = el
3420
3421 b := s.endBlock()
3422 b.Kind = ssa.BlockIf
3423 b.SetControl(el)
3424
3425
3426
3427
3428
3429 bRight := s.f.NewBlock(ssa.BlockPlain)
3430 bResult := s.f.NewBlock(ssa.BlockPlain)
3431 if n.Op() == ir.OANDAND {
3432 b.AddEdgeTo(bRight)
3433 b.AddEdgeTo(bResult)
3434 } else if n.Op() == ir.OOROR {
3435 b.AddEdgeTo(bResult)
3436 b.AddEdgeTo(bRight)
3437 }
3438
3439 s.startBlock(bRight)
3440 er := s.expr(n.Y)
3441 s.vars[n] = er
3442
3443 b = s.endBlock()
3444 b.AddEdgeTo(bResult)
3445
3446 s.startBlock(bResult)
3447 return s.variable(n, types.Types[types.TBOOL])
3448 case ir.OCOMPLEX:
3449 n := n.(*ir.BinaryExpr)
3450 r := s.expr(n.X)
3451 i := s.expr(n.Y)
3452 return s.newValue2(ssa.OpComplexMake, n.Type(), r, i)
3453
3454
3455 case ir.ONEG:
3456 n := n.(*ir.UnaryExpr)
3457 a := s.expr(n.X)
3458 if n.Type().IsComplex() {
3459 tp := types.FloatForComplex(n.Type())
3460 negop := s.ssaOp(n.Op(), tp)
3461 return s.newValue2(ssa.OpComplexMake, n.Type(),
3462 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
3463 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
3464 }
3465 return s.newValue1(s.ssaOp(n.Op(), n.Type()), a.Type, a)
3466 case ir.ONOT, ir.OBITNOT:
3467 n := n.(*ir.UnaryExpr)
3468 a := s.expr(n.X)
3469 return s.newValue1(s.ssaOp(n.Op(), n.Type()), a.Type, a)
3470 case ir.OIMAG, ir.OREAL:
3471 n := n.(*ir.UnaryExpr)
3472 a := s.expr(n.X)
3473 return s.newValue1(s.ssaOp(n.Op(), n.X.Type()), n.Type(), a)
3474 case ir.OPLUS:
3475 n := n.(*ir.UnaryExpr)
3476 return s.expr(n.X)
3477
3478 case ir.OADDR:
3479 n := n.(*ir.AddrExpr)
3480 return s.addr(n.X)
3481
3482 case ir.ORESULT:
3483 n := n.(*ir.ResultExpr)
3484 if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
3485 panic("Expected to see a previous call")
3486 }
3487 which := n.Index
3488 if which == -1 {
3489 panic(fmt.Errorf("ORESULT %v does not match call %s", n, s.prevCall))
3490 }
3491 return s.resultOfCall(s.prevCall, which, n.Type())
3492
3493 case ir.ODEREF:
3494 n := n.(*ir.StarExpr)
3495 p := s.exprPtr(n.X, n.Bounded(), n.Pos())
3496 return s.load(n.Type(), p)
3497
3498 case ir.ODOT:
3499 n := n.(*ir.SelectorExpr)
3500 if n.X.Op() == ir.OSTRUCTLIT {
3501
3502
3503
3504 if !ir.IsZero(n.X) {
3505 s.Fatalf("literal with nonzero value in SSA: %v", n.X)
3506 }
3507 return s.zeroVal(n.Type())
3508 }
3509
3510
3511
3512
3513 if ir.IsAddressable(n) && !s.canSSA(n) {
3514 p := s.addr(n)
3515 return s.load(n.Type(), p)
3516 }
3517 v := s.expr(n.X)
3518 return s.newValue1I(ssa.OpStructSelect, n.Type(), int64(fieldIdx(n)), v)
3519
3520 case ir.ODOTPTR:
3521 n := n.(*ir.SelectorExpr)
3522 p := s.exprPtr(n.X, n.Bounded(), n.Pos())
3523 p = s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type()), n.Offset(), p)
3524 return s.load(n.Type(), p)
3525
3526 case ir.OINDEX:
3527 n := n.(*ir.IndexExpr)
3528 switch {
3529 case n.X.Type().IsString():
3530 if n.Bounded() && ir.IsConst(n.X, constant.String) && ir.IsConst(n.Index, constant.Int) {
3531
3532
3533
3534 return s.newValue0I(ssa.OpConst8, types.Types[types.TUINT8], int64(int8(ir.StringVal(n.X)[ir.Int64Val(n.Index)])))
3535 }
3536 a := s.expr(n.X)
3537 i := s.expr(n.Index)
3538 len := s.newValue1(ssa.OpStringLen, types.Types[types.TINT], a)
3539 i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
3540 ptrtyp := s.f.Config.Types.BytePtr
3541 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
3542 if ir.IsConst(n.Index, constant.Int) {
3543 ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, ir.Int64Val(n.Index), ptr)
3544 } else {
3545 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
3546 }
3547 return s.load(types.Types[types.TUINT8], ptr)
3548 case n.X.Type().IsSlice():
3549 p := s.addr(n)
3550 return s.load(n.X.Type().Elem(), p)
3551 case n.X.Type().IsArray():
3552 if ssa.CanSSA(n.X.Type()) {
3553
3554 bound := n.X.Type().NumElem()
3555 a := s.expr(n.X)
3556 i := s.expr(n.Index)
3557 if bound == 0 {
3558
3559
3560 z := s.constInt(types.Types[types.TINT], 0)
3561 s.boundsCheck(z, z, ssa.BoundsIndex, false)
3562
3563
3564 return s.load(n.Type(), s.constNil(n.Type().PtrTo()))
3565 }
3566 len := s.constInt(types.Types[types.TINT], bound)
3567 s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
3568 return s.newValue1I(ssa.OpArraySelect, n.Type(), 0, a)
3569 }
3570 p := s.addr(n)
3571 return s.load(n.X.Type().Elem(), p)
3572 default:
3573 s.Fatalf("bad type for index %v", n.X.Type())
3574 return nil
3575 }
3576
3577 case ir.OLEN, ir.OCAP:
3578 n := n.(*ir.UnaryExpr)
3579
3580
3581 a := s.expr(n.X)
3582 t := n.X.Type()
3583 switch {
3584 case t.IsSlice():
3585 op := ssa.OpSliceLen
3586 if n.Op() == ir.OCAP {
3587 op = ssa.OpSliceCap
3588 }
3589 return s.newValue1(op, types.Types[types.TINT], a)
3590 case t.IsString():
3591 return s.newValue1(ssa.OpStringLen, types.Types[types.TINT], a)
3592 case t.IsMap(), t.IsChan():
3593 return s.referenceTypeBuiltin(n, a)
3594 case t.IsArray():
3595 return s.constInt(types.Types[types.TINT], t.NumElem())
3596 case t.IsPtr() && t.Elem().IsArray():
3597 return s.constInt(types.Types[types.TINT], t.Elem().NumElem())
3598 default:
3599 s.Fatalf("bad type in len/cap: %v", t)
3600 return nil
3601 }
3602
3603 case ir.OSPTR:
3604 n := n.(*ir.UnaryExpr)
3605 a := s.expr(n.X)
3606 if n.X.Type().IsSlice() {
3607 if n.Bounded() {
3608 return s.newValue1(ssa.OpSlicePtr, n.Type(), a)
3609 }
3610 return s.newValue1(ssa.OpSlicePtrUnchecked, n.Type(), a)
3611 } else {
3612 return s.newValue1(ssa.OpStringPtr, n.Type(), a)
3613 }
3614
3615 case ir.OITAB:
3616 n := n.(*ir.UnaryExpr)
3617 a := s.expr(n.X)
3618 return s.newValue1(ssa.OpITab, n.Type(), a)
3619
3620 case ir.OIDATA:
3621 n := n.(*ir.UnaryExpr)
3622 a := s.expr(n.X)
3623 return s.newValue1(ssa.OpIData, n.Type(), a)
3624
3625 case ir.OMAKEFACE:
3626 n := n.(*ir.BinaryExpr)
3627 tab := s.expr(n.X)
3628 data := s.expr(n.Y)
3629 return s.newValue2(ssa.OpIMake, n.Type(), tab, data)
3630
3631 case ir.OSLICEHEADER:
3632 n := n.(*ir.SliceHeaderExpr)
3633 p := s.expr(n.Ptr)
3634 l := s.expr(n.Len)
3635 c := s.expr(n.Cap)
3636 return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
3637
3638 case ir.OSTRINGHEADER:
3639 n := n.(*ir.StringHeaderExpr)
3640 p := s.expr(n.Ptr)
3641 l := s.expr(n.Len)
3642 return s.newValue2(ssa.OpStringMake, n.Type(), p, l)
3643
3644 case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
3645 n := n.(*ir.SliceExpr)
3646 check := s.checkPtrEnabled && n.Op() == ir.OSLICE3ARR && n.X.Op() == ir.OCONVNOP && n.X.(*ir.ConvExpr).X.Type().IsUnsafePtr()
3647 v := s.exprCheckPtr(n.X, !check)
3648 var i, j, k *ssa.Value
3649 if n.Low != nil {
3650 i = s.expr(n.Low)
3651 }
3652 if n.High != nil {
3653 j = s.expr(n.High)
3654 }
3655 if n.Max != nil {
3656 k = s.expr(n.Max)
3657 }
3658 p, l, c := s.slice(v, i, j, k, n.Bounded())
3659 if check {
3660
3661 s.checkPtrAlignment(n.X.(*ir.ConvExpr), v, s.conv(n.Max, k, k.Type, types.Types[types.TUINTPTR]))
3662 }
3663 return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
3664
3665 case ir.OSLICESTR:
3666 n := n.(*ir.SliceExpr)
3667 v := s.expr(n.X)
3668 var i, j *ssa.Value
3669 if n.Low != nil {
3670 i = s.expr(n.Low)
3671 }
3672 if n.High != nil {
3673 j = s.expr(n.High)
3674 }
3675 p, l, _ := s.slice(v, i, j, nil, n.Bounded())
3676 return s.newValue2(ssa.OpStringMake, n.Type(), p, l)
3677
3678 case ir.OSLICE2ARRPTR:
3679
3680
3681
3682
3683 n := n.(*ir.ConvExpr)
3684 v := s.expr(n.X)
3685 nelem := n.Type().Elem().NumElem()
3686 arrlen := s.constInt(types.Types[types.TINT], nelem)
3687 cap := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], v)
3688 s.boundsCheck(arrlen, cap, ssa.BoundsConvert, false)
3689 op := ssa.OpSlicePtr
3690 if nelem == 0 {
3691 op = ssa.OpSlicePtrUnchecked
3692 }
3693 return s.newValue1(op, n.Type(), v)
3694
3695 case ir.OCALLFUNC:
3696 n := n.(*ir.CallExpr)
3697 if ir.IsIntrinsicCall(n) {
3698 return s.intrinsicCall(n)
3699 }
3700 fallthrough
3701
3702 case ir.OCALLINTER:
3703 n := n.(*ir.CallExpr)
3704 return s.callResult(n, callNormal)
3705
3706 case ir.OGETG:
3707 n := n.(*ir.CallExpr)
3708 return s.newValue1(ssa.OpGetG, n.Type(), s.mem())
3709
3710 case ir.OGETCALLERSP:
3711 n := n.(*ir.CallExpr)
3712 return s.newValue1(ssa.OpGetCallerSP, n.Type(), s.mem())
3713
3714 case ir.OAPPEND:
3715 return s.append(n.(*ir.CallExpr), false)
3716
3717 case ir.OMOVE2HEAP:
3718 return s.move2heap(n.(*ir.MoveToHeapExpr))
3719
3720 case ir.OMIN, ir.OMAX:
3721 return s.minMax(n.(*ir.CallExpr))
3722
3723 case ir.OSTRUCTLIT, ir.OARRAYLIT:
3724
3725
3726
3727 n := n.(*ir.CompLitExpr)
3728 if !ir.IsZero(n) {
3729 s.Fatalf("literal with nonzero value in SSA: %v", n)
3730 }
3731 return s.zeroVal(n.Type())
3732
3733 case ir.ONEW:
3734 n := n.(*ir.UnaryExpr)
3735 if x, ok := n.X.(*ir.DynamicType); ok && x.Op() == ir.ODYNAMICTYPE {
3736 return s.newObjectNonSpecialized(n.Type().Elem(), s.expr(x.RType))
3737 }
3738 return s.newObject(n.Type().Elem())
3739
3740 case ir.OUNSAFEADD:
3741 n := n.(*ir.BinaryExpr)
3742 ptr := s.expr(n.X)
3743 len := s.expr(n.Y)
3744
3745
3746
3747 len = s.conv(n, len, len.Type, types.Types[types.TUINTPTR])
3748
3749 return s.newValue2(ssa.OpAddPtr, n.Type(), ptr, len)
3750
3751 default:
3752 s.Fatalf("unhandled expr %v", n.Op())
3753 return nil
3754 }
3755 }
3756
3757 func (s *state) resultOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.Value {
3758 aux := c.Aux.(*ssa.AuxCall)
3759 pa := aux.ParamAssignmentForResult(which)
3760
3761
3762 if len(pa.Registers) == 0 && !ssa.CanSSA(t) {
3763 addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), which, c)
3764 return s.rawLoad(t, addr)
3765 }
3766 return s.newValue1I(ssa.OpSelectN, t, which, c)
3767 }
3768
3769 func (s *state) resultAddrOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.Value {
3770 aux := c.Aux.(*ssa.AuxCall)
3771 pa := aux.ParamAssignmentForResult(which)
3772 if len(pa.Registers) == 0 {
3773 return s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), which, c)
3774 }
3775 _, addr := s.temp(c.Pos, t)
3776 rval := s.newValue1I(ssa.OpSelectN, t, which, c)
3777 s.vars[memVar] = s.newValue3Apos(ssa.OpStore, types.TypeMem, t, addr, rval, s.mem(), false)
3778 return addr
3779 }
3780
3781
3782 func (s *state) getBackingStoreInfoForAppend(n *ir.CallExpr) *backingStoreInfo {
3783 if n.Esc() != ir.EscNone {
3784 return nil
3785 }
3786 return s.getBackingStoreInfo(n.Args[0])
3787 }
3788 func (s *state) getBackingStoreInfo(n ir.Node) *backingStoreInfo {
3789 t := n.Type()
3790 et := t.Elem()
3791 maxStackSize := int64(base.Debug.VariableMakeThreshold)
3792 if et.Size() == 0 || et.Size() > maxStackSize {
3793 return nil
3794 }
3795 if base.Flag.N != 0 {
3796 return nil
3797 }
3798 if !base.VariableMakeHash.MatchPos(n.Pos(), nil) {
3799 return nil
3800 }
3801 i := s.backingStores[n]
3802 if i != nil {
3803 return i
3804 }
3805
3806
3807 K := maxStackSize / et.Size()
3808 KT := types.NewArray(et, K)
3809 KT.SetNoalg(true)
3810 types.CalcArraySize(KT)
3811
3812 align := types.NewArray(types.Types[types.TUINTPTR], 0)
3813 types.CalcArraySize(align)
3814 storeTyp := types.NewStruct([]*types.Field{
3815 {Sym: types.BlankSym, Type: align},
3816 {Sym: types.BlankSym, Type: KT},
3817 })
3818 storeTyp.SetNoalg(true)
3819 types.CalcStructSize(storeTyp)
3820
3821
3822 backingStore := typecheck.TempAt(n.Pos(), s.curfn, storeTyp)
3823 backingStore.SetAddrtaken(true)
3824
3825
3826 used := typecheck.TempAt(n.Pos(), s.curfn, types.Types[types.TBOOL])
3827 if s.curBlock == s.f.Entry {
3828 s.vars[used] = s.constBool(false)
3829 } else {
3830
3831 s.defvars[s.f.Entry.ID][used] = s.constBool(false)
3832 }
3833
3834
3835 if s.backingStores == nil {
3836 s.backingStores = map[ir.Node]*backingStoreInfo{}
3837 }
3838 i = &backingStoreInfo{K: K, store: backingStore, used: used, usedStatic: false}
3839 s.backingStores[n] = i
3840 return i
3841 }
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851 func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884 et := n.Type().Elem()
3885 pt := types.NewPtr(et)
3886
3887
3888 sn := n.Args[0]
3889 var slice, addr *ssa.Value
3890 if inplace {
3891 addr = s.addr(sn)
3892 slice = s.load(n.Type(), addr)
3893 } else {
3894 slice = s.expr(sn)
3895 }
3896
3897
3898 grow := s.f.NewBlock(ssa.BlockPlain)
3899 assign := s.f.NewBlock(ssa.BlockPlain)
3900
3901
3902 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
3903 l := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
3904 c := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], slice)
3905
3906
3907 nargs := s.constInt(types.Types[types.TINT], int64(len(n.Args)-1))
3908 oldLen := l
3909 l = s.newValue2(s.ssaOp(ir.OADD, types.Types[types.TINT]), types.Types[types.TINT], l, nargs)
3910
3911
3912 cmp := s.newValue2(s.ssaOp(ir.OLT, types.Types[types.TUINT]), types.Types[types.TBOOL], c, l)
3913
3914
3915 s.vars[ptrVar] = p
3916 s.vars[lenVar] = l
3917 if !inplace {
3918 s.vars[capVar] = c
3919 }
3920
3921 b := s.endBlock()
3922 b.Kind = ssa.BlockIf
3923 b.Likely = ssa.BranchUnlikely
3924 b.SetControl(cmp)
3925 b.AddEdgeTo(grow)
3926 b.AddEdgeTo(assign)
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950 var info *backingStoreInfo
3951 if !inplace {
3952 info = s.getBackingStoreInfoForAppend(n)
3953 }
3954
3955 if !inplace && info != nil && !n.UseBuf && !info.usedStatic {
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979 info.usedStatic = true
3980
3981
3982 usedTestBlock := s.f.NewBlock(ssa.BlockPlain)
3983 oldLenTestBlock := s.f.NewBlock(ssa.BlockPlain)
3984 bodyBlock := s.f.NewBlock(ssa.BlockPlain)
3985 growSlice := s.f.NewBlock(ssa.BlockPlain)
3986 tInt := types.Types[types.TINT]
3987 tBool := types.Types[types.TBOOL]
3988
3989
3990 s.startBlock(grow)
3991 kTest := s.newValue2(s.ssaOp(ir.OLE, tInt), tBool, l, s.constInt(tInt, info.K))
3992 b := s.endBlock()
3993 b.Kind = ssa.BlockIf
3994 b.SetControl(kTest)
3995 b.AddEdgeTo(usedTestBlock)
3996 b.AddEdgeTo(growSlice)
3997 b.Likely = ssa.BranchLikely
3998
3999
4000 s.startBlock(usedTestBlock)
4001 usedTest := s.newValue1(ssa.OpNot, tBool, s.expr(info.used))
4002 b = s.endBlock()
4003 b.Kind = ssa.BlockIf
4004 b.SetControl(usedTest)
4005 b.AddEdgeTo(oldLenTestBlock)
4006 b.AddEdgeTo(growSlice)
4007 b.Likely = ssa.BranchLikely
4008
4009
4010 s.startBlock(oldLenTestBlock)
4011 oldLenTest := s.newValue2(s.ssaOp(ir.OEQ, tInt), tBool, oldLen, s.constInt(tInt, 0))
4012 b = s.endBlock()
4013 b.Kind = ssa.BlockIf
4014 b.SetControl(oldLenTest)
4015 b.AddEdgeTo(bodyBlock)
4016 b.AddEdgeTo(growSlice)
4017 b.Likely = ssa.BranchLikely
4018
4019
4020 s.startBlock(bodyBlock)
4021 if et.HasPointers() {
4022 s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, info.store, s.mem())
4023 }
4024 addr := s.addr(info.store)
4025 s.zero(info.store.Type(), addr)
4026
4027
4028 s.vars[ptrVar] = addr
4029 s.vars[lenVar] = l
4030 s.vars[capVar] = s.constInt(tInt, info.K)
4031
4032
4033 s.assign(info.used, s.constBool(true), false, 0)
4034 b = s.endBlock()
4035 b.AddEdgeTo(assign)
4036
4037
4038 grow = growSlice
4039 }
4040
4041
4042 s.startBlock(grow)
4043 taddr := s.expr(n.Fun)
4044 var r []*ssa.Value
4045 if info != nil && n.UseBuf {
4046
4047 if et.HasPointers() && !info.usedStatic {
4048
4049
4050
4051 mem := s.defvars[s.f.Entry.ID][memVar]
4052 mem = s.f.Entry.NewValue1A(n.Pos(), ssa.OpVarDef, types.TypeMem, info.store, mem)
4053 addr := s.f.Entry.NewValue2A(n.Pos(), ssa.OpLocalAddr, types.NewPtr(info.store.Type()), info.store, s.sp, mem)
4054 mem = s.f.Entry.NewValue2I(n.Pos(), ssa.OpZero, types.TypeMem, info.store.Type().Size(), addr, mem)
4055 mem.Aux = info.store.Type()
4056 s.defvars[s.f.Entry.ID][memVar] = mem
4057 info.usedStatic = true
4058 }
4059 fn := ir.Syms.GrowsliceBuf
4060 if goexperiment.RuntimeFreegc && n.AppendNoAlias && !et.HasPointers() {
4061
4062
4063
4064
4065 fn = ir.Syms.GrowsliceBufNoAlias
4066 }
4067 r = s.rtcall(fn, true, []*types.Type{n.Type()}, p, l, c, nargs, taddr, s.addr(info.store), s.constInt(types.Types[types.TINT], info.K))
4068 } else {
4069 fn := ir.Syms.Growslice
4070 if goexperiment.RuntimeFreegc && n.AppendNoAlias && !et.HasPointers() {
4071
4072
4073
4074
4075 fn = ir.Syms.GrowsliceNoAlias
4076 }
4077 r = s.rtcall(fn, true, []*types.Type{n.Type()}, p, l, c, nargs, taddr)
4078 }
4079
4080
4081 p = s.newValue1(ssa.OpSlicePtr, pt, r[0])
4082 l = s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], r[0])
4083 c = s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], r[0])
4084
4085 s.vars[ptrVar] = p
4086 s.vars[lenVar] = l
4087 s.vars[capVar] = c
4088 if inplace {
4089 if sn.Op() == ir.ONAME {
4090 sn := sn.(*ir.Name)
4091 if sn.Class != ir.PEXTERN {
4092
4093 s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem())
4094 }
4095 }
4096 capaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, types.SliceCapOffset, addr)
4097 s.store(types.Types[types.TINT], capaddr, c)
4098 s.store(pt, addr, p)
4099 }
4100
4101 b = s.endBlock()
4102 b.AddEdgeTo(assign)
4103
4104
4105 s.startBlock(assign)
4106 p = s.variable(ptrVar, pt)
4107 l = s.variable(lenVar, types.Types[types.TINT])
4108 if !inplace {
4109 c = s.variable(capVar, types.Types[types.TINT])
4110 }
4111
4112 if inplace {
4113
4114
4115 lenaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, types.SliceLenOffset, addr)
4116 s.store(types.Types[types.TINT], lenaddr, l)
4117 }
4118
4119
4120 type argRec struct {
4121
4122
4123 v *ssa.Value
4124 store bool
4125 }
4126 args := make([]argRec, 0, len(n.Args[1:]))
4127 for _, n := range n.Args[1:] {
4128 if ssa.CanSSA(n.Type()) {
4129 args = append(args, argRec{v: s.expr(n), store: true})
4130 } else {
4131 v := s.addr(n)
4132 args = append(args, argRec{v: v})
4133 }
4134 }
4135
4136
4137 oldLen = s.newValue2(s.ssaOp(ir.OSUB, types.Types[types.TINT]), types.Types[types.TINT], l, nargs)
4138 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, oldLen)
4139 for i, arg := range args {
4140 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(types.Types[types.TINT], int64(i)))
4141 if arg.store {
4142 s.storeType(et, addr, arg.v, 0, true)
4143 } else {
4144 s.move(et, addr, arg.v)
4145 }
4146 }
4147
4148
4149
4150
4151
4152 delete(s.vars, ptrVar)
4153 delete(s.vars, lenVar)
4154 if !inplace {
4155 delete(s.vars, capVar)
4156 }
4157
4158
4159 if inplace {
4160 return nil
4161 }
4162 return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
4163 }
4164
4165 func (s *state) move2heap(n *ir.MoveToHeapExpr) *ssa.Value {
4166
4167
4168
4169
4170
4171
4172
4173
4174 slice := s.expr(n.Slice)
4175 et := slice.Type.Elem()
4176 pt := types.NewPtr(et)
4177
4178 info := s.getBackingStoreInfo(n)
4179 if info == nil {
4180
4181
4182 return slice
4183 }
4184
4185
4186 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
4187 l := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
4188 c := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], slice)
4189
4190 moveBlock := s.f.NewBlock(ssa.BlockPlain)
4191 mergeBlock := s.f.NewBlock(ssa.BlockPlain)
4192
4193 s.vars[ptrVar] = p
4194 s.vars[lenVar] = l
4195 s.vars[capVar] = c
4196
4197
4198
4199 sub := ssa.OpSub64
4200 less := ssa.OpLess64U
4201 if s.config.PtrSize == 4 {
4202 sub = ssa.OpSub32
4203 less = ssa.OpLess32U
4204 }
4205 callerSP := s.newValue1(ssa.OpGetCallerSP, types.Types[types.TUINTPTR], s.mem())
4206 frameSize := s.newValue2(sub, types.Types[types.TUINTPTR], callerSP, s.sp)
4207 pInt := s.newValue2(ssa.OpConvert, types.Types[types.TUINTPTR], p, s.mem())
4208 off := s.newValue2(sub, types.Types[types.TUINTPTR], pInt, s.sp)
4209 cond := s.newValue2(less, types.Types[types.TBOOL], off, frameSize)
4210
4211 b := s.endBlock()
4212 b.Kind = ssa.BlockIf
4213 b.Likely = ssa.BranchUnlikely
4214 b.SetControl(cond)
4215 b.AddEdgeTo(moveBlock)
4216 b.AddEdgeTo(mergeBlock)
4217
4218
4219 s.startBlock(moveBlock)
4220 var newSlice *ssa.Value
4221 if et.HasPointers() {
4222 typ := s.expr(n.RType)
4223 if n.PreserveCapacity {
4224 newSlice = s.rtcall(ir.Syms.MoveSlice, true, []*types.Type{slice.Type}, typ, p, l, c)[0]
4225 } else {
4226 newSlice = s.rtcall(ir.Syms.MoveSliceNoCap, true, []*types.Type{slice.Type}, typ, p, l)[0]
4227 }
4228 } else {
4229 elemSize := s.constInt(types.Types[types.TUINTPTR], et.Size())
4230 if n.PreserveCapacity {
4231 newSlice = s.rtcall(ir.Syms.MoveSliceNoScan, true, []*types.Type{slice.Type}, elemSize, p, l, c)[0]
4232 } else {
4233 newSlice = s.rtcall(ir.Syms.MoveSliceNoCapNoScan, true, []*types.Type{slice.Type}, elemSize, p, l)[0]
4234 }
4235 }
4236
4237 s.vars[ptrVar] = s.newValue1(ssa.OpSlicePtr, pt, newSlice)
4238 s.vars[lenVar] = s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], newSlice)
4239 s.vars[capVar] = s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], newSlice)
4240 b = s.endBlock()
4241 b.AddEdgeTo(mergeBlock)
4242
4243
4244 s.startBlock(mergeBlock)
4245 p = s.variable(ptrVar, pt)
4246 l = s.variable(lenVar, types.Types[types.TINT])
4247 c = s.variable(capVar, types.Types[types.TINT])
4248 delete(s.vars, ptrVar)
4249 delete(s.vars, lenVar)
4250 delete(s.vars, capVar)
4251 return s.newValue3(ssa.OpSliceMake, slice.Type, p, l, c)
4252 }
4253
4254
4255 func (s *state) minMax(n *ir.CallExpr) *ssa.Value {
4256
4257
4258
4259 fold := func(op func(x, a *ssa.Value) *ssa.Value) *ssa.Value {
4260 x := s.expr(n.Args[0])
4261 for _, arg := range n.Args[1:] {
4262 x = op(x, s.expr(arg))
4263 }
4264 return x
4265 }
4266
4267 typ := n.Type()
4268
4269 if typ.IsFloat() || typ.IsString() {
4270
4271
4272
4273
4274
4275
4276
4277
4278 if typ.IsFloat() {
4279 hasIntrinsic := false
4280 switch Arch.LinkArch.Family {
4281 case sys.AMD64, sys.ARM64, sys.Loong64, sys.RISCV64, sys.S390X:
4282 hasIntrinsic = true
4283 case sys.PPC64:
4284 hasIntrinsic = buildcfg.GOPPC64 >= 9
4285 }
4286
4287 if hasIntrinsic {
4288 var op ssa.Op
4289 switch {
4290 case typ.Kind() == types.TFLOAT64 && n.Op() == ir.OMIN:
4291 op = ssa.OpMin64F
4292 case typ.Kind() == types.TFLOAT64 && n.Op() == ir.OMAX:
4293 op = ssa.OpMax64F
4294 case typ.Kind() == types.TFLOAT32 && n.Op() == ir.OMIN:
4295 op = ssa.OpMin32F
4296 case typ.Kind() == types.TFLOAT32 && n.Op() == ir.OMAX:
4297 op = ssa.OpMax32F
4298 }
4299 return fold(func(x, a *ssa.Value) *ssa.Value {
4300 return s.newValue2(op, typ, x, a)
4301 })
4302 }
4303 }
4304 var name string
4305 switch typ.Kind() {
4306 case types.TFLOAT32:
4307 switch n.Op() {
4308 case ir.OMIN:
4309 name = "fmin32"
4310 case ir.OMAX:
4311 name = "fmax32"
4312 }
4313 case types.TFLOAT64:
4314 switch n.Op() {
4315 case ir.OMIN:
4316 name = "fmin64"
4317 case ir.OMAX:
4318 name = "fmax64"
4319 }
4320 case types.TSTRING:
4321 switch n.Op() {
4322 case ir.OMIN:
4323 name = "strmin"
4324 case ir.OMAX:
4325 name = "strmax"
4326 }
4327 }
4328 fn := typecheck.LookupRuntimeFunc(name)
4329
4330 return fold(func(x, a *ssa.Value) *ssa.Value {
4331 return s.rtcall(fn, true, []*types.Type{typ}, x, a)[0]
4332 })
4333 }
4334
4335 if typ.IsInteger() {
4336 if Arch.LinkArch.Family == sys.RISCV64 && buildcfg.GORISCV64 >= 22 && typ.Size() == 8 {
4337 var op ssa.Op
4338 switch {
4339 case typ.IsSigned() && n.Op() == ir.OMIN:
4340 op = ssa.OpMin64
4341 case typ.IsSigned() && n.Op() == ir.OMAX:
4342 op = ssa.OpMax64
4343 case typ.IsUnsigned() && n.Op() == ir.OMIN:
4344 op = ssa.OpMin64u
4345 case typ.IsUnsigned() && n.Op() == ir.OMAX:
4346 op = ssa.OpMax64u
4347 }
4348 return fold(func(x, a *ssa.Value) *ssa.Value {
4349 return s.newValue2(op, typ, x, a)
4350 })
4351 }
4352 }
4353
4354 lt := s.ssaOp(ir.OLT, typ)
4355
4356 return fold(func(x, a *ssa.Value) *ssa.Value {
4357 switch n.Op() {
4358 case ir.OMIN:
4359
4360 return s.ternary(s.newValue2(lt, types.Types[types.TBOOL], a, x), a, x)
4361 case ir.OMAX:
4362
4363 return s.ternary(s.newValue2(lt, types.Types[types.TBOOL], x, a), a, x)
4364 }
4365 panic("unreachable")
4366 })
4367 }
4368
4369
4370 func (s *state) ternary(cond, x, y *ssa.Value) *ssa.Value {
4371
4372
4373 ternaryVar := ssaMarker("ternary")
4374
4375 bThen := s.f.NewBlock(ssa.BlockPlain)
4376 bElse := s.f.NewBlock(ssa.BlockPlain)
4377 bEnd := s.f.NewBlock(ssa.BlockPlain)
4378
4379 b := s.endBlock()
4380 b.Kind = ssa.BlockIf
4381 b.SetControl(cond)
4382 b.AddEdgeTo(bThen)
4383 b.AddEdgeTo(bElse)
4384
4385 s.startBlock(bThen)
4386 s.vars[ternaryVar] = x
4387 s.endBlock().AddEdgeTo(bEnd)
4388
4389 s.startBlock(bElse)
4390 s.vars[ternaryVar] = y
4391 s.endBlock().AddEdgeTo(bEnd)
4392
4393 s.startBlock(bEnd)
4394 r := s.variable(ternaryVar, x.Type)
4395 delete(s.vars, ternaryVar)
4396 return r
4397 }
4398
4399
4400
4401
4402
4403 func (s *state) condBranch(cond ir.Node, yes, no *ssa.Block, likely int8) {
4404 switch cond.Op() {
4405 case ir.OANDAND:
4406 cond := cond.(*ir.LogicalExpr)
4407 mid := s.f.NewBlock(ssa.BlockPlain)
4408 s.stmtList(cond.Init())
4409 s.condBranch(cond.X, mid, no, max(likely, 0))
4410 s.startBlock(mid)
4411 s.condBranch(cond.Y, yes, no, likely)
4412 return
4413
4414
4415
4416
4417
4418
4419 case ir.OOROR:
4420 cond := cond.(*ir.LogicalExpr)
4421 mid := s.f.NewBlock(ssa.BlockPlain)
4422 s.stmtList(cond.Init())
4423 s.condBranch(cond.X, yes, mid, min(likely, 0))
4424 s.startBlock(mid)
4425 s.condBranch(cond.Y, yes, no, likely)
4426 return
4427
4428
4429
4430 case ir.ONOT:
4431 cond := cond.(*ir.UnaryExpr)
4432 s.stmtList(cond.Init())
4433 s.condBranch(cond.X, no, yes, -likely)
4434 return
4435 case ir.OCONVNOP:
4436 cond := cond.(*ir.ConvExpr)
4437 s.stmtList(cond.Init())
4438 s.condBranch(cond.X, yes, no, likely)
4439 return
4440 }
4441 c := s.expr(cond)
4442 b := s.endBlock()
4443 b.Kind = ssa.BlockIf
4444 b.SetControl(c)
4445 b.Likely = ssa.BranchPrediction(likely)
4446 b.AddEdgeTo(yes)
4447 b.AddEdgeTo(no)
4448 }
4449
4450 type skipMask uint8
4451
4452 const (
4453 skipPtr skipMask = 1 << iota
4454 skipLen
4455 skipCap
4456 )
4457
4458
4459
4460
4461
4462
4463
4464 func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask) {
4465 s.assignWhichMayOverlap(left, right, deref, skip, false)
4466 }
4467 func (s *state) assignWhichMayOverlap(left ir.Node, right *ssa.Value, deref bool, skip skipMask, mayOverlap bool) {
4468 if left.Op() == ir.ONAME && ir.IsBlank(left) {
4469 return
4470 }
4471 t := left.Type()
4472 types.CalcSize(t)
4473 if s.canSSA(left) {
4474 if deref {
4475 s.Fatalf("can SSA LHS %v but not RHS %s", left, right)
4476 }
4477 if left.Op() == ir.ODOT {
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488 left := left.(*ir.SelectorExpr)
4489 t := left.X.Type()
4490 nf := t.NumFields()
4491 idx := fieldIdx(left)
4492
4493
4494 old := s.expr(left.X)
4495
4496 if left.Type().Size() == 0 {
4497
4498 return
4499 }
4500
4501
4502 new := s.newValue0(ssa.OpStructMake, t)
4503
4504
4505 for i := 0; i < nf; i++ {
4506 if i == idx {
4507 new.AddArg(right)
4508 } else {
4509 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), int64(i), old))
4510 }
4511 }
4512
4513
4514 s.assign(left.X, new, false, 0)
4515
4516 return
4517 }
4518 if left.Op() == ir.OINDEX && left.(*ir.IndexExpr).X.Type().IsArray() {
4519 left := left.(*ir.IndexExpr)
4520 s.pushLine(left.Pos())
4521 defer s.popLine()
4522
4523
4524 t := left.X.Type()
4525 n := t.NumElem()
4526
4527 i := s.expr(left.Index)
4528 if n == 0 {
4529
4530
4531 z := s.constInt(types.Types[types.TINT], 0)
4532 s.boundsCheck(z, z, ssa.BoundsIndex, false)
4533 return
4534 }
4535 if n != 1 {
4536
4537
4538
4539
4540
4541
4542
4543
4544 return
4545 }
4546 if t.Size() == 0 {
4547 len := s.constInt(types.Types[types.TINT], n)
4548 s.boundsCheck(i, len, ssa.BoundsIndex, false)
4549 return
4550 }
4551
4552
4553 len := s.constInt(types.Types[types.TINT], 1)
4554 s.boundsCheck(i, len, ssa.BoundsIndex, false)
4555 v := s.newValue1(ssa.OpArrayMake1, t, right)
4556 s.assign(left.X, v, false, 0)
4557 return
4558 }
4559 left := left.(*ir.Name)
4560
4561 s.vars[left] = right
4562 s.addNamedValue(left, right)
4563 return
4564 }
4565
4566
4567
4568 if base, ok := clobberBase(left).(*ir.Name); ok && base.OnStack() && skip == 0 && (t.HasPointers() || ssa.IsMergeCandidate(base)) {
4569 s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, base, s.mem(), !ir.IsAutoTmp(base))
4570 }
4571
4572
4573 addr := s.addr(left)
4574 if ir.IsReflectHeaderDataField(left) {
4575
4576
4577
4578
4579
4580 t = types.Types[types.TUNSAFEPTR]
4581 }
4582 if deref {
4583
4584 if right == nil {
4585 s.zero(t, addr)
4586 } else {
4587 s.moveWhichMayOverlap(t, addr, right, mayOverlap)
4588 }
4589 return
4590 }
4591
4592 s.storeType(t, addr, right, skip, !ir.IsAutoTmp(left))
4593 }
4594
4595
4596 func (s *state) zeroVal(t *types.Type) *ssa.Value {
4597 if t.Size() == 0 {
4598 return s.entryNewValue0(ssa.OpEmpty, t)
4599 }
4600 switch {
4601 case t.IsInteger():
4602 switch t.Size() {
4603 case 1:
4604 return s.constInt8(t, 0)
4605 case 2:
4606 return s.constInt16(t, 0)
4607 case 4:
4608 return s.constInt32(t, 0)
4609 case 8:
4610 return s.constInt64(t, 0)
4611 default:
4612 s.Fatalf("bad sized integer type %v", t)
4613 }
4614 case t.IsFloat():
4615 switch t.Size() {
4616 case 4:
4617 return s.constFloat32(t, 0)
4618 case 8:
4619 return s.constFloat64(t, 0)
4620 default:
4621 s.Fatalf("bad sized float type %v", t)
4622 }
4623 case t.IsComplex():
4624 switch t.Size() {
4625 case 8:
4626 z := s.constFloat32(types.Types[types.TFLOAT32], 0)
4627 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
4628 case 16:
4629 z := s.constFloat64(types.Types[types.TFLOAT64], 0)
4630 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
4631 default:
4632 s.Fatalf("bad sized complex type %v", t)
4633 }
4634
4635 case t.IsString():
4636 return s.constEmptyString(t)
4637 case t.IsPtrShaped():
4638 return s.constNil(t)
4639 case t.IsBoolean():
4640 return s.constBool(false)
4641 case t.IsInterface():
4642 return s.constInterface(t)
4643 case t.IsSlice():
4644 return s.constSlice(t)
4645 case isStructNotSIMD(t):
4646 n := t.NumFields()
4647 v := s.entryNewValue0(ssa.OpStructMake, t)
4648 for i := 0; i < n; i++ {
4649 v.AddArg(s.zeroVal(t.FieldType(i)))
4650 }
4651 return v
4652 case t.IsArray() && t.NumElem() == 1:
4653 return s.entryNewValue1(ssa.OpArrayMake1, t, s.zeroVal(t.Elem()))
4654 case t.IsSIMD():
4655 return s.newValue0(ssa.OpZeroSIMD, t)
4656 }
4657 s.Fatalf("zero for type %v not implemented", t)
4658 return nil
4659 }
4660
4661 type callKind int8
4662
4663 const (
4664 callNormal callKind = iota
4665 callDefer
4666 callDeferStack
4667 callGo
4668 callTail
4669 )
4670
4671 type sfRtCallDef struct {
4672 rtfn *obj.LSym
4673 rtype types.Kind
4674 }
4675
4676 var softFloatOps map[ssa.Op]sfRtCallDef
4677
4678 func softfloatInit() {
4679
4680 softFloatOps = map[ssa.Op]sfRtCallDef{
4681 ssa.OpAdd32F: {typecheck.LookupRuntimeFunc("fadd32"), types.TFLOAT32},
4682 ssa.OpAdd64F: {typecheck.LookupRuntimeFunc("fadd64"), types.TFLOAT64},
4683 ssa.OpSub32F: {typecheck.LookupRuntimeFunc("fadd32"), types.TFLOAT32},
4684 ssa.OpSub64F: {typecheck.LookupRuntimeFunc("fadd64"), types.TFLOAT64},
4685 ssa.OpMul32F: {typecheck.LookupRuntimeFunc("fmul32"), types.TFLOAT32},
4686 ssa.OpMul64F: {typecheck.LookupRuntimeFunc("fmul64"), types.TFLOAT64},
4687 ssa.OpDiv32F: {typecheck.LookupRuntimeFunc("fdiv32"), types.TFLOAT32},
4688 ssa.OpDiv64F: {typecheck.LookupRuntimeFunc("fdiv64"), types.TFLOAT64},
4689
4690 ssa.OpEq64F: {typecheck.LookupRuntimeFunc("feq64"), types.TBOOL},
4691 ssa.OpEq32F: {typecheck.LookupRuntimeFunc("feq32"), types.TBOOL},
4692 ssa.OpNeq64F: {typecheck.LookupRuntimeFunc("feq64"), types.TBOOL},
4693 ssa.OpNeq32F: {typecheck.LookupRuntimeFunc("feq32"), types.TBOOL},
4694 ssa.OpLess64F: {typecheck.LookupRuntimeFunc("fgt64"), types.TBOOL},
4695 ssa.OpLess32F: {typecheck.LookupRuntimeFunc("fgt32"), types.TBOOL},
4696 ssa.OpLeq64F: {typecheck.LookupRuntimeFunc("fge64"), types.TBOOL},
4697 ssa.OpLeq32F: {typecheck.LookupRuntimeFunc("fge32"), types.TBOOL},
4698
4699 ssa.OpCvt32to32F: {typecheck.LookupRuntimeFunc("fint32to32"), types.TFLOAT32},
4700 ssa.OpCvt32Fto32: {typecheck.LookupRuntimeFunc("f32toint32"), types.TINT32},
4701 ssa.OpCvt64to32F: {typecheck.LookupRuntimeFunc("fint64to32"), types.TFLOAT32},
4702 ssa.OpCvt32Fto64: {typecheck.LookupRuntimeFunc("f32toint64"), types.TINT64},
4703 ssa.OpCvt64Uto32F: {typecheck.LookupRuntimeFunc("fuint64to32"), types.TFLOAT32},
4704 ssa.OpCvt32Fto64U: {typecheck.LookupRuntimeFunc("f32touint64"), types.TUINT64},
4705 ssa.OpCvt32to64F: {typecheck.LookupRuntimeFunc("fint32to64"), types.TFLOAT64},
4706 ssa.OpCvt64Fto32: {typecheck.LookupRuntimeFunc("f64toint32"), types.TINT32},
4707 ssa.OpCvt64to64F: {typecheck.LookupRuntimeFunc("fint64to64"), types.TFLOAT64},
4708 ssa.OpCvt64Fto64: {typecheck.LookupRuntimeFunc("f64toint64"), types.TINT64},
4709 ssa.OpCvt64Uto64F: {typecheck.LookupRuntimeFunc("fuint64to64"), types.TFLOAT64},
4710 ssa.OpCvt64Fto64U: {typecheck.LookupRuntimeFunc("f64touint64"), types.TUINT64},
4711 ssa.OpCvt32Fto64F: {typecheck.LookupRuntimeFunc("f32to64"), types.TFLOAT64},
4712 ssa.OpCvt64Fto32F: {typecheck.LookupRuntimeFunc("f64to32"), types.TFLOAT32},
4713 }
4714 }
4715
4716
4717
4718 func (s *state) sfcall(op ssa.Op, args ...*ssa.Value) (*ssa.Value, bool) {
4719 f2i := func(t *types.Type) *types.Type {
4720 switch t.Kind() {
4721 case types.TFLOAT32:
4722 return types.Types[types.TUINT32]
4723 case types.TFLOAT64:
4724 return types.Types[types.TUINT64]
4725 }
4726 return t
4727 }
4728
4729 if callDef, ok := softFloatOps[op]; ok {
4730 switch op {
4731 case ssa.OpLess32F,
4732 ssa.OpLess64F,
4733 ssa.OpLeq32F,
4734 ssa.OpLeq64F:
4735 args[0], args[1] = args[1], args[0]
4736 case ssa.OpSub32F,
4737 ssa.OpSub64F:
4738 args[1] = s.newValue1(s.ssaOp(ir.ONEG, types.Types[callDef.rtype]), args[1].Type, args[1])
4739 }
4740
4741
4742
4743 for i, a := range args {
4744 if a.Type.IsFloat() {
4745 args[i] = s.newValue1(ssa.OpCopy, f2i(a.Type), a)
4746 }
4747 }
4748
4749 rt := types.Types[callDef.rtype]
4750 result := s.rtcall(callDef.rtfn, true, []*types.Type{f2i(rt)}, args...)[0]
4751 if rt.IsFloat() {
4752 result = s.newValue1(ssa.OpCopy, rt, result)
4753 }
4754 if op == ssa.OpNeq32F || op == ssa.OpNeq64F {
4755 result = s.newValue1(ssa.OpNot, result.Type, result)
4756 }
4757 return result, true
4758 }
4759 return nil, false
4760 }
4761
4762
4763 func (s *state) split(v *ssa.Value) (*ssa.Value, *ssa.Value) {
4764 p0 := s.newValue1(ssa.OpSelect0, v.Type.FieldType(0), v)
4765 p1 := s.newValue1(ssa.OpSelect1, v.Type.FieldType(1), v)
4766 return p0, p1
4767 }
4768
4769
4770 func (s *state) intrinsicCall(n *ir.CallExpr) *ssa.Value {
4771 v := findIntrinsic(n.Fun.Sym())(s, n, s.intrinsicArgs(n))
4772 if ssa.IntrinsicsDebug > 0 {
4773 x := v
4774 if x == nil {
4775 x = s.mem()
4776 }
4777 if x.Op == ssa.OpSelect0 || x.Op == ssa.OpSelect1 {
4778 x = x.Args[0]
4779 }
4780 base.WarnfAt(n.Pos(), "intrinsic substitution for %v with %s", n.Fun.Sym().Name, x.LongString())
4781 }
4782 return v
4783 }
4784
4785
4786 func (s *state) intrinsicArgs(n *ir.CallExpr) []*ssa.Value {
4787 args := make([]*ssa.Value, len(n.Args))
4788 for i, n := range n.Args {
4789 args[i] = s.expr(n)
4790 }
4791 return args
4792 }
4793
4794
4795
4796
4797
4798
4799
4800 func (s *state) openDeferRecord(n *ir.CallExpr) {
4801 if len(n.Args) != 0 || n.Op() != ir.OCALLFUNC || n.Fun.Type().NumResults() != 0 {
4802 s.Fatalf("defer call with arguments or results: %v", n)
4803 }
4804
4805 opendefer := &openDeferInfo{
4806 n: n,
4807 }
4808 fn := n.Fun
4809
4810
4811
4812 closureVal := s.expr(fn)
4813 closure := s.openDeferSave(fn.Type(), closureVal)
4814 opendefer.closureNode = closure.Aux.(*ir.Name)
4815 if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC) {
4816 opendefer.closure = closure
4817 }
4818 index := len(s.openDefers)
4819 s.openDefers = append(s.openDefers, opendefer)
4820
4821
4822
4823 bitvalue := s.constInt8(types.Types[types.TUINT8], 1<<uint(index))
4824 newDeferBits := s.newValue2(ssa.OpOr8, types.Types[types.TUINT8], s.variable(deferBitsVar, types.Types[types.TUINT8]), bitvalue)
4825 s.vars[deferBitsVar] = newDeferBits
4826 s.store(types.Types[types.TUINT8], s.deferBitsAddr, newDeferBits)
4827 }
4828
4829
4830
4831
4832
4833
4834 func (s *state) openDeferSave(t *types.Type, val *ssa.Value) *ssa.Value {
4835 if !ssa.CanSSA(t) {
4836 s.Fatalf("openDeferSave of non-SSA-able type %v val=%v", t, val)
4837 }
4838 if !t.HasPointers() {
4839 s.Fatalf("openDeferSave of pointerless type %v val=%v", t, val)
4840 }
4841 pos := val.Pos
4842 temp := typecheck.TempAt(pos.WithNotStmt(), s.curfn, t)
4843 temp.SetOpenDeferSlot(true)
4844 temp.SetFrameOffset(int64(len(s.openDefers)))
4845 var addrTemp *ssa.Value
4846
4847
4848 if s.curBlock.ID != s.f.Entry.ID {
4849
4850
4851
4852 if t.HasPointers() {
4853 s.defvars[s.f.Entry.ID][memVar] = s.f.Entry.NewValue1A(src.NoXPos, ssa.OpVarDef, types.TypeMem, temp, s.defvars[s.f.Entry.ID][memVar])
4854 }
4855 s.defvars[s.f.Entry.ID][memVar] = s.f.Entry.NewValue1A(src.NoXPos, ssa.OpVarLive, types.TypeMem, temp, s.defvars[s.f.Entry.ID][memVar])
4856 addrTemp = s.f.Entry.NewValue2A(src.NoXPos, ssa.OpLocalAddr, types.NewPtr(temp.Type()), temp, s.sp, s.defvars[s.f.Entry.ID][memVar])
4857 } else {
4858
4859
4860
4861 if t.HasPointers() {
4862 s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, temp, s.mem(), false)
4863 }
4864 s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, temp, s.mem(), false)
4865 addrTemp = s.newValue2Apos(ssa.OpLocalAddr, types.NewPtr(temp.Type()), temp, s.sp, s.mem(), false)
4866 }
4867
4868
4869
4870
4871
4872 temp.SetNeedzero(true)
4873
4874
4875 s.store(t, addrTemp, val)
4876 return addrTemp
4877 }
4878
4879
4880
4881
4882
4883 func (s *state) openDeferExit() {
4884 deferExit := s.f.NewBlock(ssa.BlockPlain)
4885 s.endBlock().AddEdgeTo(deferExit)
4886 s.startBlock(deferExit)
4887 s.lastDeferExit = deferExit
4888 s.lastDeferCount = len(s.openDefers)
4889 zeroval := s.constInt8(types.Types[types.TUINT8], 0)
4890
4891 for i := len(s.openDefers) - 1; i >= 0; i-- {
4892 r := s.openDefers[i]
4893 bCond := s.f.NewBlock(ssa.BlockPlain)
4894 bEnd := s.f.NewBlock(ssa.BlockPlain)
4895
4896 deferBits := s.variable(deferBitsVar, types.Types[types.TUINT8])
4897
4898
4899 bitval := s.constInt8(types.Types[types.TUINT8], 1<<uint(i))
4900 andval := s.newValue2(ssa.OpAnd8, types.Types[types.TUINT8], deferBits, bitval)
4901 eqVal := s.newValue2(ssa.OpEq8, types.Types[types.TBOOL], andval, zeroval)
4902 b := s.endBlock()
4903 b.Kind = ssa.BlockIf
4904 b.SetControl(eqVal)
4905 b.AddEdgeTo(bEnd)
4906 b.AddEdgeTo(bCond)
4907 bCond.AddEdgeTo(bEnd)
4908 s.startBlock(bCond)
4909
4910
4911
4912 nbitval := s.newValue1(ssa.OpCom8, types.Types[types.TUINT8], bitval)
4913 maskedval := s.newValue2(ssa.OpAnd8, types.Types[types.TUINT8], deferBits, nbitval)
4914 s.store(types.Types[types.TUINT8], s.deferBitsAddr, maskedval)
4915
4916
4917 s.vars[deferBitsVar] = maskedval
4918
4919
4920
4921
4922 fn := r.n.Fun
4923 stksize := fn.Type().ArgWidth()
4924 var callArgs []*ssa.Value
4925 var call *ssa.Value
4926 if r.closure != nil {
4927 v := s.load(r.closure.Type.Elem(), r.closure)
4928 s.maybeNilCheckClosure(v, callDefer)
4929 codeptr := s.rawLoad(types.Types[types.TUINTPTR], v)
4930 aux := ssa.ClosureAuxCall(s.f.ABIDefault.ABIAnalyzeTypes(nil, nil))
4931 call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v)
4932 } else {
4933 aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), s.f.ABIDefault.ABIAnalyzeTypes(nil, nil))
4934 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
4935 }
4936 callArgs = append(callArgs, s.mem())
4937 call.AddArgs(callArgs...)
4938 call.AuxInt = stksize
4939 s.vars[memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, 0, call)
4940
4941
4942
4943
4944 if r.closureNode != nil {
4945 s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, r.closureNode, s.mem(), false)
4946 }
4947
4948 s.endBlock()
4949 s.startBlock(bEnd)
4950 }
4951 }
4952
4953 func (s *state) callResult(n *ir.CallExpr, k callKind) *ssa.Value {
4954 return s.call(n, k, false, nil)
4955 }
4956
4957 func (s *state) callAddr(n *ir.CallExpr, k callKind) *ssa.Value {
4958 return s.call(n, k, true, nil)
4959 }
4960
4961
4962
4963 func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool, deferExtra ir.Expr) *ssa.Value {
4964 s.prevCall = nil
4965 var calleeLSym *obj.LSym
4966 var closure *ssa.Value
4967 var codeptr *ssa.Value
4968 var dextra *ssa.Value
4969 var rcvr *ssa.Value
4970 fn := n.Fun
4971 var ACArgs []*types.Type
4972 var ACResults []*types.Type
4973 var callArgs []*ssa.Value
4974
4975 callABI := s.f.ABIDefault
4976
4977 if k != callNormal && k != callTail && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.Fun.Type().NumResults() != 0) {
4978 s.Fatalf("go/defer call with arguments: %v", n)
4979 }
4980
4981 isCallDeferRangeFunc := false
4982
4983 switch n.Op() {
4984 case ir.OCALLFUNC:
4985 if (k == callNormal || k == callTail) && fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC {
4986 fn := fn.(*ir.Name)
4987 calleeLSym = callTargetLSym(fn)
4988 if buildcfg.Experiment.RegabiArgs {
4989
4990
4991
4992
4993
4994 if fn.Func != nil {
4995 callABI = abiForFunc(fn.Func, s.f.ABI0, s.f.ABI1)
4996 }
4997 } else {
4998
4999 inRegistersImported := fn.Pragma()&ir.RegisterParams != 0
5000 inRegistersSamePackage := fn.Func != nil && fn.Func.Pragma&ir.RegisterParams != 0
5001 if inRegistersImported || inRegistersSamePackage {
5002 callABI = s.f.ABI1
5003 }
5004 }
5005 if fn := n.Fun.Sym().Name; n.Fun.Sym().Pkg == ir.Pkgs.Runtime && fn == "deferrangefunc" {
5006 isCallDeferRangeFunc = true
5007 }
5008 break
5009 }
5010 closure = s.expr(fn)
5011 if k != callDefer && k != callDeferStack {
5012
5013
5014 s.maybeNilCheckClosure(closure, k)
5015 }
5016 case ir.OCALLINTER:
5017 if fn.Op() != ir.ODOTINTER {
5018 s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
5019 }
5020 fn := fn.(*ir.SelectorExpr)
5021 var iclosure *ssa.Value
5022 iclosure, rcvr = s.getClosureAndRcvr(fn)
5023 if k == callNormal || k == callTail {
5024 codeptr = s.load(types.Types[types.TUINTPTR], iclosure)
5025 } else {
5026 closure = iclosure
5027 }
5028 }
5029 if deferExtra != nil {
5030 dextra = s.expr(deferExtra)
5031 }
5032
5033 params := callABI.ABIAnalyze(n.Fun.Type(), false )
5034 types.CalcSize(fn.Type())
5035 stksize := params.ArgWidth()
5036
5037 res := n.Fun.Type().Results()
5038 if k == callNormal || k == callTail {
5039 for _, p := range params.OutParams() {
5040 ACResults = append(ACResults, p.Type)
5041 }
5042 }
5043
5044 var call *ssa.Value
5045 if k == callDeferStack {
5046 if stksize != 0 {
5047 s.Fatalf("deferprocStack with non-zero stack size %d: %v", stksize, n)
5048 }
5049
5050 t := deferstruct()
5051 n, addr := s.temp(n.Pos(), t)
5052 n.SetNonMergeable(true)
5053 s.store(closure.Type,
5054 s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(deferStructFnField), addr),
5055 closure)
5056
5057
5058 ACArgs = append(ACArgs, types.Types[types.TUINTPTR])
5059 aux := ssa.StaticAuxCall(ir.Syms.DeferprocStack, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5060 callArgs = append(callArgs, addr, s.mem())
5061 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5062 call.AddArgs(callArgs...)
5063 call.AuxInt = int64(types.PtrSize)
5064 } else {
5065
5066
5067 argStart := base.Ctxt.Arch.FixedFrameSize
5068
5069 if k != callNormal && k != callTail {
5070
5071 ACArgs = append(ACArgs, types.Types[types.TUINTPTR])
5072 callArgs = append(callArgs, closure)
5073 stksize += int64(types.PtrSize)
5074 argStart += int64(types.PtrSize)
5075 if dextra != nil {
5076
5077 ACArgs = append(ACArgs, types.Types[types.TINTER])
5078 callArgs = append(callArgs, dextra)
5079 stksize += 2 * int64(types.PtrSize)
5080 argStart += 2 * int64(types.PtrSize)
5081 }
5082 }
5083
5084
5085 if rcvr != nil {
5086 callArgs = append(callArgs, rcvr)
5087 }
5088
5089
5090 t := n.Fun.Type()
5091 args := n.Args
5092
5093 for _, p := range params.InParams() {
5094 ACArgs = append(ACArgs, p.Type)
5095 }
5096
5097
5098
5099
5100 if s.curBlock.ID == s.f.Entry.ID && s.hasOpenDefers {
5101 b := s.endBlock()
5102 b.Kind = ssa.BlockPlain
5103 curb := s.f.NewBlock(ssa.BlockPlain)
5104 b.AddEdgeTo(curb)
5105 s.startBlock(curb)
5106 }
5107
5108 for i, n := range args {
5109 callArgs = append(callArgs, s.putArg(n, t.Param(i).Type))
5110 }
5111
5112 callArgs = append(callArgs, s.mem())
5113
5114
5115 switch {
5116 case k == callDefer:
5117 sym := ir.Syms.Deferproc
5118 if dextra != nil {
5119 sym = ir.Syms.Deferprocat
5120 }
5121 aux := ssa.StaticAuxCall(sym, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5122 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5123 case k == callGo:
5124 aux := ssa.StaticAuxCall(ir.Syms.Newproc, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5125 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5126 case closure != nil:
5127
5128
5129
5130
5131
5132 codeptr = s.rawLoad(types.Types[types.TUINTPTR], closure)
5133 aux := ssa.ClosureAuxCall(callABI.ABIAnalyzeTypes(ACArgs, ACResults))
5134 call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure)
5135 case codeptr != nil:
5136
5137 aux := ssa.InterfaceAuxCall(params)
5138 call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr)
5139 if k == callTail {
5140 call.Op = ssa.OpTailLECallInter
5141 stksize = 0
5142 }
5143 case calleeLSym != nil:
5144 aux := ssa.StaticAuxCall(calleeLSym, params)
5145 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5146 if k == callTail {
5147 call.Op = ssa.OpTailLECall
5148 stksize = 0
5149 }
5150 default:
5151 s.Fatalf("bad call type %v %v", n.Op(), n)
5152 }
5153 call.AddArgs(callArgs...)
5154 call.AuxInt = stksize
5155 }
5156 s.prevCall = call
5157 s.vars[memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
5158
5159 for _, v := range n.KeepAlive {
5160 if !v.Addrtaken() {
5161 s.Fatalf("KeepAlive variable %v must have Addrtaken set", v)
5162 }
5163 switch v.Class {
5164 case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
5165 default:
5166 s.Fatalf("KeepAlive variable %v must be Auto or Arg", v)
5167 }
5168 s.vars[memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, v, s.mem())
5169 }
5170
5171
5172 var result *ssa.Value
5173 if len(res) == 0 || k != callNormal {
5174 result = nil
5175 } else {
5176 fp := res[0]
5177 if returnResultAddr {
5178 result = s.resultAddrOfCall(call, 0, fp.Type)
5179 } else {
5180 result = s.newValue1I(ssa.OpSelectN, fp.Type, 0, call)
5181 }
5182 if n.Reshape {
5183 result = s.newValue1(ssa.OpCopy, n.Type(), result)
5184 }
5185 }
5186
5187
5188 if k == callDefer || k == callDeferStack || isCallDeferRangeFunc {
5189 b := s.endBlock()
5190 b.Kind = ssa.BlockDefer
5191 b.SetControl(call)
5192 bNext := s.f.NewBlock(ssa.BlockPlain)
5193 b.AddEdgeTo(bNext)
5194 r := s.f.DeferReturn
5195 if r == nil {
5196 r = s.f.NewBlock(ssa.BlockPlain)
5197 s.startBlock(r)
5198 s.exit()
5199 s.f.DeferReturn = r
5200 }
5201 b.AddEdgeTo(r)
5202 b.Likely = ssa.BranchLikely
5203 s.startBlock(bNext)
5204 }
5205
5206 return result
5207 }
5208
5209
5210
5211 func (s *state) maybeNilCheckClosure(closure *ssa.Value, k callKind) {
5212 if Arch.LinkArch.Family == sys.Wasm || buildcfg.GOOS == "aix" && k != callGo {
5213
5214
5215 s.nilCheck(closure)
5216 }
5217 }
5218
5219
5220
5221 func (s *state) getClosureAndRcvr(fn *ir.SelectorExpr) (*ssa.Value, *ssa.Value) {
5222 i := s.expr(fn.X)
5223 itab := s.newValue1(ssa.OpITab, types.Types[types.TUINTPTR], i)
5224 s.nilCheck(itab)
5225 itabidx := fn.Offset() + rttype.ITab.OffsetOf("Fun")
5226 closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
5227 rcvr := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, i)
5228 return closure, rcvr
5229 }
5230
5231
5232
5233 func etypesign(e types.Kind) int8 {
5234 switch e {
5235 case types.TINT8, types.TINT16, types.TINT32, types.TINT64, types.TINT:
5236 return -1
5237 case types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINT, types.TUINTPTR, types.TUNSAFEPTR:
5238 return +1
5239 }
5240 return 0
5241 }
5242
5243
5244
5245 func (s *state) addr(n ir.Node) *ssa.Value {
5246 if n.Op() != ir.ONAME {
5247 s.pushLine(n.Pos())
5248 defer s.popLine()
5249 }
5250
5251 if s.canSSA(n) {
5252
5253
5254
5255
5256
5257
5258
5259
5260 return s.newValue1A(ssa.OpAddr, n.Type().PtrTo(), ir.Syms.Zerobase, s.sb)
5261 }
5262
5263 t := types.NewPtr(n.Type())
5264 linksymOffset := func(lsym *obj.LSym, offset int64) *ssa.Value {
5265 v := s.entryNewValue1A(ssa.OpAddr, t, lsym, s.sb)
5266
5267 if offset != 0 {
5268 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, offset, v)
5269 }
5270 return v
5271 }
5272 switch n.Op() {
5273 case ir.OLINKSYMOFFSET:
5274 no := n.(*ir.LinksymOffsetExpr)
5275 return linksymOffset(no.Linksym, no.Offset_)
5276 case ir.ONAME:
5277 n := n.(*ir.Name)
5278 if n.Heapaddr != nil {
5279 return s.expr(n.Heapaddr)
5280 }
5281 switch n.Class {
5282 case ir.PEXTERN:
5283
5284 return linksymOffset(n.Linksym(), 0)
5285 case ir.PPARAM:
5286
5287 v := s.decladdrs[n]
5288 if v != nil {
5289 return v
5290 }
5291 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
5292 return nil
5293 case ir.PAUTO:
5294 return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), !ir.IsAutoTmp(n))
5295
5296 case ir.PPARAMOUT:
5297
5298
5299 return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), true)
5300 default:
5301 s.Fatalf("variable address class %v not implemented", n.Class)
5302 return nil
5303 }
5304 case ir.ORESULT:
5305
5306 n := n.(*ir.ResultExpr)
5307 return s.resultAddrOfCall(s.prevCall, n.Index, n.Type())
5308 case ir.OINDEX:
5309 n := n.(*ir.IndexExpr)
5310 if n.X.Type().IsSlice() {
5311 a := s.expr(n.X)
5312 i := s.expr(n.Index)
5313 len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], a)
5314 i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
5315 p := s.newValue1(ssa.OpSlicePtr, t, a)
5316 return s.newValue2(ssa.OpPtrIndex, t, p, i)
5317 } else {
5318 a := s.addr(n.X)
5319 i := s.expr(n.Index)
5320 len := s.constInt(types.Types[types.TINT], n.X.Type().NumElem())
5321 i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
5322 return s.newValue2(ssa.OpPtrIndex, types.NewPtr(n.X.Type().Elem()), a, i)
5323 }
5324 case ir.ODEREF:
5325 n := n.(*ir.StarExpr)
5326 return s.exprPtr(n.X, n.Bounded(), n.Pos())
5327 case ir.ODOT:
5328 n := n.(*ir.SelectorExpr)
5329 p := s.addr(n.X)
5330 return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
5331 case ir.ODOTPTR:
5332 n := n.(*ir.SelectorExpr)
5333 p := s.exprPtr(n.X, n.Bounded(), n.Pos())
5334 return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
5335 case ir.OCONVNOP:
5336 n := n.(*ir.ConvExpr)
5337 if n.Type() == n.X.Type() {
5338 return s.addr(n.X)
5339 }
5340 addr := s.addr(n.X)
5341 return s.newValue1(ssa.OpCopy, t, addr)
5342 case ir.OCALLFUNC, ir.OCALLINTER:
5343 n := n.(*ir.CallExpr)
5344 return s.callAddr(n, callNormal)
5345 case ir.ODOTTYPE, ir.ODYNAMICDOTTYPE:
5346 var v *ssa.Value
5347 if n.Op() == ir.ODOTTYPE {
5348 v, _ = s.dottype(n.(*ir.TypeAssertExpr), false)
5349 } else {
5350 v, _ = s.dynamicDottype(n.(*ir.DynamicTypeAssertExpr), false)
5351 }
5352 if v.Op != ssa.OpLoad {
5353 s.Fatalf("dottype of non-load")
5354 }
5355 if v.Args[1] != s.mem() {
5356 s.Fatalf("memory no longer live from dottype load")
5357 }
5358 return v.Args[0]
5359 default:
5360 s.Fatalf("unhandled addr %v", n.Op())
5361 return nil
5362 }
5363 }
5364
5365
5366
5367 func (s *state) canSSA(n ir.Node) bool {
5368 if base.Flag.N != 0 {
5369 return false
5370 }
5371 for {
5372 nn := n
5373 if nn.Op() == ir.ODOT {
5374 nn := nn.(*ir.SelectorExpr)
5375 n = nn.X
5376 continue
5377 }
5378 if nn.Op() == ir.OINDEX {
5379 nn := nn.(*ir.IndexExpr)
5380 if nn.X.Type().IsArray() {
5381 n = nn.X
5382 continue
5383 }
5384 }
5385 break
5386 }
5387 if n.Op() != ir.ONAME {
5388 return false
5389 }
5390 return s.canSSAName(n.(*ir.Name)) && ssa.CanSSA(n.Type())
5391 }
5392
5393 func (s *state) canSSAName(name *ir.Name) bool {
5394 if name.Addrtaken() || !name.OnStack() {
5395 return false
5396 }
5397 switch name.Class {
5398 case ir.PPARAMOUT:
5399 if s.hasdefer {
5400
5401
5402
5403
5404
5405 return false
5406 }
5407 if s.cgoUnsafeArgs {
5408
5409
5410 return false
5411 }
5412 }
5413 return true
5414
5415 }
5416
5417
5418 func (s *state) exprPtr(n ir.Node, bounded bool, lineno src.XPos) *ssa.Value {
5419 p := s.expr(n)
5420 if bounded || n.NonNil() {
5421 if s.f.Frontend().Debug_checknil() && lineno.Line() > 1 {
5422 s.f.Warnl(lineno, "removed nil check")
5423 }
5424 return p
5425 }
5426 p = s.nilCheck(p)
5427 return p
5428 }
5429
5430
5431
5432
5433
5434
5435 func (s *state) nilCheck(ptr *ssa.Value) *ssa.Value {
5436 if base.Debug.DisableNil != 0 || s.curfn.NilCheckDisabled() {
5437 return ptr
5438 }
5439 return s.newValue2(ssa.OpNilCheck, ptr.Type, ptr, s.mem())
5440 }
5441
5442
5443
5444
5445
5446
5447
5448 func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
5449 idx = s.extendIndex(idx, len, kind, bounded)
5450
5451 if bounded || base.Flag.B != 0 {
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472 return idx
5473 }
5474
5475 bNext := s.f.NewBlock(ssa.BlockPlain)
5476 bPanic := s.f.NewBlock(ssa.BlockExit)
5477
5478 if !idx.Type.IsSigned() {
5479 switch kind {
5480 case ssa.BoundsIndex:
5481 kind = ssa.BoundsIndexU
5482 case ssa.BoundsSliceAlen:
5483 kind = ssa.BoundsSliceAlenU
5484 case ssa.BoundsSliceAcap:
5485 kind = ssa.BoundsSliceAcapU
5486 case ssa.BoundsSliceB:
5487 kind = ssa.BoundsSliceBU
5488 case ssa.BoundsSlice3Alen:
5489 kind = ssa.BoundsSlice3AlenU
5490 case ssa.BoundsSlice3Acap:
5491 kind = ssa.BoundsSlice3AcapU
5492 case ssa.BoundsSlice3B:
5493 kind = ssa.BoundsSlice3BU
5494 case ssa.BoundsSlice3C:
5495 kind = ssa.BoundsSlice3CU
5496 }
5497 }
5498
5499 var cmp *ssa.Value
5500 if kind == ssa.BoundsIndex || kind == ssa.BoundsIndexU {
5501 cmp = s.newValue2(ssa.OpIsInBounds, types.Types[types.TBOOL], idx, len)
5502 } else {
5503 cmp = s.newValue2(ssa.OpIsSliceInBounds, types.Types[types.TBOOL], idx, len)
5504 }
5505 b := s.endBlock()
5506 b.Kind = ssa.BlockIf
5507 b.SetControl(cmp)
5508 b.Likely = ssa.BranchLikely
5509 b.AddEdgeTo(bNext)
5510 b.AddEdgeTo(bPanic)
5511
5512 s.startBlock(bPanic)
5513 if Arch.LinkArch.Family == sys.Wasm {
5514
5515
5516 s.rtcall(BoundsCheckFunc[kind], false, nil, idx, len)
5517 } else {
5518 mem := s.newValue3I(ssa.OpPanicBounds, types.TypeMem, int64(kind), idx, len, s.mem())
5519 s.endBlock().SetControl(mem)
5520 }
5521 s.startBlock(bNext)
5522
5523
5524 if base.Flag.Cfg.SpectreIndex {
5525 op := ssa.OpSpectreIndex
5526 if kind != ssa.BoundsIndex && kind != ssa.BoundsIndexU {
5527 op = ssa.OpSpectreSliceIndex
5528 }
5529 idx = s.newValue2(op, types.Types[types.TINT], idx, len)
5530 }
5531
5532 return idx
5533 }
5534
5535
5536 func (s *state) check(cmp *ssa.Value, fn *obj.LSym) {
5537 b := s.endBlock()
5538 b.Kind = ssa.BlockIf
5539 b.SetControl(cmp)
5540 b.Likely = ssa.BranchLikely
5541 bNext := s.f.NewBlock(ssa.BlockPlain)
5542 line := s.peekPos()
5543 pos := base.Ctxt.PosTable.Pos(line)
5544 fl := funcLine{f: fn, base: pos.Base(), line: pos.Line()}
5545 bPanic := s.panics[fl]
5546 if bPanic == nil {
5547 bPanic = s.f.NewBlock(ssa.BlockPlain)
5548 s.panics[fl] = bPanic
5549 s.startBlock(bPanic)
5550
5551
5552 s.rtcall(fn, false, nil)
5553 }
5554 b.AddEdgeTo(bNext)
5555 b.AddEdgeTo(bPanic)
5556 s.startBlock(bNext)
5557 }
5558
5559 func (s *state) intDivide(n ir.Node, a, b *ssa.Value) *ssa.Value {
5560 needcheck := true
5561 switch b.Op {
5562 case ssa.OpConst8, ssa.OpConst16, ssa.OpConst32, ssa.OpConst64:
5563 if b.AuxInt != 0 {
5564 needcheck = false
5565 }
5566 }
5567 if needcheck {
5568
5569 cmp := s.newValue2(s.ssaOp(ir.ONE, n.Type()), types.Types[types.TBOOL], b, s.zeroVal(n.Type()))
5570 s.check(cmp, ir.Syms.Panicdivide)
5571 }
5572 return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
5573 }
5574
5575
5576
5577
5578
5579 func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args ...*ssa.Value) []*ssa.Value {
5580 s.prevCall = nil
5581
5582 off := base.Ctxt.Arch.FixedFrameSize
5583 var callArgs []*ssa.Value
5584 var callArgTypes []*types.Type
5585
5586 for _, arg := range args {
5587 t := arg.Type
5588 off = types.RoundUp(off, t.Alignment())
5589 size := t.Size()
5590 callArgs = append(callArgs, arg)
5591 callArgTypes = append(callArgTypes, t)
5592 off += size
5593 }
5594 off = types.RoundUp(off, int64(types.RegSize))
5595
5596
5597 var call *ssa.Value
5598 aux := ssa.StaticAuxCall(fn, s.f.ABIDefault.ABIAnalyzeTypes(callArgTypes, results))
5599 callArgs = append(callArgs, s.mem())
5600 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5601 call.AddArgs(callArgs...)
5602 s.vars[memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(results)), call)
5603
5604 if !returns {
5605
5606 b := s.endBlock()
5607 b.Kind = ssa.BlockExit
5608 b.SetControl(call)
5609 call.AuxInt = off - base.Ctxt.Arch.FixedFrameSize
5610 if len(results) > 0 {
5611 s.Fatalf("panic call can't have results")
5612 }
5613 return nil
5614 }
5615
5616
5617 res := make([]*ssa.Value, len(results))
5618 for i, t := range results {
5619 off = types.RoundUp(off, t.Alignment())
5620 res[i] = s.resultOfCall(call, int64(i), t)
5621 off += t.Size()
5622 }
5623 off = types.RoundUp(off, int64(types.PtrSize))
5624
5625
5626 call.AuxInt = off
5627
5628 return res
5629 }
5630
5631
5632 func (s *state) storeType(t *types.Type, left, right *ssa.Value, skip skipMask, leftIsStmt bool) {
5633 s.instrument(t, left, instrumentWrite)
5634
5635 if skip == 0 && (!t.HasPointers() || ssa.IsStackAddr(left)) {
5636
5637 s.vars[memVar] = s.newValue3Apos(ssa.OpStore, types.TypeMem, t, left, right, s.mem(), leftIsStmt)
5638 return
5639 }
5640
5641
5642
5643
5644
5645
5646 s.storeTypeScalars(t, left, right, skip)
5647 if skip&skipPtr == 0 && t.HasPointers() {
5648 s.storeTypePtrs(t, left, right)
5649 }
5650 }
5651
5652
5653 func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip skipMask) {
5654 switch {
5655 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex() || t.IsSIMD():
5656 s.store(t, left, right)
5657 case t.IsPtrShaped():
5658 if t.IsPtr() && t.Elem().NotInHeap() {
5659 s.store(t, left, right)
5660 }
5661
5662 case t.IsString():
5663 if skip&skipLen != 0 {
5664 return
5665 }
5666 len := s.newValue1(ssa.OpStringLen, types.Types[types.TINT], right)
5667 lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
5668 s.store(types.Types[types.TINT], lenAddr, len)
5669 case t.IsSlice():
5670 if skip&skipLen == 0 {
5671 len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], right)
5672 lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
5673 s.store(types.Types[types.TINT], lenAddr, len)
5674 }
5675 if skip&skipCap == 0 {
5676 cap := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], right)
5677 capAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, 2*s.config.PtrSize, left)
5678 s.store(types.Types[types.TINT], capAddr, cap)
5679 }
5680 case t.IsInterface():
5681
5682 itab := s.newValue1(ssa.OpITab, s.f.Config.Types.BytePtr, right)
5683 s.store(types.Types[types.TUINTPTR], left, itab)
5684 case isStructNotSIMD(t):
5685 n := t.NumFields()
5686 for i := 0; i < n; i++ {
5687 ft := t.FieldType(i)
5688 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
5689 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
5690 s.storeTypeScalars(ft, addr, val, 0)
5691 }
5692 case t.IsArray() && t.Size() == 0:
5693
5694 case t.IsArray() && t.NumElem() == 1:
5695 s.storeTypeScalars(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right), 0)
5696 default:
5697 s.Fatalf("bad write barrier type %v", t)
5698 }
5699 }
5700
5701
5702 func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
5703 switch {
5704 case t.IsPtrShaped():
5705 if t.IsPtr() && t.Elem().NotInHeap() {
5706 break
5707 }
5708 s.store(t, left, right)
5709 case t.IsString():
5710 ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right)
5711 s.store(s.f.Config.Types.BytePtr, left, ptr)
5712 case t.IsSlice():
5713 elType := types.NewPtr(t.Elem())
5714 ptr := s.newValue1(ssa.OpSlicePtr, elType, right)
5715 s.store(elType, left, ptr)
5716 case t.IsInterface():
5717
5718 idata := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, right)
5719 idataAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.BytePtrPtr, s.config.PtrSize, left)
5720 s.store(s.f.Config.Types.BytePtr, idataAddr, idata)
5721 case isStructNotSIMD(t):
5722 n := t.NumFields()
5723 for i := 0; i < n; i++ {
5724 ft := t.FieldType(i)
5725 if !ft.HasPointers() {
5726 continue
5727 }
5728 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
5729 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
5730 s.storeTypePtrs(ft, addr, val)
5731 }
5732 case t.IsArray() && t.Size() == 0:
5733
5734 case t.IsArray() && t.NumElem() == 1:
5735 s.storeTypePtrs(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right))
5736 default:
5737 s.Fatalf("bad write barrier type %v", t)
5738 }
5739 }
5740
5741
5742 func (s *state) putArg(n ir.Node, t *types.Type) *ssa.Value {
5743 var a *ssa.Value
5744 if !ssa.CanSSA(t) {
5745 a = s.newValue2(ssa.OpDereference, t, s.addr(n), s.mem())
5746 } else {
5747 a = s.expr(n)
5748 }
5749 return a
5750 }
5751
5752
5753
5754
5755 func (s *state) slice(v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value) {
5756 t := v.Type
5757 var ptr, len, cap *ssa.Value
5758 switch {
5759 case t.IsSlice():
5760 ptr = s.newValue1(ssa.OpSlicePtr, types.NewPtr(t.Elem()), v)
5761 len = s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], v)
5762 cap = s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], v)
5763 case t.IsString():
5764 ptr = s.newValue1(ssa.OpStringPtr, types.NewPtr(types.Types[types.TUINT8]), v)
5765 len = s.newValue1(ssa.OpStringLen, types.Types[types.TINT], v)
5766 cap = len
5767 case t.IsPtr():
5768 if !t.Elem().IsArray() {
5769 s.Fatalf("bad ptr to array in slice %v\n", t)
5770 }
5771 nv := s.nilCheck(v)
5772 ptr = s.newValue1(ssa.OpCopy, types.NewPtr(t.Elem().Elem()), nv)
5773 len = s.constInt(types.Types[types.TINT], t.Elem().NumElem())
5774 cap = len
5775 default:
5776 s.Fatalf("bad type in slice %v\n", t)
5777 }
5778
5779
5780 if i == nil {
5781 i = s.constInt(types.Types[types.TINT], 0)
5782 }
5783 if j == nil {
5784 j = len
5785 }
5786 three := true
5787 if k == nil {
5788 three = false
5789 k = cap
5790 }
5791
5792
5793
5794
5795 if three {
5796 if k != cap {
5797 kind := ssa.BoundsSlice3Alen
5798 if t.IsSlice() {
5799 kind = ssa.BoundsSlice3Acap
5800 }
5801 k = s.boundsCheck(k, cap, kind, bounded)
5802 }
5803 if j != k {
5804 j = s.boundsCheck(j, k, ssa.BoundsSlice3B, bounded)
5805 }
5806 i = s.boundsCheck(i, j, ssa.BoundsSlice3C, bounded)
5807 } else {
5808 if j != k {
5809 kind := ssa.BoundsSliceAlen
5810 if t.IsSlice() {
5811 kind = ssa.BoundsSliceAcap
5812 }
5813 j = s.boundsCheck(j, k, kind, bounded)
5814 }
5815 i = s.boundsCheck(i, j, ssa.BoundsSliceB, bounded)
5816 }
5817
5818
5819 subOp := s.ssaOp(ir.OSUB, types.Types[types.TINT])
5820 mulOp := s.ssaOp(ir.OMUL, types.Types[types.TINT])
5821 andOp := s.ssaOp(ir.OAND, types.Types[types.TINT])
5822
5823
5824
5825
5826
5827 rlen := s.newValue2(subOp, types.Types[types.TINT], j, i)
5828 rcap := rlen
5829 if j != k && !t.IsString() {
5830 rcap = s.newValue2(subOp, types.Types[types.TINT], k, i)
5831 }
5832
5833 if (i.Op == ssa.OpConst64 || i.Op == ssa.OpConst32) && i.AuxInt == 0 {
5834
5835 return ptr, rlen, rcap
5836 }
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852 stride := s.constInt(types.Types[types.TINT], ptr.Type.Elem().Size())
5853
5854
5855 delta := s.newValue2(mulOp, types.Types[types.TINT], i, stride)
5856
5857
5858
5859 mask := s.newValue1(ssa.OpSlicemask, types.Types[types.TINT], rcap)
5860 delta = s.newValue2(andOp, types.Types[types.TINT], delta, mask)
5861
5862
5863 rptr := s.newValue2(ssa.OpAddPtr, ptr.Type, ptr, delta)
5864
5865 return rptr, rlen, rcap
5866 }
5867
5868 type u642fcvtTab struct {
5869 leq, cvt2F, and, rsh, or, add ssa.Op
5870 one func(*state, *types.Type, int64) *ssa.Value
5871 }
5872
5873 var u64_f64 = u642fcvtTab{
5874 leq: ssa.OpLeq64,
5875 cvt2F: ssa.OpCvt64to64F,
5876 and: ssa.OpAnd64,
5877 rsh: ssa.OpRsh64Ux64,
5878 or: ssa.OpOr64,
5879 add: ssa.OpAdd64F,
5880 one: (*state).constInt64,
5881 }
5882
5883 var u64_f32 = u642fcvtTab{
5884 leq: ssa.OpLeq64,
5885 cvt2F: ssa.OpCvt64to32F,
5886 and: ssa.OpAnd64,
5887 rsh: ssa.OpRsh64Ux64,
5888 or: ssa.OpOr64,
5889 add: ssa.OpAdd32F,
5890 one: (*state).constInt64,
5891 }
5892
5893 func (s *state) uint64Tofloat64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5894 return s.uint64Tofloat(&u64_f64, n, x, ft, tt)
5895 }
5896
5897 func (s *state) uint64Tofloat32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5898 return s.uint64Tofloat(&u64_f32, n, x, ft, tt)
5899 }
5900
5901 func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927 cmp := s.newValue2(cvttab.leq, types.Types[types.TBOOL], s.zeroVal(ft), x)
5928
5929 b := s.endBlock()
5930 b.Kind = ssa.BlockIf
5931 b.SetControl(cmp)
5932 b.Likely = ssa.BranchLikely
5933
5934 bThen := s.f.NewBlock(ssa.BlockPlain)
5935 bElse := s.f.NewBlock(ssa.BlockPlain)
5936 bAfter := s.f.NewBlock(ssa.BlockPlain)
5937
5938 b.AddEdgeTo(bThen)
5939 s.startBlock(bThen)
5940 a0 := s.newValue1(cvttab.cvt2F, tt, x)
5941 s.vars[n] = a0
5942 s.endBlock()
5943 bThen.AddEdgeTo(bAfter)
5944
5945 b.AddEdgeTo(bElse)
5946 s.startBlock(bElse)
5947 one := cvttab.one(s, ft, 1)
5948 y := s.newValue2(cvttab.and, ft, x, one)
5949 z := s.newValue2(cvttab.rsh, ft, x, one)
5950 z = s.newValue2(cvttab.or, ft, z, y)
5951 a := s.newValue1(cvttab.cvt2F, tt, z)
5952 a1 := s.newValue2(cvttab.add, tt, a, a)
5953 s.vars[n] = a1
5954 s.endBlock()
5955 bElse.AddEdgeTo(bAfter)
5956
5957 s.startBlock(bAfter)
5958 return s.variable(n, n.Type())
5959 }
5960
5961 type u322fcvtTab struct {
5962 cvtI2F, cvtF2F ssa.Op
5963 }
5964
5965 var u32_f64 = u322fcvtTab{
5966 cvtI2F: ssa.OpCvt32to64F,
5967 cvtF2F: ssa.OpCopy,
5968 }
5969
5970 var u32_f32 = u322fcvtTab{
5971 cvtI2F: ssa.OpCvt32to32F,
5972 cvtF2F: ssa.OpCvt64Fto32F,
5973 }
5974
5975 func (s *state) uint32Tofloat64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5976 return s.uint32Tofloat(&u32_f64, n, x, ft, tt)
5977 }
5978
5979 func (s *state) uint32Tofloat32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5980 return s.uint32Tofloat(&u32_f32, n, x, ft, tt)
5981 }
5982
5983 func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5984
5985
5986
5987
5988
5989 cmp := s.newValue2(ssa.OpLeq32, types.Types[types.TBOOL], s.zeroVal(ft), x)
5990 b := s.endBlock()
5991 b.Kind = ssa.BlockIf
5992 b.SetControl(cmp)
5993 b.Likely = ssa.BranchLikely
5994
5995 bThen := s.f.NewBlock(ssa.BlockPlain)
5996 bElse := s.f.NewBlock(ssa.BlockPlain)
5997 bAfter := s.f.NewBlock(ssa.BlockPlain)
5998
5999 b.AddEdgeTo(bThen)
6000 s.startBlock(bThen)
6001 a0 := s.newValue1(cvttab.cvtI2F, tt, x)
6002 s.vars[n] = a0
6003 s.endBlock()
6004 bThen.AddEdgeTo(bAfter)
6005
6006 b.AddEdgeTo(bElse)
6007 s.startBlock(bElse)
6008 a1 := s.newValue1(ssa.OpCvt32to64F, types.Types[types.TFLOAT64], x)
6009 twoToThe32 := s.constFloat64(types.Types[types.TFLOAT64], float64(1<<32))
6010 a2 := s.newValue2(ssa.OpAdd64F, types.Types[types.TFLOAT64], a1, twoToThe32)
6011 a3 := s.newValue1(cvttab.cvtF2F, tt, a2)
6012
6013 s.vars[n] = a3
6014 s.endBlock()
6015 bElse.AddEdgeTo(bAfter)
6016
6017 s.startBlock(bAfter)
6018 return s.variable(n, n.Type())
6019 }
6020
6021
6022 func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
6023 if !n.X.Type().IsMap() && !n.X.Type().IsChan() {
6024 s.Fatalf("node must be a map or a channel")
6025 }
6026 if n.X.Type().IsChan() && n.Op() == ir.OLEN {
6027 s.Fatalf("cannot inline len(chan)")
6028 }
6029 if n.X.Type().IsChan() && n.Op() == ir.OCAP {
6030 s.Fatalf("cannot inline cap(chan)")
6031 }
6032 if n.X.Type().IsMap() && n.Op() == ir.OCAP {
6033 s.Fatalf("cannot inline cap(map)")
6034 }
6035
6036
6037
6038
6039
6040
6041
6042
6043 lenType := n.Type()
6044 nilValue := s.constNil(types.Types[types.TUINTPTR])
6045 cmp := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], x, nilValue)
6046 b := s.endBlock()
6047 b.Kind = ssa.BlockIf
6048 b.SetControl(cmp)
6049 b.Likely = ssa.BranchUnlikely
6050
6051 bThen := s.f.NewBlock(ssa.BlockPlain)
6052 bElse := s.f.NewBlock(ssa.BlockPlain)
6053 bAfter := s.f.NewBlock(ssa.BlockPlain)
6054
6055
6056 b.AddEdgeTo(bThen)
6057 s.startBlock(bThen)
6058 s.vars[n] = s.zeroVal(lenType)
6059 s.endBlock()
6060 bThen.AddEdgeTo(bAfter)
6061
6062 b.AddEdgeTo(bElse)
6063 s.startBlock(bElse)
6064 switch n.Op() {
6065 case ir.OLEN:
6066 if n.X.Type().IsMap() {
6067
6068 loadType := reflectdata.MapType().Field(0).Type
6069 load := s.load(loadType, x)
6070 s.vars[n] = s.conv(nil, load, loadType, lenType)
6071 } else {
6072
6073 s.vars[n] = s.load(lenType, x)
6074 }
6075 case ir.OCAP:
6076
6077 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Size(), x)
6078 s.vars[n] = s.load(lenType, sw)
6079 default:
6080 s.Fatalf("op must be OLEN or OCAP")
6081 }
6082 s.endBlock()
6083 bElse.AddEdgeTo(bAfter)
6084
6085 s.startBlock(bAfter)
6086 return s.variable(n, lenType)
6087 }
6088
6089 type f2uCvtTab struct {
6090 ltf, cvt2U, subf, or ssa.Op
6091 floatValue func(*state, *types.Type, float64) *ssa.Value
6092 intValue func(*state, *types.Type, int64) *ssa.Value
6093 cutoff uint64
6094 }
6095
6096 var f32_u64 = f2uCvtTab{
6097 ltf: ssa.OpLess32F,
6098 cvt2U: ssa.OpCvt32Fto64,
6099 subf: ssa.OpSub32F,
6100 or: ssa.OpOr64,
6101 floatValue: (*state).constFloat32,
6102 intValue: (*state).constInt64,
6103 cutoff: 1 << 63,
6104 }
6105
6106 var f64_u64 = f2uCvtTab{
6107 ltf: ssa.OpLess64F,
6108 cvt2U: ssa.OpCvt64Fto64,
6109 subf: ssa.OpSub64F,
6110 or: ssa.OpOr64,
6111 floatValue: (*state).constFloat64,
6112 intValue: (*state).constInt64,
6113 cutoff: 1 << 63,
6114 }
6115
6116 var f32_u32 = f2uCvtTab{
6117 ltf: ssa.OpLess32F,
6118 cvt2U: ssa.OpCvt32Fto32,
6119 subf: ssa.OpSub32F,
6120 or: ssa.OpOr32,
6121 floatValue: (*state).constFloat32,
6122 intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
6123 cutoff: 1 << 31,
6124 }
6125
6126 var f64_u32 = f2uCvtTab{
6127 ltf: ssa.OpLess64F,
6128 cvt2U: ssa.OpCvt64Fto32,
6129 subf: ssa.OpSub64F,
6130 or: ssa.OpOr32,
6131 floatValue: (*state).constFloat64,
6132 intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
6133 cutoff: 1 << 31,
6134 }
6135
6136 func (s *state) float32ToUint64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6137 return s.floatToUint(&f32_u64, n, x, ft, tt)
6138 }
6139 func (s *state) float64ToUint64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6140 return s.floatToUint(&f64_u64, n, x, ft, tt)
6141 }
6142
6143 func (s *state) float32ToUint32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6144 return s.floatToUint(&f32_u32, n, x, ft, tt)
6145 }
6146
6147 func (s *state) float64ToUint32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6148 return s.floatToUint(&f64_u32, n, x, ft, tt)
6149 }
6150
6151 func (s *state) floatToUint(cvttab *f2uCvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165 cutoff := cvttab.floatValue(s, ft, float64(cvttab.cutoff))
6166 cmp := s.newValueOrSfCall2(cvttab.ltf, types.Types[types.TBOOL], x, cutoff)
6167 b := s.endBlock()
6168 b.Kind = ssa.BlockIf
6169 b.SetControl(cmp)
6170 b.Likely = ssa.BranchLikely
6171
6172 var bThen, bZero *ssa.Block
6173
6174 newConversion := base.ConvertHash.MatchPosWithInfo(n.Pos(), "U", nil)
6175 if newConversion {
6176 bZero = s.f.NewBlock(ssa.BlockPlain)
6177 bThen = s.f.NewBlock(ssa.BlockIf)
6178 } else {
6179 bThen = s.f.NewBlock(ssa.BlockPlain)
6180 }
6181
6182 bElse := s.f.NewBlock(ssa.BlockPlain)
6183 bAfter := s.f.NewBlock(ssa.BlockPlain)
6184
6185 b.AddEdgeTo(bThen)
6186 s.startBlock(bThen)
6187 a0 := s.newValueOrSfCall1(cvttab.cvt2U, tt, x)
6188 s.vars[n] = a0
6189
6190 if newConversion {
6191 cmpz := s.newValueOrSfCall2(cvttab.ltf, types.Types[types.TBOOL], x, cvttab.floatValue(s, ft, 0.0))
6192 s.endBlock()
6193 bThen.SetControl(cmpz)
6194 bThen.AddEdgeTo(bZero)
6195 bThen.Likely = ssa.BranchUnlikely
6196 bThen.AddEdgeTo(bAfter)
6197
6198 s.startBlock(bZero)
6199 s.vars[n] = cvttab.intValue(s, tt, 0)
6200 s.endBlock()
6201 bZero.AddEdgeTo(bAfter)
6202 } else {
6203 s.endBlock()
6204 bThen.AddEdgeTo(bAfter)
6205 }
6206
6207 b.AddEdgeTo(bElse)
6208 s.startBlock(bElse)
6209 y := s.newValueOrSfCall2(cvttab.subf, ft, x, cutoff)
6210 y = s.newValueOrSfCall1(cvttab.cvt2U, tt, y)
6211 z := cvttab.intValue(s, tt, int64(-cvttab.cutoff))
6212 a1 := s.newValue2(cvttab.or, tt, y, z)
6213 s.vars[n] = a1
6214 s.endBlock()
6215 bElse.AddEdgeTo(bAfter)
6216
6217 s.startBlock(bAfter)
6218 return s.variable(n, n.Type())
6219 }
6220
6221
6222
6223
6224 func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
6225 iface := s.expr(n.X)
6226 target := s.reflectType(n.Type())
6227 var targetItab *ssa.Value
6228 if n.ITab != nil {
6229 targetItab = s.expr(n.ITab)
6230 }
6231
6232 if n.UseNilPanic {
6233 if commaok {
6234 base.Fatalf("unexpected *ir.TypeAssertExpr with UseNilPanic == true && commaok == true")
6235 }
6236 if n.Type().IsInterface() {
6237
6238
6239 base.Fatalf("unexpected *ir.TypeAssertExpr with UseNilPanic == true && Type().IsInterface() == true")
6240 }
6241 typs := s.f.Config.Types
6242 iface = s.newValue2(
6243 ssa.OpIMake,
6244 iface.Type,
6245 s.nilCheck(s.newValue1(ssa.OpITab, typs.BytePtr, iface)),
6246 s.newValue1(ssa.OpIData, typs.BytePtr, iface),
6247 )
6248 }
6249
6250 return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, nil, target, targetItab, commaok, n.Descriptor)
6251 }
6252
6253 func (s *state) dynamicDottype(n *ir.DynamicTypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
6254 iface := s.expr(n.X)
6255 var source, target, targetItab *ssa.Value
6256 if n.SrcRType != nil {
6257 source = s.expr(n.SrcRType)
6258 }
6259 if !n.X.Type().IsEmptyInterface() && !n.Type().IsInterface() {
6260 byteptr := s.f.Config.Types.BytePtr
6261 targetItab = s.expr(n.ITab)
6262
6263
6264 target = s.load(byteptr, s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), targetItab))
6265 } else {
6266 target = s.expr(n.RType)
6267 }
6268 return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, source, target, targetItab, commaok, nil)
6269 }
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279 func (s *state) dottype1(pos src.XPos, src, dst *types.Type, iface, source, target, targetItab *ssa.Value, commaok bool, descriptor *obj.LSym) (res, resok *ssa.Value) {
6280 typs := s.f.Config.Types
6281 byteptr := typs.BytePtr
6282 if dst.IsInterface() {
6283 if dst.IsEmptyInterface() {
6284
6285
6286 if base.Debug.TypeAssert > 0 {
6287 base.WarnfAt(pos, "type assertion inlined")
6288 }
6289
6290
6291 itab := s.newValue1(ssa.OpITab, byteptr, iface)
6292
6293 cond := s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6294
6295 if src.IsEmptyInterface() && commaok {
6296
6297 return iface, cond
6298 }
6299
6300
6301 b := s.endBlock()
6302 b.Kind = ssa.BlockIf
6303 b.SetControl(cond)
6304 b.Likely = ssa.BranchLikely
6305 bOk := s.f.NewBlock(ssa.BlockPlain)
6306 bFail := s.f.NewBlock(ssa.BlockPlain)
6307 b.AddEdgeTo(bOk)
6308 b.AddEdgeTo(bFail)
6309
6310 if !commaok {
6311
6312 s.startBlock(bFail)
6313 s.rtcall(ir.Syms.Panicnildottype, false, nil, target)
6314
6315
6316 s.startBlock(bOk)
6317 if src.IsEmptyInterface() {
6318 res = iface
6319 return
6320 }
6321
6322 off := s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab)
6323 typ := s.load(byteptr, off)
6324 idata := s.newValue1(ssa.OpIData, byteptr, iface)
6325 res = s.newValue2(ssa.OpIMake, dst, typ, idata)
6326 return
6327 }
6328
6329 s.startBlock(bOk)
6330
6331
6332 off := s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab)
6333 s.vars[typVar] = s.load(byteptr, off)
6334 s.endBlock()
6335
6336
6337 s.startBlock(bFail)
6338 s.vars[typVar] = itab
6339 s.endBlock()
6340
6341
6342 bEnd := s.f.NewBlock(ssa.BlockPlain)
6343 bOk.AddEdgeTo(bEnd)
6344 bFail.AddEdgeTo(bEnd)
6345 s.startBlock(bEnd)
6346 idata := s.newValue1(ssa.OpIData, byteptr, iface)
6347 res = s.newValue2(ssa.OpIMake, dst, s.variable(typVar, byteptr), idata)
6348 resok = cond
6349 delete(s.vars, typVar)
6350 return
6351 }
6352
6353 if base.Debug.TypeAssert > 0 {
6354 base.WarnfAt(pos, "type assertion not inlined")
6355 }
6356
6357 itab := s.newValue1(ssa.OpITab, byteptr, iface)
6358 data := s.newValue1(ssa.OpIData, types.Types[types.TUNSAFEPTR], iface)
6359
6360
6361 bNil := s.f.NewBlock(ssa.BlockPlain)
6362 bNonNil := s.f.NewBlock(ssa.BlockPlain)
6363 bMerge := s.f.NewBlock(ssa.BlockPlain)
6364 cond := s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6365 b := s.endBlock()
6366 b.Kind = ssa.BlockIf
6367 b.SetControl(cond)
6368 b.Likely = ssa.BranchLikely
6369 b.AddEdgeTo(bNonNil)
6370 b.AddEdgeTo(bNil)
6371
6372 s.startBlock(bNil)
6373 if commaok {
6374 s.vars[typVar] = itab
6375 b := s.endBlock()
6376 b.AddEdgeTo(bMerge)
6377 } else {
6378
6379 s.rtcall(ir.Syms.Panicnildottype, false, nil, target)
6380 }
6381
6382
6383 s.startBlock(bNonNil)
6384 typ := itab
6385 if !src.IsEmptyInterface() {
6386 typ = s.load(byteptr, s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab))
6387 }
6388
6389
6390 var d *ssa.Value
6391 if descriptor != nil {
6392 d = s.newValue1A(ssa.OpAddr, byteptr, descriptor, s.sb)
6393 if base.Flag.N == 0 && rtabi.UseInterfaceSwitchCache(Arch.LinkArch.Family) {
6394
6395
6396 if intrinsics.lookup(Arch.LinkArch.Arch, "internal/runtime/atomic", "Loadp") == nil {
6397 s.Fatalf("atomic load not available")
6398 }
6399
6400 var mul, and, add, zext ssa.Op
6401 if s.config.PtrSize == 4 {
6402 mul = ssa.OpMul32
6403 and = ssa.OpAnd32
6404 add = ssa.OpAdd32
6405 zext = ssa.OpCopy
6406 } else {
6407 mul = ssa.OpMul64
6408 and = ssa.OpAnd64
6409 add = ssa.OpAdd64
6410 zext = ssa.OpZeroExt32to64
6411 }
6412
6413 loopHead := s.f.NewBlock(ssa.BlockPlain)
6414 loopBody := s.f.NewBlock(ssa.BlockPlain)
6415 cacheHit := s.f.NewBlock(ssa.BlockPlain)
6416 cacheMiss := s.f.NewBlock(ssa.BlockPlain)
6417
6418
6419
6420 atomicLoad := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(typs.BytePtr, types.TypeMem), d, s.mem())
6421 cache := s.newValue1(ssa.OpSelect0, typs.BytePtr, atomicLoad)
6422 s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, atomicLoad)
6423
6424
6425 var hash *ssa.Value
6426 if src.IsEmptyInterface() {
6427 hash = s.newValue2(ssa.OpLoad, typs.UInt32, s.newValue1I(ssa.OpOffPtr, typs.UInt32Ptr, rttype.Type.OffsetOf("Hash"), typ), s.mem())
6428 } else {
6429 hash = s.newValue2(ssa.OpLoad, typs.UInt32, s.newValue1I(ssa.OpOffPtr, typs.UInt32Ptr, rttype.ITab.OffsetOf("Hash"), itab), s.mem())
6430 }
6431 hash = s.newValue1(zext, typs.Uintptr, hash)
6432 s.vars[hashVar] = hash
6433
6434 mask := s.newValue2(ssa.OpLoad, typs.Uintptr, cache, s.mem())
6435
6436 b := s.endBlock()
6437 b.AddEdgeTo(loopHead)
6438
6439
6440
6441 s.startBlock(loopHead)
6442 idx := s.newValue2(and, typs.Uintptr, s.variable(hashVar, typs.Uintptr), mask)
6443 idx = s.newValue2(mul, typs.Uintptr, idx, s.uintptrConstant(uint64(2*s.config.PtrSize)))
6444 idx = s.newValue2(add, typs.Uintptr, idx, s.uintptrConstant(uint64(s.config.PtrSize)))
6445 e := s.newValue2(ssa.OpAddPtr, typs.UintptrPtr, cache, idx)
6446
6447 s.vars[hashVar] = s.newValue2(add, typs.Uintptr, s.variable(hashVar, typs.Uintptr), s.uintptrConstant(1))
6448
6449
6450
6451 eTyp := s.newValue2(ssa.OpLoad, typs.Uintptr, e, s.mem())
6452 cmp1 := s.newValue2(ssa.OpEqPtr, typs.Bool, typ, eTyp)
6453 b = s.endBlock()
6454 b.Kind = ssa.BlockIf
6455 b.SetControl(cmp1)
6456 b.AddEdgeTo(cacheHit)
6457 b.AddEdgeTo(loopBody)
6458
6459
6460
6461 s.startBlock(loopBody)
6462 cmp2 := s.newValue2(ssa.OpEqPtr, typs.Bool, eTyp, s.constNil(typs.BytePtr))
6463 b = s.endBlock()
6464 b.Kind = ssa.BlockIf
6465 b.SetControl(cmp2)
6466 b.AddEdgeTo(cacheMiss)
6467 b.AddEdgeTo(loopHead)
6468
6469
6470
6471 s.startBlock(cacheHit)
6472 eItab := s.newValue2(ssa.OpLoad, typs.BytePtr, s.newValue1I(ssa.OpOffPtr, typs.BytePtrPtr, s.config.PtrSize, e), s.mem())
6473 s.vars[typVar] = eItab
6474 b = s.endBlock()
6475 b.AddEdgeTo(bMerge)
6476
6477
6478 s.startBlock(cacheMiss)
6479 }
6480 }
6481
6482
6483 if descriptor != nil {
6484 itab = s.rtcall(ir.Syms.TypeAssert, true, []*types.Type{byteptr}, d, typ)[0]
6485 } else {
6486 var fn *obj.LSym
6487 if commaok {
6488 fn = ir.Syms.AssertE2I2
6489 } else {
6490 fn = ir.Syms.AssertE2I
6491 }
6492 itab = s.rtcall(fn, true, []*types.Type{byteptr}, target, typ)[0]
6493 }
6494 s.vars[typVar] = itab
6495 b = s.endBlock()
6496 b.AddEdgeTo(bMerge)
6497
6498
6499 s.startBlock(bMerge)
6500 itab = s.variable(typVar, byteptr)
6501 var ok *ssa.Value
6502 if commaok {
6503 ok = s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6504 }
6505 return s.newValue2(ssa.OpIMake, dst, itab, data), ok
6506 }
6507
6508 if base.Debug.TypeAssert > 0 {
6509 base.WarnfAt(pos, "type assertion inlined")
6510 }
6511
6512
6513 direct := types.IsDirectIface(dst)
6514 itab := s.newValue1(ssa.OpITab, byteptr, iface)
6515 if base.Debug.TypeAssert > 0 {
6516 base.WarnfAt(pos, "type assertion inlined")
6517 }
6518 var wantedFirstWord *ssa.Value
6519 if src.IsEmptyInterface() {
6520
6521 wantedFirstWord = target
6522 } else {
6523
6524 wantedFirstWord = targetItab
6525 }
6526
6527 var tmp ir.Node
6528 var addr *ssa.Value
6529 if commaok && !ssa.CanSSA(dst) {
6530
6531
6532 tmp, addr = s.temp(pos, dst)
6533 }
6534
6535 cond := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], itab, wantedFirstWord)
6536 b := s.endBlock()
6537 b.Kind = ssa.BlockIf
6538 b.SetControl(cond)
6539 b.Likely = ssa.BranchLikely
6540
6541 bOk := s.f.NewBlock(ssa.BlockPlain)
6542 bFail := s.f.NewBlock(ssa.BlockPlain)
6543 b.AddEdgeTo(bOk)
6544 b.AddEdgeTo(bFail)
6545
6546 if !commaok {
6547
6548 s.startBlock(bFail)
6549 taddr := source
6550 if taddr == nil {
6551 taddr = s.reflectType(src)
6552 }
6553 if src.IsEmptyInterface() {
6554 s.rtcall(ir.Syms.PanicdottypeE, false, nil, itab, target, taddr)
6555 } else {
6556 s.rtcall(ir.Syms.PanicdottypeI, false, nil, itab, target, taddr)
6557 }
6558
6559
6560 s.startBlock(bOk)
6561 if direct {
6562 return s.newValue1(ssa.OpIData, dst, iface), nil
6563 }
6564 p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
6565 return s.load(dst, p), nil
6566 }
6567
6568
6569
6570 bEnd := s.f.NewBlock(ssa.BlockPlain)
6571
6572
6573 valVar := ssaMarker("val")
6574
6575
6576 s.startBlock(bOk)
6577 if tmp == nil {
6578 if direct {
6579 s.vars[valVar] = s.newValue1(ssa.OpIData, dst, iface)
6580 } else {
6581 p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
6582 s.vars[valVar] = s.load(dst, p)
6583 }
6584 } else {
6585 p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
6586 s.move(dst, addr, p)
6587 }
6588 s.vars[okVar] = s.constBool(true)
6589 s.endBlock()
6590 bOk.AddEdgeTo(bEnd)
6591
6592
6593 s.startBlock(bFail)
6594 if tmp == nil {
6595 s.vars[valVar] = s.zeroVal(dst)
6596 } else {
6597 s.zero(dst, addr)
6598 }
6599 s.vars[okVar] = s.constBool(false)
6600 s.endBlock()
6601 bFail.AddEdgeTo(bEnd)
6602
6603
6604 s.startBlock(bEnd)
6605 if tmp == nil {
6606 res = s.variable(valVar, dst)
6607 delete(s.vars, valVar)
6608 } else {
6609 res = s.load(dst, addr)
6610 }
6611 resok = s.variable(okVar, types.Types[types.TBOOL])
6612 delete(s.vars, okVar)
6613 return res, resok
6614 }
6615
6616
6617 func (s *state) temp(pos src.XPos, t *types.Type) (*ir.Name, *ssa.Value) {
6618 tmp := typecheck.TempAt(pos, s.curfn, t)
6619 if t.HasPointers() || (ssa.IsMergeCandidate(tmp) && t != deferstruct()) {
6620 s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp, s.mem())
6621 }
6622 addr := s.addr(tmp)
6623 return tmp, addr
6624 }
6625
6626
6627 func (s *state) variable(n ir.Node, t *types.Type) *ssa.Value {
6628 v := s.vars[n]
6629 if v != nil {
6630 return v
6631 }
6632 v = s.fwdVars[n]
6633 if v != nil {
6634 return v
6635 }
6636
6637 if s.curBlock == s.f.Entry {
6638
6639 s.f.Fatalf("value %v (%v) incorrectly live at entry", n, v)
6640 }
6641
6642
6643 v = s.newValue0A(ssa.OpFwdRef, t, fwdRefAux{N: n})
6644 s.fwdVars[n] = v
6645 if n.Op() == ir.ONAME {
6646 s.addNamedValue(n.(*ir.Name), v)
6647 }
6648 return v
6649 }
6650
6651 func (s *state) mem() *ssa.Value {
6652 return s.variable(memVar, types.TypeMem)
6653 }
6654
6655 func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) {
6656 if n.Class == ir.Pxxx {
6657
6658 return
6659 }
6660 if ir.IsAutoTmp(n) {
6661
6662 return
6663 }
6664 if n.Class == ir.PPARAMOUT {
6665
6666
6667 return
6668 }
6669 loc := ssa.LocalSlot{N: n, Type: n.Type(), Off: 0}
6670 values, ok := s.f.NamedValues[loc]
6671 if !ok {
6672 s.f.Names = append(s.f.Names, &loc)
6673 s.f.CanonicalLocalSlots[loc] = &loc
6674 }
6675 s.f.NamedValues[loc] = append(values, v)
6676 }
6677
6678
6679 type Branch struct {
6680 P *obj.Prog
6681 B *ssa.Block
6682 }
6683
6684
6685 type State struct {
6686 ABI obj.ABI
6687
6688 pp *objw.Progs
6689
6690
6691
6692 Branches []Branch
6693
6694
6695 JumpTables []*ssa.Block
6696
6697
6698 bstart []*obj.Prog
6699
6700 maxarg int64
6701
6702
6703
6704 livenessMap liveness.Map
6705
6706
6707
6708 partLiveArgs map[*ir.Name]bool
6709
6710
6711
6712
6713 lineRunStart *obj.Prog
6714
6715
6716 OnWasmStackSkipped int
6717 }
6718
6719 func (s *State) FuncInfo() *obj.FuncInfo {
6720 return s.pp.CurFunc.LSym.Func()
6721 }
6722
6723
6724 func (s *State) Prog(as obj.As) *obj.Prog {
6725 p := s.pp.Prog(as)
6726 if objw.LosesStmtMark(as) {
6727 return p
6728 }
6729
6730
6731 if s.lineRunStart == nil || s.lineRunStart.Pos.Line() != p.Pos.Line() {
6732 s.lineRunStart = p
6733 } else if p.Pos.IsStmt() == src.PosIsStmt {
6734 s.lineRunStart.Pos = s.lineRunStart.Pos.WithIsStmt()
6735 p.Pos = p.Pos.WithNotStmt()
6736 }
6737 return p
6738 }
6739
6740
6741 func (s *State) Pc() *obj.Prog {
6742 return s.pp.Next
6743 }
6744
6745
6746 func (s *State) SetPos(pos src.XPos) {
6747 s.pp.Pos = pos
6748 }
6749
6750
6751
6752
6753 func (s *State) Br(op obj.As, target *ssa.Block) *obj.Prog {
6754 p := s.Prog(op)
6755 p.To.Type = obj.TYPE_BRANCH
6756 s.Branches = append(s.Branches, Branch{P: p, B: target})
6757 return p
6758 }
6759
6760
6761
6762
6763
6764
6765 func (s *State) DebugFriendlySetPosFrom(v *ssa.Value) {
6766 switch v.Op {
6767 case ssa.OpPhi, ssa.OpCopy, ssa.OpLoadReg, ssa.OpStoreReg:
6768
6769 s.SetPos(v.Pos.WithNotStmt())
6770 default:
6771 p := v.Pos
6772 if p != src.NoXPos {
6773
6774
6775
6776
6777 if p.IsStmt() != src.PosIsStmt {
6778 if s.pp.Pos.IsStmt() == src.PosIsStmt && s.pp.Pos.SameFileAndLine(p) {
6779
6780
6781
6782
6783
6784
6785
6786
6787
6788
6789
6790
6791
6792 return
6793 }
6794 p = p.WithNotStmt()
6795
6796 }
6797 s.SetPos(p)
6798 } else {
6799 s.SetPos(s.pp.Pos.WithNotStmt())
6800 }
6801 }
6802 }
6803
6804
6805 func emitArgInfo(e *ssafn, f *ssa.Func, pp *objw.Progs) {
6806 ft := e.curfn.Type()
6807 if ft.NumRecvs() == 0 && ft.NumParams() == 0 {
6808 return
6809 }
6810
6811 x := EmitArgInfo(e.curfn, f.OwnAux.ABIInfo())
6812 x.Set(obj.AttrContentAddressable, true)
6813 e.curfn.LSym.Func().ArgInfo = x
6814
6815
6816 p := pp.Prog(obj.AFUNCDATA)
6817 p.From.SetConst(rtabi.FUNCDATA_ArgInfo)
6818 p.To.Type = obj.TYPE_MEM
6819 p.To.Name = obj.NAME_EXTERN
6820 p.To.Sym = x
6821 }
6822
6823
6824 func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
6825 x := base.Ctxt.Lookup(fmt.Sprintf("%s.arginfo%d", f.LSym.Name, f.ABI))
6826 x.Align = 1
6827
6828
6829
6830
6831 PtrSize := int64(types.PtrSize)
6832 uintptrTyp := types.Types[types.TUINTPTR]
6833
6834 isAggregate := func(t *types.Type) bool {
6835 return isStructNotSIMD(t) || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice()
6836 }
6837
6838 wOff := 0
6839 n := 0
6840 writebyte := func(o uint8) { wOff = objw.Uint8(x, wOff, o) }
6841
6842
6843 write1 := func(sz, offset int64) {
6844 if offset >= rtabi.TraceArgsSpecial {
6845 writebyte(rtabi.TraceArgsOffsetTooLarge)
6846 } else {
6847 writebyte(uint8(offset))
6848 writebyte(uint8(sz))
6849 }
6850 n++
6851 }
6852
6853
6854
6855 var visitType func(baseOffset int64, t *types.Type, depth int) bool
6856 visitType = func(baseOffset int64, t *types.Type, depth int) bool {
6857 if n >= rtabi.TraceArgsLimit {
6858 writebyte(rtabi.TraceArgsDotdotdot)
6859 return false
6860 }
6861 if !isAggregate(t) {
6862 write1(t.Size(), baseOffset)
6863 return true
6864 }
6865 writebyte(rtabi.TraceArgsStartAgg)
6866 depth++
6867 if depth >= rtabi.TraceArgsMaxDepth {
6868 writebyte(rtabi.TraceArgsDotdotdot)
6869 writebyte(rtabi.TraceArgsEndAgg)
6870 n++
6871 return true
6872 }
6873 switch {
6874 case t.IsInterface(), t.IsString():
6875 _ = visitType(baseOffset, uintptrTyp, depth) &&
6876 visitType(baseOffset+PtrSize, uintptrTyp, depth)
6877 case t.IsSlice():
6878 _ = visitType(baseOffset, uintptrTyp, depth) &&
6879 visitType(baseOffset+PtrSize, uintptrTyp, depth) &&
6880 visitType(baseOffset+PtrSize*2, uintptrTyp, depth)
6881 case t.IsComplex():
6882 _ = visitType(baseOffset, types.FloatForComplex(t), depth) &&
6883 visitType(baseOffset+t.Size()/2, types.FloatForComplex(t), depth)
6884 case t.IsArray():
6885 if t.NumElem() == 0 {
6886 n++
6887 break
6888 }
6889 for i := int64(0); i < t.NumElem(); i++ {
6890 if !visitType(baseOffset, t.Elem(), depth) {
6891 break
6892 }
6893 baseOffset += t.Elem().Size()
6894 }
6895 case isStructNotSIMD(t):
6896 if t.NumFields() == 0 {
6897 n++
6898 break
6899 }
6900 for _, field := range t.Fields() {
6901 if !visitType(baseOffset+field.Offset, field.Type, depth) {
6902 break
6903 }
6904 }
6905 }
6906 writebyte(rtabi.TraceArgsEndAgg)
6907 return true
6908 }
6909
6910 start := 0
6911 if strings.Contains(f.LSym.Name, "[") {
6912
6913 start = 1
6914 }
6915
6916 for _, a := range abiInfo.InParams()[start:] {
6917 if !visitType(a.FrameOffset(abiInfo), a.Type, 0) {
6918 break
6919 }
6920 }
6921 writebyte(rtabi.TraceArgsEndSeq)
6922 if wOff > rtabi.TraceArgsMaxLen {
6923 base.Fatalf("ArgInfo too large")
6924 }
6925
6926 return x
6927 }
6928
6929
6930 func emitWrappedFuncInfo(e *ssafn, pp *objw.Progs) {
6931 if base.Ctxt.Flag_linkshared {
6932
6933
6934 return
6935 }
6936
6937 wfn := e.curfn.WrappedFunc
6938 if wfn == nil {
6939 return
6940 }
6941
6942 wsym := wfn.Linksym()
6943 x := base.Ctxt.LookupInit(fmt.Sprintf("%s.wrapinfo", wsym.Name), func(x *obj.LSym) {
6944 objw.SymPtrOff(x, 0, wsym)
6945 x.Set(obj.AttrContentAddressable, true)
6946 x.Align = 4
6947 })
6948 e.curfn.LSym.Func().WrapInfo = x
6949
6950
6951 p := pp.Prog(obj.AFUNCDATA)
6952 p.From.SetConst(rtabi.FUNCDATA_WrapInfo)
6953 p.To.Type = obj.TYPE_MEM
6954 p.To.Name = obj.NAME_EXTERN
6955 p.To.Sym = x
6956 }
6957
6958
6959 func genssa(f *ssa.Func, pp *objw.Progs) {
6960 var s State
6961 s.ABI = f.OwnAux.Fn.ABI()
6962
6963 e := f.Frontend().(*ssafn)
6964
6965 gatherPrintInfo := f.PrintOrHtmlSSA || ssa.GenssaDump[f.Name]
6966
6967 var lv *liveness.Liveness
6968 s.livenessMap, s.partLiveArgs, lv = liveness.Compute(e.curfn, f, e.stkptrsize, pp, gatherPrintInfo)
6969 emitArgInfo(e, f, pp)
6970 argLiveBlockMap, argLiveValueMap := liveness.ArgLiveness(e.curfn, f, pp)
6971
6972 openDeferInfo := e.curfn.LSym.Func().OpenCodedDeferInfo
6973 if openDeferInfo != nil {
6974
6975
6976 p := pp.Prog(obj.AFUNCDATA)
6977 p.From.SetConst(rtabi.FUNCDATA_OpenCodedDeferInfo)
6978 p.To.Type = obj.TYPE_MEM
6979 p.To.Name = obj.NAME_EXTERN
6980 p.To.Sym = openDeferInfo
6981 }
6982
6983 emitWrappedFuncInfo(e, pp)
6984
6985
6986 s.bstart = make([]*obj.Prog, f.NumBlocks())
6987 s.pp = pp
6988 var progToValue map[*obj.Prog]*ssa.Value
6989 var progToBlock map[*obj.Prog]*ssa.Block
6990 var valueToProgAfter []*obj.Prog
6991 if gatherPrintInfo {
6992 progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
6993 progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
6994 f.Logf("genssa %s\n", f.Name)
6995 progToBlock[s.pp.Next] = f.Blocks[0]
6996 }
6997
6998 if base.Ctxt.Flag_locationlists {
6999 if cap(f.Cache.ValueToProgAfter) < f.NumValues() {
7000 f.Cache.ValueToProgAfter = make([]*obj.Prog, f.NumValues())
7001 }
7002 valueToProgAfter = f.Cache.ValueToProgAfter[:f.NumValues()]
7003 clear(valueToProgAfter)
7004 }
7005
7006
7007
7008 firstPos := src.NoXPos
7009 for _, v := range f.Entry.Values {
7010 if v.Pos.IsStmt() == src.PosIsStmt && v.Op != ssa.OpArg && v.Op != ssa.OpArgIntReg && v.Op != ssa.OpArgFloatReg && v.Op != ssa.OpLoadReg && v.Op != ssa.OpStoreReg {
7011 firstPos = v.Pos
7012 v.Pos = firstPos.WithDefaultStmt()
7013 break
7014 }
7015 }
7016
7017
7018
7019
7020 var inlMarks map[*obj.Prog]int32
7021 var inlMarkList []*obj.Prog
7022
7023
7024
7025 var inlMarksByPos map[src.XPos][]*obj.Prog
7026
7027 var argLiveIdx int = -1
7028
7029
7030
7031
7032
7033 var hotAlign, hotRequire int64
7034
7035 if base.Debug.AlignHot > 0 {
7036 switch base.Ctxt.Arch.Name {
7037
7038
7039
7040
7041
7042 case "amd64", "386":
7043
7044
7045
7046 hotAlign = 64
7047 hotRequire = 31
7048 }
7049 }
7050
7051
7052 for i, b := range f.Blocks {
7053
7054 s.lineRunStart = nil
7055 s.SetPos(s.pp.Pos.WithNotStmt())
7056
7057 if hotAlign > 0 && b.Hotness&ssa.HotPgoInitial == ssa.HotPgoInitial {
7058
7059
7060
7061
7062
7063 p := s.pp.Prog(obj.APCALIGNMAX)
7064 p.From.SetConst(hotAlign)
7065 p.To.SetConst(hotRequire)
7066 }
7067
7068 s.bstart[b.ID] = s.pp.Next
7069
7070 if idx, ok := argLiveBlockMap[b.ID]; ok && idx != argLiveIdx {
7071 argLiveIdx = idx
7072 p := s.pp.Prog(obj.APCDATA)
7073 p.From.SetConst(rtabi.PCDATA_ArgLiveIndex)
7074 p.To.SetConst(int64(idx))
7075 }
7076
7077
7078 Arch.SSAMarkMoves(&s, b)
7079 for _, v := range b.Values {
7080 x := s.pp.Next
7081 s.DebugFriendlySetPosFrom(v)
7082
7083 if v.Op.ResultInArg0() && v.ResultReg() != v.Args[0].Reg() {
7084 v.Fatalf("input[0] and output not in same register %s", v.LongString())
7085 }
7086
7087 switch v.Op {
7088 case ssa.OpInitMem:
7089
7090 case ssa.OpArg:
7091
7092 case ssa.OpSP, ssa.OpSB:
7093
7094 case ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN, ssa.OpMakeResult:
7095
7096 case ssa.OpGetG:
7097
7098
7099 case ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive, ssa.OpWBend:
7100
7101 case ssa.OpPhi:
7102 CheckLoweredPhi(v)
7103 case ssa.OpConvert:
7104
7105 if v.Args[0].Reg() != v.Reg() {
7106 v.Fatalf("OpConvert should be a no-op: %s; %s", v.Args[0].LongString(), v.LongString())
7107 }
7108 case ssa.OpInlMark:
7109 p := Arch.Ginsnop(s.pp)
7110 if inlMarks == nil {
7111 inlMarks = map[*obj.Prog]int32{}
7112 inlMarksByPos = map[src.XPos][]*obj.Prog{}
7113 }
7114 inlMarks[p] = v.AuxInt32()
7115 inlMarkList = append(inlMarkList, p)
7116 pos := v.Pos.AtColumn1()
7117 inlMarksByPos[pos] = append(inlMarksByPos[pos], p)
7118 firstPos = src.NoXPos
7119
7120 default:
7121
7122 if firstPos != src.NoXPos && v.Op != ssa.OpArgIntReg && v.Op != ssa.OpArgFloatReg && v.Op != ssa.OpLoadReg && v.Op != ssa.OpStoreReg {
7123 s.SetPos(firstPos)
7124 firstPos = src.NoXPos
7125 }
7126
7127
7128 s.pp.NextLive = s.livenessMap.Get(v)
7129 s.pp.NextUnsafe = s.livenessMap.GetUnsafe(v)
7130
7131
7132 Arch.SSAGenValue(&s, v)
7133 }
7134
7135 if idx, ok := argLiveValueMap[v.ID]; ok && idx != argLiveIdx {
7136 argLiveIdx = idx
7137 p := s.pp.Prog(obj.APCDATA)
7138 p.From.SetConst(rtabi.PCDATA_ArgLiveIndex)
7139 p.To.SetConst(int64(idx))
7140 }
7141
7142 if base.Ctxt.Flag_locationlists {
7143 valueToProgAfter[v.ID] = s.pp.Next
7144 }
7145
7146 if gatherPrintInfo {
7147 for ; x != s.pp.Next; x = x.Link {
7148 progToValue[x] = v
7149 }
7150 }
7151 }
7152
7153 if s.bstart[b.ID] == s.pp.Next && len(b.Succs) == 1 && b.Succs[0].Block() == b {
7154 p := Arch.Ginsnop(s.pp)
7155 p.Pos = p.Pos.WithIsStmt()
7156 if b.Pos == src.NoXPos {
7157 b.Pos = p.Pos
7158 if b.Pos == src.NoXPos {
7159 b.Pos = s.pp.Text.Pos
7160 }
7161 }
7162 b.Pos = b.Pos.WithBogusLine()
7163 }
7164
7165
7166
7167
7168
7169 s.pp.NextUnsafe = s.livenessMap.GetUnsafeBlock(b)
7170
7171
7172 var next *ssa.Block
7173 if i < len(f.Blocks)-1 && base.Flag.N == 0 {
7174
7175
7176
7177
7178 next = f.Blocks[i+1]
7179 }
7180 x := s.pp.Next
7181 s.SetPos(b.Pos)
7182 Arch.SSAGenBlock(&s, b, next)
7183 if gatherPrintInfo {
7184 for ; x != s.pp.Next; x = x.Link {
7185 progToBlock[x] = b
7186 }
7187 }
7188 }
7189 if f.Blocks[len(f.Blocks)-1].Kind == ssa.BlockExit {
7190
7191
7192
7193
7194 Arch.Ginsnop(s.pp)
7195 }
7196 if openDeferInfo != nil {
7197
7198
7199
7200
7201
7202
7203
7204
7205 s.pp.NextLive = s.livenessMap.DeferReturn
7206 p := s.pp.Prog(obj.ACALL)
7207 p.To.Type = obj.TYPE_MEM
7208 p.To.Name = obj.NAME_EXTERN
7209 p.To.Sym = ir.Syms.Deferreturn
7210
7211
7212
7213
7214
7215 for _, o := range f.OwnAux.ABIInfo().OutParams() {
7216 n := o.Name
7217 rts, offs := o.RegisterTypesAndOffsets()
7218 for i := range o.Registers {
7219 Arch.LoadRegResult(&s, f, rts[i], ssa.ObjRegForAbiReg(o.Registers[i], f.Config), n, offs[i])
7220 }
7221 }
7222
7223 s.pp.Prog(obj.ARET)
7224 }
7225
7226 if inlMarks != nil {
7227 hasCall := false
7228
7229
7230
7231
7232 for p := s.pp.Text; p != nil; p = p.Link {
7233 if p.As == obj.ANOP || p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT ||
7234 p.As == obj.APCALIGN || p.As == obj.APCALIGNMAX || Arch.LinkArch.Family == sys.Wasm {
7235
7236
7237
7238
7239
7240 continue
7241 }
7242 if _, ok := inlMarks[p]; ok {
7243
7244
7245 continue
7246 }
7247 if p.As == obj.ACALL || p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
7248 hasCall = true
7249 }
7250 pos := p.Pos.AtColumn1()
7251 marks := inlMarksByPos[pos]
7252 if len(marks) == 0 {
7253 continue
7254 }
7255 for _, m := range marks {
7256
7257
7258
7259 p.Pos = p.Pos.WithIsStmt()
7260 s.pp.CurFunc.LSym.Func().AddInlMark(p, inlMarks[m])
7261
7262 m.As = obj.ANOP
7263 m.Pos = src.NoXPos
7264 m.From = obj.Addr{}
7265 m.To = obj.Addr{}
7266 }
7267 delete(inlMarksByPos, pos)
7268 }
7269
7270 for _, p := range inlMarkList {
7271 if p.As != obj.ANOP {
7272 s.pp.CurFunc.LSym.Func().AddInlMark(p, inlMarks[p])
7273 }
7274 }
7275
7276 if e.stksize == 0 && !hasCall {
7277
7278
7279
7280
7281
7282
7283 for p := s.pp.Text; p != nil; p = p.Link {
7284 if p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT || p.As == obj.ANOP {
7285 continue
7286 }
7287 if base.Ctxt.PosTable.Pos(p.Pos).Base().InliningIndex() >= 0 {
7288
7289 nop := Arch.Ginsnop(s.pp)
7290 nop.Pos = e.curfn.Pos().WithIsStmt()
7291
7292
7293
7294
7295
7296 for x := s.pp.Text; x != nil; x = x.Link {
7297 if x.Link == nop {
7298 x.Link = nop.Link
7299 break
7300 }
7301 }
7302
7303 for x := s.pp.Text; x != nil; x = x.Link {
7304 if x.Link == p {
7305 nop.Link = p
7306 x.Link = nop
7307 break
7308 }
7309 }
7310 }
7311 break
7312 }
7313 }
7314 }
7315
7316 if base.Ctxt.Flag_locationlists {
7317 var debugInfo *ssa.FuncDebug
7318 debugInfo = e.curfn.DebugInfo.(*ssa.FuncDebug)
7319
7320
7321 debugInfo.EntryID = f.Entry.ID
7322 if e.curfn.ABI == obj.ABIInternal && base.Flag.N != 0 {
7323 ssa.BuildFuncDebugNoOptimized(base.Ctxt, f, base.Debug.LocationLists > 1, StackOffset, debugInfo)
7324 } else {
7325 ssa.BuildFuncDebug(base.Ctxt, f, base.Debug.LocationLists, StackOffset, debugInfo)
7326 }
7327 bstart := s.bstart
7328 idToIdx := make([]int, f.NumBlocks())
7329 for i, b := range f.Blocks {
7330 idToIdx[b.ID] = i
7331 }
7332
7333
7334
7335 debugInfo.GetPC = func(b, v ssa.ID) int64 {
7336 switch v {
7337 case ssa.BlockStart.ID:
7338 if b == f.Entry.ID {
7339 return 0
7340
7341 }
7342 return bstart[b].Pc
7343 case ssa.BlockEnd.ID:
7344 blk := f.Blocks[idToIdx[b]]
7345 nv := len(blk.Values)
7346 return valueToProgAfter[blk.Values[nv-1].ID].Pc
7347 case ssa.FuncEnd.ID:
7348 return e.curfn.LSym.Size
7349 default:
7350 return valueToProgAfter[v].Pc
7351 }
7352 }
7353 }
7354
7355
7356 for _, br := range s.Branches {
7357 br.P.To.SetTarget(s.bstart[br.B.ID])
7358 if br.P.Pos.IsStmt() != src.PosIsStmt {
7359 br.P.Pos = br.P.Pos.WithNotStmt()
7360 } else if v0 := br.B.FirstPossibleStmtValue(); v0 != nil && v0.Pos.Line() == br.P.Pos.Line() && v0.Pos.IsStmt() == src.PosIsStmt {
7361 br.P.Pos = br.P.Pos.WithNotStmt()
7362 }
7363
7364 }
7365
7366
7367 for _, jt := range s.JumpTables {
7368
7369 targets := make([]*obj.Prog, len(jt.Succs))
7370 for i, e := range jt.Succs {
7371 targets[i] = s.bstart[e.Block().ID]
7372 }
7373
7374
7375
7376 fi := s.pp.CurFunc.LSym.Func()
7377 fi.JumpTables = append(fi.JumpTables, obj.JumpTable{Sym: jt.Aux.(*obj.LSym), Targets: targets})
7378 }
7379
7380 if e.log {
7381 filename := ""
7382 for p := s.pp.Text; p != nil; p = p.Link {
7383 if p.Pos.IsKnown() && p.InnermostFilename() != filename {
7384 filename = p.InnermostFilename()
7385 f.Logf("# %s\n", filename)
7386 }
7387
7388 var s string
7389 if v, ok := progToValue[p]; ok {
7390 s = v.String()
7391 } else if b, ok := progToBlock[p]; ok {
7392 s = b.String()
7393 } else {
7394 s = " "
7395 }
7396 f.Logf(" %-6s\t%.5d (%s)\t%s\n", s, p.Pc, p.InnermostLineNumber(), p.InstructionString())
7397 }
7398 }
7399 if f.HTMLWriter != nil {
7400 var buf strings.Builder
7401 buf.WriteString("<code>")
7402 buf.WriteString("<dl class=\"ssa-gen\">")
7403 filename := ""
7404
7405 liveness := lv.Format(nil)
7406 if liveness != "" {
7407 buf.WriteString("<dt class=\"ssa-prog-src\"></dt><dd class=\"ssa-prog\">")
7408 buf.WriteString(html.EscapeString("# " + liveness))
7409 buf.WriteString("</dd>")
7410 }
7411
7412 for p := s.pp.Text; p != nil; p = p.Link {
7413
7414
7415 if p.Pos.IsKnown() && p.InnermostFilename() != filename {
7416 filename = p.InnermostFilename()
7417 buf.WriteString("<dt class=\"ssa-prog-src\"></dt><dd class=\"ssa-prog\">")
7418 buf.WriteString(html.EscapeString("# " + filename))
7419 buf.WriteString("</dd>")
7420 }
7421
7422 buf.WriteString("<dt class=\"ssa-prog-src\">")
7423 if v, ok := progToValue[p]; ok {
7424
7425
7426 if p.As != obj.APCDATA {
7427 if liveness := lv.Format(v); liveness != "" {
7428
7429 buf.WriteString("</dt><dd class=\"ssa-prog\">")
7430 buf.WriteString(html.EscapeString("# " + liveness))
7431 buf.WriteString("</dd>")
7432
7433 buf.WriteString("<dt class=\"ssa-prog-src\">")
7434 }
7435 }
7436
7437 buf.WriteString(v.HTML())
7438 } else if b, ok := progToBlock[p]; ok {
7439 buf.WriteString("<b>" + b.HTML() + "</b>")
7440 }
7441 buf.WriteString("</dt>")
7442 buf.WriteString("<dd class=\"ssa-prog\">")
7443 fmt.Fprintf(&buf, "%.5d <span class=\"l%v line-number\">(%s)</span> %s", p.Pc, p.InnermostLineNumber(), p.InnermostLineNumberHTML(), html.EscapeString(p.InstructionString()))
7444 buf.WriteString("</dd>")
7445 }
7446 buf.WriteString("</dl>")
7447 buf.WriteString("</code>")
7448 f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String())
7449 }
7450 if ssa.GenssaDump[f.Name] {
7451 fi := f.DumpFileForPhase("genssa")
7452 if fi != nil {
7453
7454
7455 inliningDiffers := func(a, b []src.Pos) bool {
7456 if len(a) != len(b) {
7457 return true
7458 }
7459 for i := range a {
7460 if a[i].Filename() != b[i].Filename() {
7461 return true
7462 }
7463 if i != len(a)-1 && a[i].Line() != b[i].Line() {
7464 return true
7465 }
7466 }
7467 return false
7468 }
7469
7470 var allPosOld []src.Pos
7471 var allPos []src.Pos
7472
7473 for p := s.pp.Text; p != nil; p = p.Link {
7474 if p.Pos.IsKnown() {
7475 allPos = allPos[:0]
7476 p.Ctxt.AllPos(p.Pos, func(pos src.Pos) { allPos = append(allPos, pos) })
7477 if inliningDiffers(allPos, allPosOld) {
7478 for _, pos := range allPos {
7479 fmt.Fprintf(fi, "# %s:%d\n", pos.Filename(), pos.Line())
7480 }
7481 allPos, allPosOld = allPosOld, allPos
7482 }
7483 }
7484
7485 var s string
7486 if v, ok := progToValue[p]; ok {
7487 s = v.String()
7488 } else if b, ok := progToBlock[p]; ok {
7489 s = b.String()
7490 } else {
7491 s = " "
7492 }
7493 fmt.Fprintf(fi, " %-6s\t%.5d %s\t%s\n", s, p.Pc, ssa.StmtString(p.Pos), p.InstructionString())
7494 }
7495 fi.Close()
7496 }
7497 }
7498
7499 defframe(&s, e, f)
7500
7501 f.HTMLWriter.Close()
7502 f.HTMLWriter = nil
7503 }
7504
7505 func defframe(s *State, e *ssafn, f *ssa.Func) {
7506 pp := s.pp
7507
7508 s.maxarg = types.RoundUp(s.maxarg, e.stkalign)
7509 frame := s.maxarg + e.stksize
7510 if Arch.PadFrame != nil {
7511 frame = Arch.PadFrame(frame)
7512 }
7513
7514
7515 pp.Text.To.Type = obj.TYPE_TEXTSIZE
7516 pp.Text.To.Val = int32(types.RoundUp(f.OwnAux.ArgWidth(), int64(types.RegSize)))
7517 pp.Text.To.Offset = frame
7518
7519 p := pp.Text
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530 if f.OwnAux.ABIInfo().InRegistersUsed() != 0 && base.Flag.N == 0 {
7531
7532
7533 type nameOff struct {
7534 n *ir.Name
7535 off int64
7536 }
7537 partLiveArgsSpilled := make(map[nameOff]bool)
7538 for _, v := range f.Entry.Values {
7539 if v.Op.IsCall() {
7540 break
7541 }
7542 if v.Op != ssa.OpStoreReg || v.Args[0].Op != ssa.OpArgIntReg {
7543 continue
7544 }
7545 n, off := ssa.AutoVar(v)
7546 if n.Class != ir.PPARAM || n.Addrtaken() || !ssa.CanSSA(n.Type()) || !s.partLiveArgs[n] {
7547 continue
7548 }
7549 partLiveArgsSpilled[nameOff{n, off}] = true
7550 }
7551
7552
7553 for _, a := range f.OwnAux.ABIInfo().InParams() {
7554 n := a.Name
7555 if n == nil || n.Addrtaken() || !ssa.CanSSA(n.Type()) || !s.partLiveArgs[n] || len(a.Registers) <= 1 {
7556 continue
7557 }
7558 rts, offs := a.RegisterTypesAndOffsets()
7559 for i := range a.Registers {
7560 if !rts[i].HasPointers() {
7561 continue
7562 }
7563 if partLiveArgsSpilled[nameOff{n, offs[i]}] {
7564 continue
7565 }
7566 reg := ssa.ObjRegForAbiReg(a.Registers[i], f.Config)
7567 p = Arch.SpillArgReg(pp, p, f, rts[i], reg, n, offs[i])
7568 }
7569 }
7570 }
7571
7572
7573
7574
7575 var lo, hi int64
7576
7577
7578
7579 var state uint32
7580
7581
7582
7583 for _, n := range e.curfn.Dcl {
7584 if !n.Needzero() {
7585 continue
7586 }
7587 if n.Class != ir.PAUTO {
7588 e.Fatalf(n.Pos(), "needzero class %d", n.Class)
7589 }
7590 if n.Type().Size()%int64(types.PtrSize) != 0 || n.FrameOffset()%int64(types.PtrSize) != 0 || n.Type().Size() == 0 {
7591 e.Fatalf(n.Pos(), "var %L has size %d offset %d", n, n.Type().Size(), n.Offset_)
7592 }
7593
7594 if lo != hi && n.FrameOffset()+n.Type().Size() >= lo-int64(2*types.RegSize) {
7595
7596 lo = n.FrameOffset()
7597 continue
7598 }
7599
7600
7601 p = Arch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
7602
7603
7604 lo = n.FrameOffset()
7605 hi = lo + n.Type().Size()
7606 }
7607
7608
7609 Arch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
7610 }
7611
7612
7613 type IndexJump struct {
7614 Jump obj.As
7615 Index int
7616 }
7617
7618 func (s *State) oneJump(b *ssa.Block, jump *IndexJump) {
7619 p := s.Br(jump.Jump, b.Succs[jump.Index].Block())
7620 p.Pos = b.Pos
7621 }
7622
7623
7624
7625 func (s *State) CombJump(b, next *ssa.Block, jumps *[2][2]IndexJump) {
7626 switch next {
7627 case b.Succs[0].Block():
7628 s.oneJump(b, &jumps[0][0])
7629 s.oneJump(b, &jumps[0][1])
7630 case b.Succs[1].Block():
7631 s.oneJump(b, &jumps[1][0])
7632 s.oneJump(b, &jumps[1][1])
7633 default:
7634 var q *obj.Prog
7635 if b.Likely != ssa.BranchUnlikely {
7636 s.oneJump(b, &jumps[1][0])
7637 s.oneJump(b, &jumps[1][1])
7638 q = s.Br(obj.AJMP, b.Succs[1].Block())
7639 } else {
7640 s.oneJump(b, &jumps[0][0])
7641 s.oneJump(b, &jumps[0][1])
7642 q = s.Br(obj.AJMP, b.Succs[0].Block())
7643 }
7644 q.Pos = b.Pos
7645 }
7646 }
7647
7648
7649 func AddAux(a *obj.Addr, v *ssa.Value) {
7650 AddAux2(a, v, v.AuxInt)
7651 }
7652 func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
7653 if a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR {
7654 v.Fatalf("bad AddAux addr %v", a)
7655 }
7656
7657 a.Offset += offset
7658
7659
7660 if v.Aux == nil {
7661 return
7662 }
7663
7664 switch n := v.Aux.(type) {
7665 case *ssa.AuxCall:
7666 a.Name = obj.NAME_EXTERN
7667 a.Sym = n.Fn
7668 case *obj.LSym:
7669 a.Name = obj.NAME_EXTERN
7670 a.Sym = n
7671 case *ir.Name:
7672 if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
7673 a.Name = obj.NAME_PARAM
7674 } else {
7675 a.Name = obj.NAME_AUTO
7676 }
7677 a.Sym = n.Linksym()
7678 a.Offset += n.FrameOffset()
7679 default:
7680 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
7681 }
7682 }
7683
7684
7685
7686 func (s *state) extendIndex(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
7687 size := idx.Type.Size()
7688 if size == s.config.PtrSize {
7689 return idx
7690 }
7691 if size > s.config.PtrSize {
7692
7693
7694 var lo *ssa.Value
7695 if idx.Type.IsSigned() {
7696 lo = s.newValue1(ssa.OpInt64Lo, types.Types[types.TINT], idx)
7697 } else {
7698 lo = s.newValue1(ssa.OpInt64Lo, types.Types[types.TUINT], idx)
7699 }
7700 if bounded || base.Flag.B != 0 {
7701 return lo
7702 }
7703 bNext := s.f.NewBlock(ssa.BlockPlain)
7704 bPanic := s.f.NewBlock(ssa.BlockExit)
7705 hi := s.newValue1(ssa.OpInt64Hi, types.Types[types.TUINT32], idx)
7706 cmp := s.newValue2(ssa.OpEq32, types.Types[types.TBOOL], hi, s.constInt32(types.Types[types.TUINT32], 0))
7707 if !idx.Type.IsSigned() {
7708 switch kind {
7709 case ssa.BoundsIndex:
7710 kind = ssa.BoundsIndexU
7711 case ssa.BoundsSliceAlen:
7712 kind = ssa.BoundsSliceAlenU
7713 case ssa.BoundsSliceAcap:
7714 kind = ssa.BoundsSliceAcapU
7715 case ssa.BoundsSliceB:
7716 kind = ssa.BoundsSliceBU
7717 case ssa.BoundsSlice3Alen:
7718 kind = ssa.BoundsSlice3AlenU
7719 case ssa.BoundsSlice3Acap:
7720 kind = ssa.BoundsSlice3AcapU
7721 case ssa.BoundsSlice3B:
7722 kind = ssa.BoundsSlice3BU
7723 case ssa.BoundsSlice3C:
7724 kind = ssa.BoundsSlice3CU
7725 }
7726 }
7727 b := s.endBlock()
7728 b.Kind = ssa.BlockIf
7729 b.SetControl(cmp)
7730 b.Likely = ssa.BranchLikely
7731 b.AddEdgeTo(bNext)
7732 b.AddEdgeTo(bPanic)
7733
7734 s.startBlock(bPanic)
7735 mem := s.newValue4I(ssa.OpPanicExtend, types.TypeMem, int64(kind), hi, lo, len, s.mem())
7736 s.endBlock().SetControl(mem)
7737 s.startBlock(bNext)
7738
7739 return lo
7740 }
7741
7742
7743 var op ssa.Op
7744 if idx.Type.IsSigned() {
7745 switch 10*size + s.config.PtrSize {
7746 case 14:
7747 op = ssa.OpSignExt8to32
7748 case 18:
7749 op = ssa.OpSignExt8to64
7750 case 24:
7751 op = ssa.OpSignExt16to32
7752 case 28:
7753 op = ssa.OpSignExt16to64
7754 case 48:
7755 op = ssa.OpSignExt32to64
7756 default:
7757 s.Fatalf("bad signed index extension %s", idx.Type)
7758 }
7759 } else {
7760 switch 10*size + s.config.PtrSize {
7761 case 14:
7762 op = ssa.OpZeroExt8to32
7763 case 18:
7764 op = ssa.OpZeroExt8to64
7765 case 24:
7766 op = ssa.OpZeroExt16to32
7767 case 28:
7768 op = ssa.OpZeroExt16to64
7769 case 48:
7770 op = ssa.OpZeroExt32to64
7771 default:
7772 s.Fatalf("bad unsigned index extension %s", idx.Type)
7773 }
7774 }
7775 return s.newValue1(op, types.Types[types.TINT], idx)
7776 }
7777
7778
7779
7780 func CheckLoweredPhi(v *ssa.Value) {
7781 if v.Op != ssa.OpPhi {
7782 v.Fatalf("CheckLoweredPhi called with non-phi value: %v", v.LongString())
7783 }
7784 if v.Type.IsMemory() {
7785 return
7786 }
7787 f := v.Block.Func
7788 loc := f.RegAlloc[v.ID]
7789 for _, a := range v.Args {
7790 if aloc := f.RegAlloc[a.ID]; aloc != loc {
7791 v.Fatalf("phi arg at different location than phi: %v @ %s, but arg %v @ %s\n%s\n", v, loc, a, aloc, v.Block.Func)
7792 }
7793 }
7794 }
7795
7796
7797
7798
7799
7800 func CheckLoweredGetClosurePtr(v *ssa.Value) {
7801 entry := v.Block.Func.Entry
7802 if entry != v.Block {
7803 base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
7804 }
7805 for _, w := range entry.Values {
7806 if w == v {
7807 break
7808 }
7809 switch w.Op {
7810 case ssa.OpArgIntReg, ssa.OpArgFloatReg:
7811
7812 default:
7813 base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
7814 }
7815 }
7816 }
7817
7818
7819 func CheckArgReg(v *ssa.Value) {
7820 entry := v.Block.Func.Entry
7821 if entry != v.Block {
7822 base.Fatalf("in %s, badly placed ArgIReg or ArgFReg: %v %v", v.Block.Func.Name, v.Block, v)
7823 }
7824 }
7825
7826 func AddrAuto(a *obj.Addr, v *ssa.Value) {
7827 n, off := ssa.AutoVar(v)
7828 a.Type = obj.TYPE_MEM
7829 a.Sym = n.Linksym()
7830 a.Reg = int16(Arch.REGSP)
7831 a.Offset = n.FrameOffset() + off
7832 if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
7833 a.Name = obj.NAME_PARAM
7834 } else {
7835 a.Name = obj.NAME_AUTO
7836 }
7837 }
7838
7839
7840
7841 func (s *State) Call(v *ssa.Value) *obj.Prog {
7842 pPosIsStmt := s.pp.Pos.IsStmt()
7843 s.PrepareCall(v)
7844
7845 p := s.Prog(obj.ACALL)
7846 if pPosIsStmt == src.PosIsStmt {
7847 p.Pos = v.Pos.WithIsStmt()
7848 } else {
7849 p.Pos = v.Pos.WithNotStmt()
7850 }
7851 if sym, ok := v.Aux.(*ssa.AuxCall); ok && sym.Fn != nil {
7852 p.To.Type = obj.TYPE_MEM
7853 p.To.Name = obj.NAME_EXTERN
7854 p.To.Sym = sym.Fn
7855 } else {
7856
7857 switch Arch.LinkArch.Family {
7858 case sys.AMD64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X, sys.Wasm:
7859 p.To.Type = obj.TYPE_REG
7860 case sys.ARM, sys.ARM64, sys.Loong64, sys.MIPS, sys.MIPS64:
7861 p.To.Type = obj.TYPE_MEM
7862 default:
7863 base.Fatalf("unknown indirect call family")
7864 }
7865 p.To.Reg = v.Args[0].Reg()
7866 }
7867 return p
7868 }
7869
7870
7871
7872 func (s *State) TailCall(v *ssa.Value) *obj.Prog {
7873 p := s.Call(v)
7874 p.As = obj.ARET
7875 return p
7876 }
7877
7878
7879
7880
7881 func (s *State) PrepareCall(v *ssa.Value) {
7882 idx := s.livenessMap.Get(v)
7883 if !idx.StackMapValid() {
7884
7885 if sym, ok := v.Aux.(*ssa.AuxCall); !ok || !(sym.Fn == ir.Syms.WBZero || sym.Fn == ir.Syms.WBMove) {
7886 base.Fatalf("missing stack map index for %v", v.LongString())
7887 }
7888 }
7889
7890 call, ok := v.Aux.(*ssa.AuxCall)
7891
7892 if ok {
7893
7894
7895 if nowritebarrierrecCheck != nil {
7896 nowritebarrierrecCheck.recordCall(s.pp.CurFunc, call.Fn, v.Pos)
7897 }
7898 }
7899
7900 if s.maxarg < v.AuxInt {
7901 s.maxarg = v.AuxInt
7902 }
7903 }
7904
7905
7906
7907 func (s *State) UseArgs(n int64) {
7908 if s.maxarg < n {
7909 s.maxarg = n
7910 }
7911 }
7912
7913
7914 func fieldIdx(n *ir.SelectorExpr) int {
7915 t := n.X.Type()
7916 if !isStructNotSIMD(t) {
7917 panic("ODOT's LHS is not a struct")
7918 }
7919
7920 for i, f := range t.Fields() {
7921 if f.Sym == n.Sel {
7922 if f.Offset != n.Offset() {
7923 panic("field offset doesn't match")
7924 }
7925 return i
7926 }
7927 }
7928 panic(fmt.Sprintf("can't find field in expr %v\n", n))
7929
7930
7931
7932 }
7933
7934
7935
7936 type ssafn struct {
7937 curfn *ir.Func
7938 strings map[string]*obj.LSym
7939 stksize int64
7940 stkptrsize int64
7941
7942
7943
7944
7945
7946 stkalign int64
7947
7948 log bool
7949 }
7950
7951
7952
7953 func (e *ssafn) StringData(s string) *obj.LSym {
7954 if aux, ok := e.strings[s]; ok {
7955 return aux
7956 }
7957 if e.strings == nil {
7958 e.strings = make(map[string]*obj.LSym)
7959 }
7960 data := staticdata.StringSym(e.curfn.Pos(), s)
7961 e.strings[s] = data
7962 return data
7963 }
7964
7965
7966 func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
7967 node := parent.N
7968
7969 if node.Class != ir.PAUTO || node.Addrtaken() {
7970
7971 return ssa.LocalSlot{N: node, Type: t, Off: parent.Off + offset}
7972 }
7973
7974 sym := &types.Sym{Name: node.Sym().Name + suffix, Pkg: types.LocalPkg}
7975 n := e.curfn.NewLocal(parent.N.Pos(), sym, t)
7976 n.SetUsed(true)
7977 n.SetEsc(ir.EscNever)
7978 types.CalcSize(t)
7979 return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset}
7980 }
7981
7982
7983 func (e *ssafn) Logf(msg string, args ...any) {
7984 if e.log {
7985 fmt.Printf(msg, args...)
7986 }
7987 }
7988
7989 func (e *ssafn) Log() bool {
7990 return e.log
7991 }
7992
7993
7994 func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...any) {
7995 base.Pos = pos
7996 nargs := append([]any{ir.FuncName(e.curfn)}, args...)
7997 base.Fatalf("'%s': "+msg, nargs...)
7998 }
7999
8000
8001
8002 func (e *ssafn) Warnl(pos src.XPos, fmt_ string, args ...any) {
8003 base.WarnfAt(pos, fmt_, args...)
8004 }
8005
8006 func (e *ssafn) Debug_checknil() bool {
8007 return base.Debug.Nil != 0
8008 }
8009
8010 func (e *ssafn) UseWriteBarrier() bool {
8011 return base.Flag.WB
8012 }
8013
8014 func (e *ssafn) Syslook(name string) *obj.LSym {
8015 switch name {
8016 case "goschedguarded":
8017 return ir.Syms.Goschedguarded
8018 case "writeBarrier":
8019 return ir.Syms.WriteBarrier
8020 case "wbZero":
8021 return ir.Syms.WBZero
8022 case "wbMove":
8023 return ir.Syms.WBMove
8024 case "cgoCheckMemmove":
8025 return ir.Syms.CgoCheckMemmove
8026 case "cgoCheckPtrWrite":
8027 return ir.Syms.CgoCheckPtrWrite
8028 }
8029 e.Fatalf(src.NoXPos, "unknown Syslook func %v", name)
8030 return nil
8031 }
8032
8033 func (e *ssafn) Func() *ir.Func {
8034 return e.curfn
8035 }
8036
8037 func clobberBase(n ir.Node) ir.Node {
8038 if n.Op() == ir.ODOT {
8039 n := n.(*ir.SelectorExpr)
8040 if n.X.Type().NumFields() == 1 {
8041 return clobberBase(n.X)
8042 }
8043 }
8044 if n.Op() == ir.OINDEX {
8045 n := n.(*ir.IndexExpr)
8046 if n.X.Type().IsArray() && n.X.Type().NumElem() == 1 {
8047 return clobberBase(n.X)
8048 }
8049 }
8050 return n
8051 }
8052
8053
8054 func callTargetLSym(callee *ir.Name) *obj.LSym {
8055 if callee.Func == nil {
8056
8057
8058
8059 return callee.Linksym()
8060 }
8061
8062 return callee.LinksymABI(callee.Func.ABI)
8063 }
8064
8065
8066 const deferStructFnField = 4
8067
8068 var deferType *types.Type
8069
8070
8071
8072 func deferstruct() *types.Type {
8073 if deferType != nil {
8074 return deferType
8075 }
8076
8077 makefield := func(name string, t *types.Type) *types.Field {
8078 sym := (*types.Pkg)(nil).Lookup(name)
8079 return types.NewField(src.NoXPos, sym, t)
8080 }
8081
8082 fields := []*types.Field{
8083 makefield("heap", types.Types[types.TBOOL]),
8084 makefield("rangefunc", types.Types[types.TBOOL]),
8085 makefield("sp", types.Types[types.TUINTPTR]),
8086 makefield("pc", types.Types[types.TUINTPTR]),
8087
8088
8089
8090 makefield("fn", types.Types[types.TUINTPTR]),
8091 makefield("link", types.Types[types.TUINTPTR]),
8092 makefield("head", types.Types[types.TUINTPTR]),
8093 }
8094 if name := fields[deferStructFnField].Sym.Name; name != "fn" {
8095 base.Fatalf("deferStructFnField is %q, not fn", name)
8096 }
8097
8098 n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.Pkgs.Runtime.Lookup("_defer"))
8099 typ := types.NewNamed(n)
8100 n.SetType(typ)
8101 n.SetTypecheck(1)
8102
8103
8104 typ.SetUnderlying(types.NewStruct(fields))
8105 types.CalcStructSize(typ)
8106
8107 deferType = typ
8108 return typ
8109 }
8110
8111
8112
8113
8114
8115 func SpillSlotAddr(spill ssa.Spill, baseReg int16, extraOffset int64) obj.Addr {
8116 return obj.Addr{
8117 Name: obj.NAME_NONE,
8118 Type: obj.TYPE_MEM,
8119 Reg: baseReg,
8120 Offset: spill.Offset + extraOffset,
8121 }
8122 }
8123
8124 func isStructNotSIMD(t *types.Type) bool {
8125 return t.IsStruct() && !t.IsSIMD()
8126 }
8127
8128 var BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
8129
View as plain text