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 len := s.constInt(types.Types[types.TINT], bound)
3558 if bound == 0 {
3559
3560 s.boundsCheck(i, len, ssa.BoundsIndex, false)
3561
3562
3563 return s.load(n.Type(), s.constNil(n.Type().PtrTo()))
3564 }
3565 s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
3566 return s.newValue1I(ssa.OpArraySelect, n.Type(), 0, a)
3567 }
3568 p := s.addr(n)
3569 return s.load(n.X.Type().Elem(), p)
3570 default:
3571 s.Fatalf("bad type for index %v", n.X.Type())
3572 return nil
3573 }
3574
3575 case ir.OLEN, ir.OCAP:
3576 n := n.(*ir.UnaryExpr)
3577
3578
3579 a := s.expr(n.X)
3580 t := n.X.Type()
3581 switch {
3582 case t.IsSlice():
3583 op := ssa.OpSliceLen
3584 if n.Op() == ir.OCAP {
3585 op = ssa.OpSliceCap
3586 }
3587 return s.newValue1(op, types.Types[types.TINT], a)
3588 case t.IsString():
3589 return s.newValue1(ssa.OpStringLen, types.Types[types.TINT], a)
3590 case t.IsMap(), t.IsChan():
3591 return s.referenceTypeBuiltin(n, a)
3592 case t.IsArray():
3593 return s.constInt(types.Types[types.TINT], t.NumElem())
3594 case t.IsPtr() && t.Elem().IsArray():
3595 return s.constInt(types.Types[types.TINT], t.Elem().NumElem())
3596 default:
3597 s.Fatalf("bad type in len/cap: %v", t)
3598 return nil
3599 }
3600
3601 case ir.OSPTR:
3602 n := n.(*ir.UnaryExpr)
3603 a := s.expr(n.X)
3604 if n.X.Type().IsSlice() {
3605 if n.Bounded() {
3606 return s.newValue1(ssa.OpSlicePtr, n.Type(), a)
3607 }
3608 return s.newValue1(ssa.OpSlicePtrUnchecked, n.Type(), a)
3609 } else {
3610 return s.newValue1(ssa.OpStringPtr, n.Type(), a)
3611 }
3612
3613 case ir.OITAB:
3614 n := n.(*ir.UnaryExpr)
3615 a := s.expr(n.X)
3616 return s.newValue1(ssa.OpITab, n.Type(), a)
3617
3618 case ir.OIDATA:
3619 n := n.(*ir.UnaryExpr)
3620 a := s.expr(n.X)
3621 return s.newValue1(ssa.OpIData, n.Type(), a)
3622
3623 case ir.OMAKEFACE:
3624 n := n.(*ir.BinaryExpr)
3625 tab := s.expr(n.X)
3626 data := s.expr(n.Y)
3627 return s.newValue2(ssa.OpIMake, n.Type(), tab, data)
3628
3629 case ir.OSLICEHEADER:
3630 n := n.(*ir.SliceHeaderExpr)
3631 p := s.expr(n.Ptr)
3632 l := s.expr(n.Len)
3633 c := s.expr(n.Cap)
3634 return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
3635
3636 case ir.OSTRINGHEADER:
3637 n := n.(*ir.StringHeaderExpr)
3638 p := s.expr(n.Ptr)
3639 l := s.expr(n.Len)
3640 return s.newValue2(ssa.OpStringMake, n.Type(), p, l)
3641
3642 case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
3643 n := n.(*ir.SliceExpr)
3644 check := s.checkPtrEnabled && n.Op() == ir.OSLICE3ARR && n.X.Op() == ir.OCONVNOP && n.X.(*ir.ConvExpr).X.Type().IsUnsafePtr()
3645 v := s.exprCheckPtr(n.X, !check)
3646 var i, j, k *ssa.Value
3647 if n.Low != nil {
3648 i = s.expr(n.Low)
3649 }
3650 if n.High != nil {
3651 j = s.expr(n.High)
3652 }
3653 if n.Max != nil {
3654 k = s.expr(n.Max)
3655 }
3656 p, l, c := s.slice(v, i, j, k, n.Bounded())
3657 if check {
3658
3659 s.checkPtrAlignment(n.X.(*ir.ConvExpr), v, s.conv(n.Max, k, k.Type, types.Types[types.TUINTPTR]))
3660 }
3661 return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
3662
3663 case ir.OSLICESTR:
3664 n := n.(*ir.SliceExpr)
3665 v := s.expr(n.X)
3666 var i, j *ssa.Value
3667 if n.Low != nil {
3668 i = s.expr(n.Low)
3669 }
3670 if n.High != nil {
3671 j = s.expr(n.High)
3672 }
3673 p, l, _ := s.slice(v, i, j, nil, n.Bounded())
3674 return s.newValue2(ssa.OpStringMake, n.Type(), p, l)
3675
3676 case ir.OSLICE2ARRPTR:
3677
3678
3679
3680
3681 n := n.(*ir.ConvExpr)
3682 v := s.expr(n.X)
3683 nelem := n.Type().Elem().NumElem()
3684 arrlen := s.constInt(types.Types[types.TINT], nelem)
3685 cap := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], v)
3686 s.boundsCheck(arrlen, cap, ssa.BoundsConvert, false)
3687 op := ssa.OpSlicePtr
3688 if nelem == 0 {
3689 op = ssa.OpSlicePtrUnchecked
3690 }
3691 return s.newValue1(op, n.Type(), v)
3692
3693 case ir.OCALLFUNC:
3694 n := n.(*ir.CallExpr)
3695 if ir.IsIntrinsicCall(n) {
3696 return s.intrinsicCall(n)
3697 }
3698 fallthrough
3699
3700 case ir.OCALLINTER:
3701 n := n.(*ir.CallExpr)
3702 return s.callResult(n, callNormal)
3703
3704 case ir.OGETG:
3705 n := n.(*ir.CallExpr)
3706 return s.newValue1(ssa.OpGetG, n.Type(), s.mem())
3707
3708 case ir.OGETCALLERSP:
3709 n := n.(*ir.CallExpr)
3710 return s.newValue1(ssa.OpGetCallerSP, n.Type(), s.mem())
3711
3712 case ir.OAPPEND:
3713 return s.append(n.(*ir.CallExpr), false)
3714
3715 case ir.OMOVE2HEAP:
3716 return s.move2heap(n.(*ir.MoveToHeapExpr))
3717
3718 case ir.OMIN, ir.OMAX:
3719 return s.minMax(n.(*ir.CallExpr))
3720
3721 case ir.OSTRUCTLIT, ir.OARRAYLIT:
3722
3723
3724
3725 n := n.(*ir.CompLitExpr)
3726 if !ir.IsZero(n) {
3727 s.Fatalf("literal with nonzero value in SSA: %v", n)
3728 }
3729 return s.zeroVal(n.Type())
3730
3731 case ir.ONEW:
3732 n := n.(*ir.UnaryExpr)
3733 if x, ok := n.X.(*ir.DynamicType); ok && x.Op() == ir.ODYNAMICTYPE {
3734 return s.newObjectNonSpecialized(n.Type().Elem(), s.expr(x.RType))
3735 }
3736 return s.newObject(n.Type().Elem())
3737
3738 case ir.OUNSAFEADD:
3739 n := n.(*ir.BinaryExpr)
3740 ptr := s.expr(n.X)
3741 len := s.expr(n.Y)
3742
3743
3744
3745 len = s.conv(n, len, len.Type, types.Types[types.TUINTPTR])
3746
3747 return s.newValue2(ssa.OpAddPtr, n.Type(), ptr, len)
3748
3749 default:
3750 s.Fatalf("unhandled expr %v", n.Op())
3751 return nil
3752 }
3753 }
3754
3755 func (s *state) resultOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.Value {
3756 aux := c.Aux.(*ssa.AuxCall)
3757 pa := aux.ParamAssignmentForResult(which)
3758
3759
3760 if len(pa.Registers) == 0 && !ssa.CanSSA(t) {
3761 addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), which, c)
3762 return s.rawLoad(t, addr)
3763 }
3764 return s.newValue1I(ssa.OpSelectN, t, which, c)
3765 }
3766
3767 func (s *state) resultAddrOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.Value {
3768 aux := c.Aux.(*ssa.AuxCall)
3769 pa := aux.ParamAssignmentForResult(which)
3770 if len(pa.Registers) == 0 {
3771 return s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), which, c)
3772 }
3773 _, addr := s.temp(c.Pos, t)
3774 rval := s.newValue1I(ssa.OpSelectN, t, which, c)
3775 s.vars[memVar] = s.newValue3Apos(ssa.OpStore, types.TypeMem, t, addr, rval, s.mem(), false)
3776 return addr
3777 }
3778
3779
3780 func (s *state) getBackingStoreInfoForAppend(n *ir.CallExpr) *backingStoreInfo {
3781 if n.Esc() != ir.EscNone {
3782 return nil
3783 }
3784 return s.getBackingStoreInfo(n.Args[0])
3785 }
3786 func (s *state) getBackingStoreInfo(n ir.Node) *backingStoreInfo {
3787 t := n.Type()
3788 et := t.Elem()
3789 maxStackSize := int64(base.Debug.VariableMakeThreshold)
3790 if et.Size() == 0 || et.Size() > maxStackSize {
3791 return nil
3792 }
3793 if base.Flag.N != 0 {
3794 return nil
3795 }
3796 if !base.VariableMakeHash.MatchPos(n.Pos(), nil) {
3797 return nil
3798 }
3799 i := s.backingStores[n]
3800 if i != nil {
3801 return i
3802 }
3803
3804
3805 K := maxStackSize / et.Size()
3806 KT := types.NewArray(et, K)
3807 KT.SetNoalg(true)
3808 types.CalcArraySize(KT)
3809
3810 align := types.NewArray(types.Types[types.TUINTPTR], 0)
3811 types.CalcArraySize(align)
3812 storeTyp := types.NewStruct([]*types.Field{
3813 {Sym: types.BlankSym, Type: align},
3814 {Sym: types.BlankSym, Type: KT},
3815 })
3816 storeTyp.SetNoalg(true)
3817 types.CalcStructSize(storeTyp)
3818
3819
3820 backingStore := typecheck.TempAt(n.Pos(), s.curfn, storeTyp)
3821 backingStore.SetAddrtaken(true)
3822
3823
3824 used := typecheck.TempAt(n.Pos(), s.curfn, types.Types[types.TBOOL])
3825 if s.curBlock == s.f.Entry {
3826 s.vars[used] = s.constBool(false)
3827 } else {
3828
3829 s.defvars[s.f.Entry.ID][used] = s.constBool(false)
3830 }
3831
3832
3833 if s.backingStores == nil {
3834 s.backingStores = map[ir.Node]*backingStoreInfo{}
3835 }
3836 i = &backingStoreInfo{K: K, store: backingStore, used: used, usedStatic: false}
3837 s.backingStores[n] = i
3838 return i
3839 }
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849 func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
3850
3851
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 et := n.Type().Elem()
3883 pt := types.NewPtr(et)
3884
3885
3886 sn := n.Args[0]
3887 var slice, addr *ssa.Value
3888 if inplace {
3889 addr = s.addr(sn)
3890 slice = s.load(n.Type(), addr)
3891 } else {
3892 slice = s.expr(sn)
3893 }
3894
3895
3896 grow := s.f.NewBlock(ssa.BlockPlain)
3897 assign := s.f.NewBlock(ssa.BlockPlain)
3898
3899
3900 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
3901 l := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
3902 c := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], slice)
3903
3904
3905 nargs := s.constInt(types.Types[types.TINT], int64(len(n.Args)-1))
3906 oldLen := l
3907 l = s.newValue2(s.ssaOp(ir.OADD, types.Types[types.TINT]), types.Types[types.TINT], l, nargs)
3908
3909
3910 cmp := s.newValue2(s.ssaOp(ir.OLT, types.Types[types.TUINT]), types.Types[types.TBOOL], c, l)
3911
3912
3913 s.vars[ptrVar] = p
3914 s.vars[lenVar] = l
3915 if !inplace {
3916 s.vars[capVar] = c
3917 }
3918
3919 b := s.endBlock()
3920 b.Kind = ssa.BlockIf
3921 b.Likely = ssa.BranchUnlikely
3922 b.SetControl(cmp)
3923 b.AddEdgeTo(grow)
3924 b.AddEdgeTo(assign)
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948 var info *backingStoreInfo
3949 if !inplace {
3950 info = s.getBackingStoreInfoForAppend(n)
3951 }
3952
3953 if !inplace && info != nil && !n.UseBuf && !info.usedStatic {
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977 info.usedStatic = true
3978
3979
3980 usedTestBlock := s.f.NewBlock(ssa.BlockPlain)
3981 oldLenTestBlock := s.f.NewBlock(ssa.BlockPlain)
3982 bodyBlock := s.f.NewBlock(ssa.BlockPlain)
3983 growSlice := s.f.NewBlock(ssa.BlockPlain)
3984 tInt := types.Types[types.TINT]
3985 tBool := types.Types[types.TBOOL]
3986
3987
3988 s.startBlock(grow)
3989 kTest := s.newValue2(s.ssaOp(ir.OLE, tInt), tBool, l, s.constInt(tInt, info.K))
3990 b := s.endBlock()
3991 b.Kind = ssa.BlockIf
3992 b.SetControl(kTest)
3993 b.AddEdgeTo(usedTestBlock)
3994 b.AddEdgeTo(growSlice)
3995 b.Likely = ssa.BranchLikely
3996
3997
3998 s.startBlock(usedTestBlock)
3999 usedTest := s.newValue1(ssa.OpNot, tBool, s.expr(info.used))
4000 b = s.endBlock()
4001 b.Kind = ssa.BlockIf
4002 b.SetControl(usedTest)
4003 b.AddEdgeTo(oldLenTestBlock)
4004 b.AddEdgeTo(growSlice)
4005 b.Likely = ssa.BranchLikely
4006
4007
4008 s.startBlock(oldLenTestBlock)
4009 oldLenTest := s.newValue2(s.ssaOp(ir.OEQ, tInt), tBool, oldLen, s.constInt(tInt, 0))
4010 b = s.endBlock()
4011 b.Kind = ssa.BlockIf
4012 b.SetControl(oldLenTest)
4013 b.AddEdgeTo(bodyBlock)
4014 b.AddEdgeTo(growSlice)
4015 b.Likely = ssa.BranchLikely
4016
4017
4018 s.startBlock(bodyBlock)
4019 if et.HasPointers() {
4020 s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, info.store, s.mem())
4021 }
4022 addr := s.addr(info.store)
4023 s.zero(info.store.Type(), addr)
4024
4025
4026 s.vars[ptrVar] = addr
4027 s.vars[lenVar] = l
4028 s.vars[capVar] = s.constInt(tInt, info.K)
4029
4030
4031 s.assign(info.used, s.constBool(true), false, 0)
4032 b = s.endBlock()
4033 b.AddEdgeTo(assign)
4034
4035
4036 grow = growSlice
4037 }
4038
4039
4040 s.startBlock(grow)
4041 taddr := s.expr(n.Fun)
4042 var r []*ssa.Value
4043 if info != nil && n.UseBuf {
4044
4045 if et.HasPointers() && !info.usedStatic {
4046
4047
4048
4049 mem := s.defvars[s.f.Entry.ID][memVar]
4050 mem = s.f.Entry.NewValue1A(n.Pos(), ssa.OpVarDef, types.TypeMem, info.store, mem)
4051 addr := s.f.Entry.NewValue2A(n.Pos(), ssa.OpLocalAddr, types.NewPtr(info.store.Type()), info.store, s.sp, mem)
4052 mem = s.f.Entry.NewValue2I(n.Pos(), ssa.OpZero, types.TypeMem, info.store.Type().Size(), addr, mem)
4053 mem.Aux = info.store.Type()
4054 s.defvars[s.f.Entry.ID][memVar] = mem
4055 info.usedStatic = true
4056 }
4057 fn := ir.Syms.GrowsliceBuf
4058 if goexperiment.RuntimeFreegc && n.AppendNoAlias && !et.HasPointers() {
4059
4060
4061
4062
4063 fn = ir.Syms.GrowsliceBufNoAlias
4064 }
4065 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))
4066 } else {
4067 fn := ir.Syms.Growslice
4068 if goexperiment.RuntimeFreegc && n.AppendNoAlias && !et.HasPointers() {
4069
4070
4071
4072
4073 fn = ir.Syms.GrowsliceNoAlias
4074 }
4075 r = s.rtcall(fn, true, []*types.Type{n.Type()}, p, l, c, nargs, taddr)
4076 }
4077
4078
4079 p = s.newValue1(ssa.OpSlicePtr, pt, r[0])
4080 l = s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], r[0])
4081 c = s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], r[0])
4082
4083 s.vars[ptrVar] = p
4084 s.vars[lenVar] = l
4085 s.vars[capVar] = c
4086 if inplace {
4087 if sn.Op() == ir.ONAME {
4088 sn := sn.(*ir.Name)
4089 if sn.Class != ir.PEXTERN {
4090
4091 s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem())
4092 }
4093 }
4094 capaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, types.SliceCapOffset, addr)
4095 s.store(types.Types[types.TINT], capaddr, c)
4096 s.store(pt, addr, p)
4097 }
4098
4099 b = s.endBlock()
4100 b.AddEdgeTo(assign)
4101
4102
4103 s.startBlock(assign)
4104 p = s.variable(ptrVar, pt)
4105 l = s.variable(lenVar, types.Types[types.TINT])
4106 if !inplace {
4107 c = s.variable(capVar, types.Types[types.TINT])
4108 }
4109
4110 if inplace {
4111
4112
4113 lenaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, types.SliceLenOffset, addr)
4114 s.store(types.Types[types.TINT], lenaddr, l)
4115 }
4116
4117
4118 type argRec struct {
4119
4120
4121 v *ssa.Value
4122 store bool
4123 }
4124 args := make([]argRec, 0, len(n.Args[1:]))
4125 for _, n := range n.Args[1:] {
4126 if ssa.CanSSA(n.Type()) {
4127 args = append(args, argRec{v: s.expr(n), store: true})
4128 } else {
4129 v := s.addr(n)
4130 args = append(args, argRec{v: v})
4131 }
4132 }
4133
4134
4135 oldLen = s.newValue2(s.ssaOp(ir.OSUB, types.Types[types.TINT]), types.Types[types.TINT], l, nargs)
4136 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, oldLen)
4137 for i, arg := range args {
4138 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(types.Types[types.TINT], int64(i)))
4139 if arg.store {
4140 s.storeType(et, addr, arg.v, 0, true)
4141 } else {
4142 s.move(et, addr, arg.v)
4143 }
4144 }
4145
4146
4147
4148
4149
4150 delete(s.vars, ptrVar)
4151 delete(s.vars, lenVar)
4152 if !inplace {
4153 delete(s.vars, capVar)
4154 }
4155
4156
4157 if inplace {
4158 return nil
4159 }
4160 return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
4161 }
4162
4163 func (s *state) move2heap(n *ir.MoveToHeapExpr) *ssa.Value {
4164
4165
4166
4167
4168
4169
4170
4171
4172 slice := s.expr(n.Slice)
4173 et := slice.Type.Elem()
4174 pt := types.NewPtr(et)
4175
4176 info := s.getBackingStoreInfo(n)
4177 if info == nil {
4178
4179
4180 return slice
4181 }
4182
4183
4184 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
4185 l := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
4186 c := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], slice)
4187
4188 moveBlock := s.f.NewBlock(ssa.BlockPlain)
4189 mergeBlock := s.f.NewBlock(ssa.BlockPlain)
4190
4191 s.vars[ptrVar] = p
4192 s.vars[lenVar] = l
4193 s.vars[capVar] = c
4194
4195
4196
4197 sub := ssa.OpSub64
4198 less := ssa.OpLess64U
4199 if s.config.PtrSize == 4 {
4200 sub = ssa.OpSub32
4201 less = ssa.OpLess32U
4202 }
4203 callerSP := s.newValue1(ssa.OpGetCallerSP, types.Types[types.TUINTPTR], s.mem())
4204 frameSize := s.newValue2(sub, types.Types[types.TUINTPTR], callerSP, s.sp)
4205 pInt := s.newValue2(ssa.OpConvert, types.Types[types.TUINTPTR], p, s.mem())
4206 off := s.newValue2(sub, types.Types[types.TUINTPTR], pInt, s.sp)
4207 cond := s.newValue2(less, types.Types[types.TBOOL], off, frameSize)
4208
4209 b := s.endBlock()
4210 b.Kind = ssa.BlockIf
4211 b.Likely = ssa.BranchUnlikely
4212 b.SetControl(cond)
4213 b.AddEdgeTo(moveBlock)
4214 b.AddEdgeTo(mergeBlock)
4215
4216
4217 s.startBlock(moveBlock)
4218 var newSlice *ssa.Value
4219 if et.HasPointers() {
4220 typ := s.expr(n.RType)
4221 if n.PreserveCapacity {
4222 newSlice = s.rtcall(ir.Syms.MoveSlice, true, []*types.Type{slice.Type}, typ, p, l, c)[0]
4223 } else {
4224 newSlice = s.rtcall(ir.Syms.MoveSliceNoCap, true, []*types.Type{slice.Type}, typ, p, l)[0]
4225 }
4226 } else {
4227 elemSize := s.constInt(types.Types[types.TUINTPTR], et.Size())
4228 if n.PreserveCapacity {
4229 newSlice = s.rtcall(ir.Syms.MoveSliceNoScan, true, []*types.Type{slice.Type}, elemSize, p, l, c)[0]
4230 } else {
4231 newSlice = s.rtcall(ir.Syms.MoveSliceNoCapNoScan, true, []*types.Type{slice.Type}, elemSize, p, l)[0]
4232 }
4233 }
4234
4235 s.vars[ptrVar] = s.newValue1(ssa.OpSlicePtr, pt, newSlice)
4236 s.vars[lenVar] = s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], newSlice)
4237 s.vars[capVar] = s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], newSlice)
4238 b = s.endBlock()
4239 b.AddEdgeTo(mergeBlock)
4240
4241
4242 s.startBlock(mergeBlock)
4243 p = s.variable(ptrVar, pt)
4244 l = s.variable(lenVar, types.Types[types.TINT])
4245 c = s.variable(capVar, types.Types[types.TINT])
4246 delete(s.vars, ptrVar)
4247 delete(s.vars, lenVar)
4248 delete(s.vars, capVar)
4249 return s.newValue3(ssa.OpSliceMake, slice.Type, p, l, c)
4250 }
4251
4252
4253 func (s *state) minMax(n *ir.CallExpr) *ssa.Value {
4254
4255
4256
4257 fold := func(op func(x, a *ssa.Value) *ssa.Value) *ssa.Value {
4258 x := s.expr(n.Args[0])
4259 for _, arg := range n.Args[1:] {
4260 x = op(x, s.expr(arg))
4261 }
4262 return x
4263 }
4264
4265 typ := n.Type()
4266
4267 if typ.IsFloat() || typ.IsString() {
4268
4269
4270
4271
4272
4273
4274
4275
4276 if typ.IsFloat() {
4277 hasIntrinsic := false
4278 switch Arch.LinkArch.Family {
4279 case sys.AMD64, sys.ARM64, sys.Loong64, sys.RISCV64, sys.S390X:
4280 hasIntrinsic = true
4281 case sys.PPC64:
4282 hasIntrinsic = buildcfg.GOPPC64 >= 9
4283 }
4284
4285 if hasIntrinsic {
4286 var op ssa.Op
4287 switch {
4288 case typ.Kind() == types.TFLOAT64 && n.Op() == ir.OMIN:
4289 op = ssa.OpMin64F
4290 case typ.Kind() == types.TFLOAT64 && n.Op() == ir.OMAX:
4291 op = ssa.OpMax64F
4292 case typ.Kind() == types.TFLOAT32 && n.Op() == ir.OMIN:
4293 op = ssa.OpMin32F
4294 case typ.Kind() == types.TFLOAT32 && n.Op() == ir.OMAX:
4295 op = ssa.OpMax32F
4296 }
4297 return fold(func(x, a *ssa.Value) *ssa.Value {
4298 return s.newValue2(op, typ, x, a)
4299 })
4300 }
4301 }
4302 var name string
4303 switch typ.Kind() {
4304 case types.TFLOAT32:
4305 switch n.Op() {
4306 case ir.OMIN:
4307 name = "fmin32"
4308 case ir.OMAX:
4309 name = "fmax32"
4310 }
4311 case types.TFLOAT64:
4312 switch n.Op() {
4313 case ir.OMIN:
4314 name = "fmin64"
4315 case ir.OMAX:
4316 name = "fmax64"
4317 }
4318 case types.TSTRING:
4319 switch n.Op() {
4320 case ir.OMIN:
4321 name = "strmin"
4322 case ir.OMAX:
4323 name = "strmax"
4324 }
4325 }
4326 fn := typecheck.LookupRuntimeFunc(name)
4327
4328 return fold(func(x, a *ssa.Value) *ssa.Value {
4329 return s.rtcall(fn, true, []*types.Type{typ}, x, a)[0]
4330 })
4331 }
4332
4333 if typ.IsInteger() {
4334 if Arch.LinkArch.Family == sys.RISCV64 && buildcfg.GORISCV64 >= 22 && typ.Size() == 8 {
4335 var op ssa.Op
4336 switch {
4337 case typ.IsSigned() && n.Op() == ir.OMIN:
4338 op = ssa.OpMin64
4339 case typ.IsSigned() && n.Op() == ir.OMAX:
4340 op = ssa.OpMax64
4341 case typ.IsUnsigned() && n.Op() == ir.OMIN:
4342 op = ssa.OpMin64u
4343 case typ.IsUnsigned() && n.Op() == ir.OMAX:
4344 op = ssa.OpMax64u
4345 }
4346 return fold(func(x, a *ssa.Value) *ssa.Value {
4347 return s.newValue2(op, typ, x, a)
4348 })
4349 }
4350 }
4351
4352 lt := s.ssaOp(ir.OLT, typ)
4353
4354 return fold(func(x, a *ssa.Value) *ssa.Value {
4355 switch n.Op() {
4356 case ir.OMIN:
4357
4358 return s.ternary(s.newValue2(lt, types.Types[types.TBOOL], a, x), a, x)
4359 case ir.OMAX:
4360
4361 return s.ternary(s.newValue2(lt, types.Types[types.TBOOL], x, a), a, x)
4362 }
4363 panic("unreachable")
4364 })
4365 }
4366
4367
4368 func (s *state) ternary(cond, x, y *ssa.Value) *ssa.Value {
4369
4370
4371 ternaryVar := ssaMarker("ternary")
4372
4373 bThen := s.f.NewBlock(ssa.BlockPlain)
4374 bElse := s.f.NewBlock(ssa.BlockPlain)
4375 bEnd := s.f.NewBlock(ssa.BlockPlain)
4376
4377 b := s.endBlock()
4378 b.Kind = ssa.BlockIf
4379 b.SetControl(cond)
4380 b.AddEdgeTo(bThen)
4381 b.AddEdgeTo(bElse)
4382
4383 s.startBlock(bThen)
4384 s.vars[ternaryVar] = x
4385 s.endBlock().AddEdgeTo(bEnd)
4386
4387 s.startBlock(bElse)
4388 s.vars[ternaryVar] = y
4389 s.endBlock().AddEdgeTo(bEnd)
4390
4391 s.startBlock(bEnd)
4392 r := s.variable(ternaryVar, x.Type)
4393 delete(s.vars, ternaryVar)
4394 return r
4395 }
4396
4397
4398
4399
4400
4401 func (s *state) condBranch(cond ir.Node, yes, no *ssa.Block, likely int8) {
4402 switch cond.Op() {
4403 case ir.OANDAND:
4404 cond := cond.(*ir.LogicalExpr)
4405 mid := s.f.NewBlock(ssa.BlockPlain)
4406 s.stmtList(cond.Init())
4407 s.condBranch(cond.X, mid, no, max(likely, 0))
4408 s.startBlock(mid)
4409 s.condBranch(cond.Y, yes, no, likely)
4410 return
4411
4412
4413
4414
4415
4416
4417 case ir.OOROR:
4418 cond := cond.(*ir.LogicalExpr)
4419 mid := s.f.NewBlock(ssa.BlockPlain)
4420 s.stmtList(cond.Init())
4421 s.condBranch(cond.X, yes, mid, min(likely, 0))
4422 s.startBlock(mid)
4423 s.condBranch(cond.Y, yes, no, likely)
4424 return
4425
4426
4427
4428 case ir.ONOT:
4429 cond := cond.(*ir.UnaryExpr)
4430 s.stmtList(cond.Init())
4431 s.condBranch(cond.X, no, yes, -likely)
4432 return
4433 case ir.OCONVNOP:
4434 cond := cond.(*ir.ConvExpr)
4435 s.stmtList(cond.Init())
4436 s.condBranch(cond.X, yes, no, likely)
4437 return
4438 }
4439 c := s.expr(cond)
4440 b := s.endBlock()
4441 b.Kind = ssa.BlockIf
4442 b.SetControl(c)
4443 b.Likely = ssa.BranchPrediction(likely)
4444 b.AddEdgeTo(yes)
4445 b.AddEdgeTo(no)
4446 }
4447
4448 type skipMask uint8
4449
4450 const (
4451 skipPtr skipMask = 1 << iota
4452 skipLen
4453 skipCap
4454 )
4455
4456
4457
4458
4459
4460
4461
4462 func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask) {
4463 s.assignWhichMayOverlap(left, right, deref, skip, false)
4464 }
4465 func (s *state) assignWhichMayOverlap(left ir.Node, right *ssa.Value, deref bool, skip skipMask, mayOverlap bool) {
4466 if left.Op() == ir.ONAME && ir.IsBlank(left) {
4467 return
4468 }
4469 t := left.Type()
4470 types.CalcSize(t)
4471 if s.canSSA(left) {
4472 if deref {
4473 s.Fatalf("can SSA LHS %v but not RHS %s", left, right)
4474 }
4475 if left.Op() == ir.ODOT {
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486 left := left.(*ir.SelectorExpr)
4487 t := left.X.Type()
4488 nf := t.NumFields()
4489 idx := fieldIdx(left)
4490
4491
4492 old := s.expr(left.X)
4493
4494 if left.Type().Size() == 0 {
4495
4496 return
4497 }
4498
4499
4500 new := s.newValue0(ssa.OpStructMake, t)
4501
4502
4503 for i := 0; i < nf; i++ {
4504 if i == idx {
4505 new.AddArg(right)
4506 } else {
4507 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), int64(i), old))
4508 }
4509 }
4510
4511
4512 s.assign(left.X, new, false, 0)
4513
4514 return
4515 }
4516 if left.Op() == ir.OINDEX && left.(*ir.IndexExpr).X.Type().IsArray() {
4517 left := left.(*ir.IndexExpr)
4518 s.pushLine(left.Pos())
4519 defer s.popLine()
4520
4521
4522 t := left.X.Type()
4523 n := t.NumElem()
4524
4525 i := s.expr(left.Index)
4526 if n == 0 {
4527 _ = s.expr(left.X)
4528
4529
4530 z := s.constInt(types.Types[types.TINT], 0)
4531 s.boundsCheck(z, z, ssa.BoundsIndex, false)
4532 return
4533 }
4534 if t.Size() == 0 {
4535 _ = s.expr(left.X)
4536
4537
4538 len := s.constInt(types.Types[types.TINT], n)
4539 s.boundsCheck(i, len, ssa.BoundsIndex, false)
4540 return
4541 }
4542 if n != 1 {
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552 _ = s.expr(left.X)
4553 return
4554 }
4555
4556
4557 len := s.constInt(types.Types[types.TINT], 1)
4558 s.boundsCheck(i, len, ssa.BoundsIndex, false)
4559 v := s.newValue1(ssa.OpArrayMake1, t, right)
4560 s.assign(left.X, v, false, 0)
4561 return
4562 }
4563 left := left.(*ir.Name)
4564
4565 s.vars[left] = right
4566 s.addNamedValue(left, right)
4567 return
4568 }
4569
4570
4571
4572 if base, ok := clobberBase(left).(*ir.Name); ok && base.OnStack() && skip == 0 && (t.HasPointers() || ssa.IsMergeCandidate(base)) {
4573 s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, base, s.mem(), !ir.IsAutoTmp(base))
4574 }
4575
4576
4577 addr := s.addr(left)
4578 if ir.IsReflectHeaderDataField(left) {
4579
4580
4581
4582
4583
4584 t = types.Types[types.TUNSAFEPTR]
4585 }
4586 if deref {
4587
4588 if right == nil {
4589 s.zero(t, addr)
4590 } else {
4591 s.moveWhichMayOverlap(t, addr, right, mayOverlap)
4592 }
4593 return
4594 }
4595
4596 s.storeType(t, addr, right, skip, !ir.IsAutoTmp(left))
4597 }
4598
4599
4600 func (s *state) zeroVal(t *types.Type) *ssa.Value {
4601 if t.Size() == 0 {
4602 return s.entryNewValue0(ssa.OpEmpty, t)
4603 }
4604 switch {
4605 case t.IsInteger():
4606 switch t.Size() {
4607 case 1:
4608 return s.constInt8(t, 0)
4609 case 2:
4610 return s.constInt16(t, 0)
4611 case 4:
4612 return s.constInt32(t, 0)
4613 case 8:
4614 return s.constInt64(t, 0)
4615 default:
4616 s.Fatalf("bad sized integer type %v", t)
4617 }
4618 case t.IsFloat():
4619 switch t.Size() {
4620 case 4:
4621 return s.constFloat32(t, 0)
4622 case 8:
4623 return s.constFloat64(t, 0)
4624 default:
4625 s.Fatalf("bad sized float type %v", t)
4626 }
4627 case t.IsComplex():
4628 switch t.Size() {
4629 case 8:
4630 z := s.constFloat32(types.Types[types.TFLOAT32], 0)
4631 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
4632 case 16:
4633 z := s.constFloat64(types.Types[types.TFLOAT64], 0)
4634 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
4635 default:
4636 s.Fatalf("bad sized complex type %v", t)
4637 }
4638
4639 case t.IsString():
4640 return s.constEmptyString(t)
4641 case t.IsPtrShaped():
4642 return s.constNil(t)
4643 case t.IsBoolean():
4644 return s.constBool(false)
4645 case t.IsInterface():
4646 return s.constInterface(t)
4647 case t.IsSlice():
4648 return s.constSlice(t)
4649 case isStructNotSIMD(t):
4650 n := t.NumFields()
4651 v := s.entryNewValue0(ssa.OpStructMake, t)
4652 for i := 0; i < n; i++ {
4653 v.AddArg(s.zeroVal(t.FieldType(i)))
4654 }
4655 return v
4656 case t.IsArray() && t.NumElem() == 1:
4657 return s.entryNewValue1(ssa.OpArrayMake1, t, s.zeroVal(t.Elem()))
4658 case t.IsSIMD():
4659 return s.newValue0(ssa.OpZeroSIMD, t)
4660 }
4661 s.Fatalf("zero for type %v not implemented", t)
4662 return nil
4663 }
4664
4665 type callKind int8
4666
4667 const (
4668 callNormal callKind = iota
4669 callDefer
4670 callDeferStack
4671 callGo
4672 callTail
4673 )
4674
4675 type sfRtCallDef struct {
4676 rtfn *obj.LSym
4677 rtype types.Kind
4678 }
4679
4680 var softFloatOps map[ssa.Op]sfRtCallDef
4681
4682 func softfloatInit() {
4683
4684 softFloatOps = map[ssa.Op]sfRtCallDef{
4685 ssa.OpAdd32F: {typecheck.LookupRuntimeFunc("fadd32"), types.TFLOAT32},
4686 ssa.OpAdd64F: {typecheck.LookupRuntimeFunc("fadd64"), types.TFLOAT64},
4687 ssa.OpSub32F: {typecheck.LookupRuntimeFunc("fadd32"), types.TFLOAT32},
4688 ssa.OpSub64F: {typecheck.LookupRuntimeFunc("fadd64"), types.TFLOAT64},
4689 ssa.OpMul32F: {typecheck.LookupRuntimeFunc("fmul32"), types.TFLOAT32},
4690 ssa.OpMul64F: {typecheck.LookupRuntimeFunc("fmul64"), types.TFLOAT64},
4691 ssa.OpDiv32F: {typecheck.LookupRuntimeFunc("fdiv32"), types.TFLOAT32},
4692 ssa.OpDiv64F: {typecheck.LookupRuntimeFunc("fdiv64"), types.TFLOAT64},
4693
4694 ssa.OpEq64F: {typecheck.LookupRuntimeFunc("feq64"), types.TBOOL},
4695 ssa.OpEq32F: {typecheck.LookupRuntimeFunc("feq32"), types.TBOOL},
4696 ssa.OpNeq64F: {typecheck.LookupRuntimeFunc("feq64"), types.TBOOL},
4697 ssa.OpNeq32F: {typecheck.LookupRuntimeFunc("feq32"), types.TBOOL},
4698 ssa.OpLess64F: {typecheck.LookupRuntimeFunc("fgt64"), types.TBOOL},
4699 ssa.OpLess32F: {typecheck.LookupRuntimeFunc("fgt32"), types.TBOOL},
4700 ssa.OpLeq64F: {typecheck.LookupRuntimeFunc("fge64"), types.TBOOL},
4701 ssa.OpLeq32F: {typecheck.LookupRuntimeFunc("fge32"), types.TBOOL},
4702
4703 ssa.OpCvt32to32F: {typecheck.LookupRuntimeFunc("fint32to32"), types.TFLOAT32},
4704 ssa.OpCvt32Fto32: {typecheck.LookupRuntimeFunc("f32toint32"), types.TINT32},
4705 ssa.OpCvt64to32F: {typecheck.LookupRuntimeFunc("fint64to32"), types.TFLOAT32},
4706 ssa.OpCvt32Fto64: {typecheck.LookupRuntimeFunc("f32toint64"), types.TINT64},
4707 ssa.OpCvt64Uto32F: {typecheck.LookupRuntimeFunc("fuint64to32"), types.TFLOAT32},
4708 ssa.OpCvt32Fto64U: {typecheck.LookupRuntimeFunc("f32touint64"), types.TUINT64},
4709 ssa.OpCvt32to64F: {typecheck.LookupRuntimeFunc("fint32to64"), types.TFLOAT64},
4710 ssa.OpCvt64Fto32: {typecheck.LookupRuntimeFunc("f64toint32"), types.TINT32},
4711 ssa.OpCvt64to64F: {typecheck.LookupRuntimeFunc("fint64to64"), types.TFLOAT64},
4712 ssa.OpCvt64Fto64: {typecheck.LookupRuntimeFunc("f64toint64"), types.TINT64},
4713 ssa.OpCvt64Uto64F: {typecheck.LookupRuntimeFunc("fuint64to64"), types.TFLOAT64},
4714 ssa.OpCvt64Fto64U: {typecheck.LookupRuntimeFunc("f64touint64"), types.TUINT64},
4715 ssa.OpCvt32Fto64F: {typecheck.LookupRuntimeFunc("f32to64"), types.TFLOAT64},
4716 ssa.OpCvt64Fto32F: {typecheck.LookupRuntimeFunc("f64to32"), types.TFLOAT32},
4717 }
4718 }
4719
4720
4721
4722 func (s *state) sfcall(op ssa.Op, args ...*ssa.Value) (*ssa.Value, bool) {
4723 f2i := func(t *types.Type) *types.Type {
4724 switch t.Kind() {
4725 case types.TFLOAT32:
4726 return types.Types[types.TUINT32]
4727 case types.TFLOAT64:
4728 return types.Types[types.TUINT64]
4729 }
4730 return t
4731 }
4732
4733 if callDef, ok := softFloatOps[op]; ok {
4734 switch op {
4735 case ssa.OpLess32F,
4736 ssa.OpLess64F,
4737 ssa.OpLeq32F,
4738 ssa.OpLeq64F:
4739 args[0], args[1] = args[1], args[0]
4740 case ssa.OpSub32F,
4741 ssa.OpSub64F:
4742 args[1] = s.newValue1(s.ssaOp(ir.ONEG, types.Types[callDef.rtype]), args[1].Type, args[1])
4743 }
4744
4745
4746
4747 for i, a := range args {
4748 if a.Type.IsFloat() {
4749 args[i] = s.newValue1(ssa.OpCopy, f2i(a.Type), a)
4750 }
4751 }
4752
4753 rt := types.Types[callDef.rtype]
4754 result := s.rtcall(callDef.rtfn, true, []*types.Type{f2i(rt)}, args...)[0]
4755 if rt.IsFloat() {
4756 result = s.newValue1(ssa.OpCopy, rt, result)
4757 }
4758 if op == ssa.OpNeq32F || op == ssa.OpNeq64F {
4759 result = s.newValue1(ssa.OpNot, result.Type, result)
4760 }
4761 return result, true
4762 }
4763 return nil, false
4764 }
4765
4766
4767 func (s *state) split(v *ssa.Value) (*ssa.Value, *ssa.Value) {
4768 p0 := s.newValue1(ssa.OpSelect0, v.Type.FieldType(0), v)
4769 p1 := s.newValue1(ssa.OpSelect1, v.Type.FieldType(1), v)
4770 return p0, p1
4771 }
4772
4773
4774 func (s *state) intrinsicCall(n *ir.CallExpr) *ssa.Value {
4775 v := findIntrinsic(n.Fun.Sym())(s, n, s.intrinsicArgs(n))
4776 if ssa.IntrinsicsDebug > 0 {
4777 x := v
4778 if x == nil {
4779 x = s.mem()
4780 }
4781 if x.Op == ssa.OpSelect0 || x.Op == ssa.OpSelect1 {
4782 x = x.Args[0]
4783 }
4784 base.WarnfAt(n.Pos(), "intrinsic substitution for %v with %s", n.Fun.Sym().Name, x.LongString())
4785 }
4786 return v
4787 }
4788
4789
4790 func (s *state) intrinsicArgs(n *ir.CallExpr) []*ssa.Value {
4791 args := make([]*ssa.Value, len(n.Args))
4792 for i, n := range n.Args {
4793 args[i] = s.expr(n)
4794 }
4795 return args
4796 }
4797
4798
4799
4800
4801
4802
4803
4804 func (s *state) openDeferRecord(n *ir.CallExpr) {
4805 if len(n.Args) != 0 || n.Op() != ir.OCALLFUNC || n.Fun.Type().NumResults() != 0 {
4806 s.Fatalf("defer call with arguments or results: %v", n)
4807 }
4808
4809 opendefer := &openDeferInfo{
4810 n: n,
4811 }
4812 fn := n.Fun
4813
4814
4815
4816 closureVal := s.expr(fn)
4817 closure := s.openDeferSave(fn.Type(), closureVal)
4818 opendefer.closureNode = closure.Aux.(*ir.Name)
4819 if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC) {
4820 opendefer.closure = closure
4821 }
4822 index := len(s.openDefers)
4823 s.openDefers = append(s.openDefers, opendefer)
4824
4825
4826
4827 bitvalue := s.constInt8(types.Types[types.TUINT8], 1<<uint(index))
4828 newDeferBits := s.newValue2(ssa.OpOr8, types.Types[types.TUINT8], s.variable(deferBitsVar, types.Types[types.TUINT8]), bitvalue)
4829 s.vars[deferBitsVar] = newDeferBits
4830 s.store(types.Types[types.TUINT8], s.deferBitsAddr, newDeferBits)
4831 }
4832
4833
4834
4835
4836
4837
4838 func (s *state) openDeferSave(t *types.Type, val *ssa.Value) *ssa.Value {
4839 if !ssa.CanSSA(t) {
4840 s.Fatalf("openDeferSave of non-SSA-able type %v val=%v", t, val)
4841 }
4842 if !t.HasPointers() {
4843 s.Fatalf("openDeferSave of pointerless type %v val=%v", t, val)
4844 }
4845 pos := val.Pos
4846 temp := typecheck.TempAt(pos.WithNotStmt(), s.curfn, t)
4847 temp.SetOpenDeferSlot(true)
4848 temp.SetFrameOffset(int64(len(s.openDefers)))
4849 var addrTemp *ssa.Value
4850
4851
4852 if s.curBlock.ID != s.f.Entry.ID {
4853
4854
4855
4856 if t.HasPointers() {
4857 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])
4858 }
4859 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])
4860 addrTemp = s.f.Entry.NewValue2A(src.NoXPos, ssa.OpLocalAddr, types.NewPtr(temp.Type()), temp, s.sp, s.defvars[s.f.Entry.ID][memVar])
4861 } else {
4862
4863
4864
4865 if t.HasPointers() {
4866 s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, temp, s.mem(), false)
4867 }
4868 s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, temp, s.mem(), false)
4869 addrTemp = s.newValue2Apos(ssa.OpLocalAddr, types.NewPtr(temp.Type()), temp, s.sp, s.mem(), false)
4870 }
4871
4872
4873
4874
4875
4876 temp.SetNeedzero(true)
4877
4878
4879 s.store(t, addrTemp, val)
4880 return addrTemp
4881 }
4882
4883
4884
4885
4886
4887 func (s *state) openDeferExit() {
4888 deferExit := s.f.NewBlock(ssa.BlockPlain)
4889 s.endBlock().AddEdgeTo(deferExit)
4890 s.startBlock(deferExit)
4891 s.lastDeferExit = deferExit
4892 s.lastDeferCount = len(s.openDefers)
4893 zeroval := s.constInt8(types.Types[types.TUINT8], 0)
4894
4895 for i := len(s.openDefers) - 1; i >= 0; i-- {
4896 r := s.openDefers[i]
4897 bCond := s.f.NewBlock(ssa.BlockPlain)
4898 bEnd := s.f.NewBlock(ssa.BlockPlain)
4899
4900 deferBits := s.variable(deferBitsVar, types.Types[types.TUINT8])
4901
4902
4903 bitval := s.constInt8(types.Types[types.TUINT8], 1<<uint(i))
4904 andval := s.newValue2(ssa.OpAnd8, types.Types[types.TUINT8], deferBits, bitval)
4905 eqVal := s.newValue2(ssa.OpEq8, types.Types[types.TBOOL], andval, zeroval)
4906 b := s.endBlock()
4907 b.Kind = ssa.BlockIf
4908 b.SetControl(eqVal)
4909 b.AddEdgeTo(bEnd)
4910 b.AddEdgeTo(bCond)
4911 bCond.AddEdgeTo(bEnd)
4912 s.startBlock(bCond)
4913
4914
4915
4916 nbitval := s.newValue1(ssa.OpCom8, types.Types[types.TUINT8], bitval)
4917 maskedval := s.newValue2(ssa.OpAnd8, types.Types[types.TUINT8], deferBits, nbitval)
4918 s.store(types.Types[types.TUINT8], s.deferBitsAddr, maskedval)
4919
4920
4921 s.vars[deferBitsVar] = maskedval
4922
4923
4924
4925
4926 fn := r.n.Fun
4927 stksize := fn.Type().ArgWidth()
4928 var callArgs []*ssa.Value
4929 var call *ssa.Value
4930 if r.closure != nil {
4931 v := s.load(r.closure.Type.Elem(), r.closure)
4932 s.maybeNilCheckClosure(v, callDefer)
4933 codeptr := s.rawLoad(types.Types[types.TUINTPTR], v)
4934 aux := ssa.ClosureAuxCall(s.f.ABIDefault.ABIAnalyzeTypes(nil, nil))
4935 call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v)
4936 } else {
4937 aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), s.f.ABIDefault.ABIAnalyzeTypes(nil, nil))
4938 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
4939 }
4940 callArgs = append(callArgs, s.mem())
4941 call.AddArgs(callArgs...)
4942 call.AuxInt = stksize
4943 s.vars[memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, 0, call)
4944
4945
4946
4947
4948 if r.closureNode != nil {
4949 s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, r.closureNode, s.mem(), false)
4950 }
4951
4952 s.endBlock()
4953 s.startBlock(bEnd)
4954 }
4955 }
4956
4957 func (s *state) callResult(n *ir.CallExpr, k callKind) *ssa.Value {
4958 return s.call(n, k, false, nil)
4959 }
4960
4961 func (s *state) callAddr(n *ir.CallExpr, k callKind) *ssa.Value {
4962 return s.call(n, k, true, nil)
4963 }
4964
4965
4966
4967 func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool, deferExtra ir.Expr) *ssa.Value {
4968 s.prevCall = nil
4969 var calleeLSym *obj.LSym
4970 var closure *ssa.Value
4971 var codeptr *ssa.Value
4972 var dextra *ssa.Value
4973 var rcvr *ssa.Value
4974 fn := n.Fun
4975 var ACArgs []*types.Type
4976 var ACResults []*types.Type
4977 var callArgs []*ssa.Value
4978
4979 callABI := s.f.ABIDefault
4980
4981 if k != callNormal && k != callTail && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.Fun.Type().NumResults() != 0) {
4982 s.Fatalf("go/defer call with arguments: %v", n)
4983 }
4984
4985 isCallDeferRangeFunc := false
4986
4987 switch n.Op() {
4988 case ir.OCALLFUNC:
4989 if (k == callNormal || k == callTail) && fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC {
4990 fn := fn.(*ir.Name)
4991 calleeLSym = callTargetLSym(fn)
4992 if buildcfg.Experiment.RegabiArgs {
4993
4994
4995
4996
4997
4998 if fn.Func != nil {
4999 callABI = abiForFunc(fn.Func, s.f.ABI0, s.f.ABI1)
5000 }
5001 } else {
5002
5003 inRegistersImported := fn.Pragma()&ir.RegisterParams != 0
5004 inRegistersSamePackage := fn.Func != nil && fn.Func.Pragma&ir.RegisterParams != 0
5005 if inRegistersImported || inRegistersSamePackage {
5006 callABI = s.f.ABI1
5007 }
5008 }
5009 if fn := n.Fun.Sym().Name; n.Fun.Sym().Pkg == ir.Pkgs.Runtime && fn == "deferrangefunc" {
5010 isCallDeferRangeFunc = true
5011 }
5012 break
5013 }
5014 closure = s.expr(fn)
5015 if k != callDefer && k != callDeferStack {
5016
5017
5018 s.maybeNilCheckClosure(closure, k)
5019 }
5020 case ir.OCALLINTER:
5021 if fn.Op() != ir.ODOTINTER {
5022 s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
5023 }
5024 fn := fn.(*ir.SelectorExpr)
5025 var iclosure *ssa.Value
5026 iclosure, rcvr = s.getClosureAndRcvr(fn)
5027 if k == callNormal || k == callTail {
5028 codeptr = s.load(types.Types[types.TUINTPTR], iclosure)
5029 } else {
5030 closure = iclosure
5031 }
5032 }
5033 if deferExtra != nil {
5034 dextra = s.expr(deferExtra)
5035 }
5036
5037 params := callABI.ABIAnalyze(n.Fun.Type(), false )
5038 types.CalcSize(fn.Type())
5039 stksize := params.ArgWidth()
5040
5041 res := n.Fun.Type().Results()
5042 if k == callNormal || k == callTail {
5043 for _, p := range params.OutParams() {
5044 ACResults = append(ACResults, p.Type)
5045 }
5046 }
5047
5048 var call *ssa.Value
5049 if k == callDeferStack {
5050 if stksize != 0 {
5051 s.Fatalf("deferprocStack with non-zero stack size %d: %v", stksize, n)
5052 }
5053
5054 t := deferstruct()
5055 n, addr := s.temp(n.Pos(), t)
5056 n.SetNonMergeable(true)
5057 s.store(closure.Type,
5058 s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(deferStructFnField), addr),
5059 closure)
5060
5061
5062 ACArgs = append(ACArgs, types.Types[types.TUINTPTR])
5063 aux := ssa.StaticAuxCall(ir.Syms.DeferprocStack, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5064 callArgs = append(callArgs, addr, s.mem())
5065 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5066 call.AddArgs(callArgs...)
5067 call.AuxInt = int64(types.PtrSize)
5068 } else {
5069
5070
5071 argStart := base.Ctxt.Arch.FixedFrameSize
5072
5073 if k != callNormal && k != callTail {
5074
5075 ACArgs = append(ACArgs, types.Types[types.TUINTPTR])
5076 callArgs = append(callArgs, closure)
5077 stksize += int64(types.PtrSize)
5078 argStart += int64(types.PtrSize)
5079 if dextra != nil {
5080
5081 ACArgs = append(ACArgs, types.Types[types.TINTER])
5082 callArgs = append(callArgs, dextra)
5083 stksize += 2 * int64(types.PtrSize)
5084 argStart += 2 * int64(types.PtrSize)
5085 }
5086 }
5087
5088
5089 if rcvr != nil {
5090 callArgs = append(callArgs, rcvr)
5091 }
5092
5093
5094 t := n.Fun.Type()
5095 args := n.Args
5096
5097 for _, p := range params.InParams() {
5098 ACArgs = append(ACArgs, p.Type)
5099 }
5100
5101
5102
5103
5104 if s.curBlock.ID == s.f.Entry.ID && s.hasOpenDefers {
5105 b := s.endBlock()
5106 b.Kind = ssa.BlockPlain
5107 curb := s.f.NewBlock(ssa.BlockPlain)
5108 b.AddEdgeTo(curb)
5109 s.startBlock(curb)
5110 }
5111
5112 for i, n := range args {
5113 callArgs = append(callArgs, s.putArg(n, t.Param(i).Type))
5114 }
5115
5116 callArgs = append(callArgs, s.mem())
5117
5118
5119 switch {
5120 case k == callDefer:
5121 sym := ir.Syms.Deferproc
5122 if dextra != nil {
5123 sym = ir.Syms.Deferprocat
5124 }
5125 aux := ssa.StaticAuxCall(sym, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5126 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5127 case k == callGo:
5128 aux := ssa.StaticAuxCall(ir.Syms.Newproc, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5129 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5130 case closure != nil:
5131
5132
5133
5134
5135
5136 codeptr = s.rawLoad(types.Types[types.TUINTPTR], closure)
5137 aux := ssa.ClosureAuxCall(callABI.ABIAnalyzeTypes(ACArgs, ACResults))
5138 call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure)
5139 case codeptr != nil:
5140
5141 aux := ssa.InterfaceAuxCall(params)
5142 call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr)
5143 if k == callTail {
5144 call.Op = ssa.OpTailLECallInter
5145 stksize = 0
5146 }
5147 case calleeLSym != nil:
5148 aux := ssa.StaticAuxCall(calleeLSym, params)
5149 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5150 if k == callTail {
5151 call.Op = ssa.OpTailLECall
5152 stksize = 0
5153 }
5154 default:
5155 s.Fatalf("bad call type %v %v", n.Op(), n)
5156 }
5157 call.AddArgs(callArgs...)
5158 call.AuxInt = stksize
5159 }
5160 s.prevCall = call
5161 s.vars[memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
5162
5163 for _, v := range n.KeepAlive {
5164 if !v.Addrtaken() {
5165 s.Fatalf("KeepAlive variable %v must have Addrtaken set", v)
5166 }
5167 switch v.Class {
5168 case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
5169 default:
5170 s.Fatalf("KeepAlive variable %v must be Auto or Arg", v)
5171 }
5172 s.vars[memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, v, s.mem())
5173 }
5174
5175
5176 var result *ssa.Value
5177 if len(res) == 0 || k != callNormal {
5178 result = nil
5179 } else {
5180 fp := res[0]
5181 if returnResultAddr {
5182 result = s.resultAddrOfCall(call, 0, fp.Type)
5183 } else {
5184 result = s.newValue1I(ssa.OpSelectN, fp.Type, 0, call)
5185 }
5186 if n.Reshape {
5187 result = s.newValue1(ssa.OpCopy, n.Type(), result)
5188 }
5189 }
5190
5191
5192 if k == callDefer || k == callDeferStack || isCallDeferRangeFunc {
5193 b := s.endBlock()
5194 b.Kind = ssa.BlockDefer
5195 b.SetControl(call)
5196 bNext := s.f.NewBlock(ssa.BlockPlain)
5197 b.AddEdgeTo(bNext)
5198 r := s.f.DeferReturn
5199 if r == nil {
5200 r = s.f.NewBlock(ssa.BlockPlain)
5201 s.startBlock(r)
5202 s.exit()
5203 s.f.DeferReturn = r
5204 }
5205 b.AddEdgeTo(r)
5206 b.Likely = ssa.BranchLikely
5207 s.startBlock(bNext)
5208 }
5209
5210 return result
5211 }
5212
5213
5214
5215 func (s *state) maybeNilCheckClosure(closure *ssa.Value, k callKind) {
5216 if Arch.LinkArch.Family == sys.Wasm || buildcfg.GOOS == "aix" && k != callGo {
5217
5218
5219 s.nilCheck(closure)
5220 }
5221 }
5222
5223
5224
5225 func (s *state) getClosureAndRcvr(fn *ir.SelectorExpr) (*ssa.Value, *ssa.Value) {
5226 i := s.expr(fn.X)
5227 itab := s.newValue1(ssa.OpITab, types.Types[types.TUINTPTR], i)
5228 s.nilCheck(itab)
5229 itabidx := fn.Offset() + rttype.ITab.OffsetOf("Fun")
5230 closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
5231 rcvr := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, i)
5232 return closure, rcvr
5233 }
5234
5235
5236
5237 func etypesign(e types.Kind) int8 {
5238 switch e {
5239 case types.TINT8, types.TINT16, types.TINT32, types.TINT64, types.TINT:
5240 return -1
5241 case types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINT, types.TUINTPTR, types.TUNSAFEPTR:
5242 return +1
5243 }
5244 return 0
5245 }
5246
5247
5248
5249 func (s *state) addr(n ir.Node) *ssa.Value {
5250 if n.Op() != ir.ONAME {
5251 s.pushLine(n.Pos())
5252 defer s.popLine()
5253 }
5254
5255 if s.canSSA(n) {
5256
5257
5258
5259
5260
5261
5262
5263
5264 s.boundsCheckArrayIndex(n)
5265 return s.newValue1A(ssa.OpAddr, n.Type().PtrTo(), ir.Syms.Zerobase, s.sb)
5266 }
5267
5268 t := types.NewPtr(n.Type())
5269 linksymOffset := func(lsym *obj.LSym, offset int64) *ssa.Value {
5270 v := s.entryNewValue1A(ssa.OpAddr, t, lsym, s.sb)
5271
5272 if offset != 0 {
5273 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, offset, v)
5274 }
5275 return v
5276 }
5277 switch n.Op() {
5278 case ir.OLINKSYMOFFSET:
5279 no := n.(*ir.LinksymOffsetExpr)
5280 return linksymOffset(no.Linksym, no.Offset_)
5281 case ir.ONAME:
5282 n := n.(*ir.Name)
5283 if n.Heapaddr != nil {
5284 return s.expr(n.Heapaddr)
5285 }
5286 switch n.Class {
5287 case ir.PEXTERN:
5288
5289 return linksymOffset(n.Linksym(), 0)
5290 case ir.PPARAM:
5291
5292 v := s.decladdrs[n]
5293 if v != nil {
5294 return v
5295 }
5296 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
5297 return nil
5298 case ir.PAUTO:
5299 return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), !ir.IsAutoTmp(n))
5300
5301 case ir.PPARAMOUT:
5302
5303
5304 return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), true)
5305 default:
5306 s.Fatalf("variable address class %v not implemented", n.Class)
5307 return nil
5308 }
5309 case ir.ORESULT:
5310
5311 n := n.(*ir.ResultExpr)
5312 return s.resultAddrOfCall(s.prevCall, n.Index, n.Type())
5313 case ir.OINDEX:
5314 n := n.(*ir.IndexExpr)
5315 if n.X.Type().IsSlice() {
5316 a := s.expr(n.X)
5317 i := s.expr(n.Index)
5318 len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], a)
5319 i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
5320 p := s.newValue1(ssa.OpSlicePtr, t, a)
5321 return s.newValue2(ssa.OpPtrIndex, t, p, i)
5322 } else {
5323 a := s.addr(n.X)
5324 i := s.expr(n.Index)
5325 len := s.constInt(types.Types[types.TINT], n.X.Type().NumElem())
5326 i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
5327 return s.newValue2(ssa.OpPtrIndex, types.NewPtr(n.X.Type().Elem()), a, i)
5328 }
5329 case ir.ODEREF:
5330 n := n.(*ir.StarExpr)
5331 return s.exprPtr(n.X, n.Bounded(), n.Pos())
5332 case ir.ODOT:
5333 n := n.(*ir.SelectorExpr)
5334 p := s.addr(n.X)
5335 return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
5336 case ir.ODOTPTR:
5337 n := n.(*ir.SelectorExpr)
5338 p := s.exprPtr(n.X, n.Bounded(), n.Pos())
5339 return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
5340 case ir.OCONVNOP:
5341 n := n.(*ir.ConvExpr)
5342 if n.Type() == n.X.Type() {
5343 return s.addr(n.X)
5344 }
5345 addr := s.addr(n.X)
5346 return s.newValue1(ssa.OpCopy, t, addr)
5347 case ir.OCALLFUNC, ir.OCALLINTER:
5348 n := n.(*ir.CallExpr)
5349 return s.callAddr(n, callNormal)
5350 case ir.ODOTTYPE, ir.ODYNAMICDOTTYPE:
5351 var v *ssa.Value
5352 if n.Op() == ir.ODOTTYPE {
5353 v, _ = s.dottype(n.(*ir.TypeAssertExpr), false)
5354 } else {
5355 v, _ = s.dynamicDottype(n.(*ir.DynamicTypeAssertExpr), false)
5356 }
5357 if v.Op != ssa.OpLoad {
5358 s.Fatalf("dottype of non-load")
5359 }
5360 if v.Args[1] != s.mem() {
5361 s.Fatalf("memory no longer live from dottype load")
5362 }
5363 return v.Args[0]
5364 default:
5365 s.Fatalf("unhandled addr %v", n.Op())
5366 return nil
5367 }
5368 }
5369
5370
5371
5372 func (s *state) canSSA(n ir.Node) bool {
5373 if base.Flag.N != 0 {
5374 return false
5375 }
5376 for {
5377 nn := n
5378 if nn.Op() == ir.ODOT {
5379 nn := nn.(*ir.SelectorExpr)
5380 n = nn.X
5381 continue
5382 }
5383 if nn.Op() == ir.OINDEX {
5384 nn := nn.(*ir.IndexExpr)
5385 if nn.X.Type().IsArray() {
5386 n = nn.X
5387 continue
5388 }
5389 }
5390 break
5391 }
5392 if n.Op() != ir.ONAME {
5393 return false
5394 }
5395 return s.canSSAName(n.(*ir.Name)) && ssa.CanSSA(n.Type())
5396 }
5397
5398 func (s *state) canSSAName(name *ir.Name) bool {
5399 if name.Addrtaken() || !name.OnStack() {
5400 return false
5401 }
5402 switch name.Class {
5403 case ir.PPARAMOUT:
5404 if s.hasdefer {
5405
5406
5407
5408
5409
5410 return false
5411 }
5412 if s.cgoUnsafeArgs {
5413
5414
5415 return false
5416 }
5417 }
5418 return true
5419
5420 }
5421
5422
5423 func (s *state) exprPtr(n ir.Node, bounded bool, lineno src.XPos) *ssa.Value {
5424 p := s.expr(n)
5425 if bounded || n.NonNil() {
5426 if s.f.Frontend().Debug_checknil() && lineno.Line() > 1 {
5427 s.f.Warnl(lineno, "removed nil check")
5428 }
5429 return p
5430 }
5431 p = s.nilCheck(p)
5432 return p
5433 }
5434
5435
5436
5437
5438
5439
5440 func (s *state) nilCheck(ptr *ssa.Value) *ssa.Value {
5441 if base.Debug.DisableNil != 0 || s.curfn.NilCheckDisabled() {
5442 return ptr
5443 }
5444 return s.newValue2(ssa.OpNilCheck, ptr.Type, ptr, s.mem())
5445 }
5446
5447
5448 func (s *state) boundsCheckArrayIndex(n ir.Node) {
5449 if n.Op() != ir.OINDEX {
5450 return
5451 }
5452 nn := n.(*ir.IndexExpr)
5453 typ := nn.X.Type()
5454 if typ.IsArray() {
5455 _ = s.expr(nn.X)
5456 idx := s.expr(nn.Index)
5457 len := s.constInt(types.Types[types.TINT], typ.NumElem())
5458 s.boundsCheck(idx, len, ssa.BoundsIndex, nn.Bounded())
5459 }
5460 }
5461
5462
5463
5464
5465
5466
5467
5468 func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
5469 idx = s.extendIndex(idx, len, kind, bounded)
5470
5471 if bounded || base.Flag.B != 0 {
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492 return idx
5493 }
5494
5495 bNext := s.f.NewBlock(ssa.BlockPlain)
5496 bPanic := s.f.NewBlock(ssa.BlockExit)
5497
5498 if !idx.Type.IsSigned() {
5499 switch kind {
5500 case ssa.BoundsIndex:
5501 kind = ssa.BoundsIndexU
5502 case ssa.BoundsSliceAlen:
5503 kind = ssa.BoundsSliceAlenU
5504 case ssa.BoundsSliceAcap:
5505 kind = ssa.BoundsSliceAcapU
5506 case ssa.BoundsSliceB:
5507 kind = ssa.BoundsSliceBU
5508 case ssa.BoundsSlice3Alen:
5509 kind = ssa.BoundsSlice3AlenU
5510 case ssa.BoundsSlice3Acap:
5511 kind = ssa.BoundsSlice3AcapU
5512 case ssa.BoundsSlice3B:
5513 kind = ssa.BoundsSlice3BU
5514 case ssa.BoundsSlice3C:
5515 kind = ssa.BoundsSlice3CU
5516 }
5517 }
5518
5519 var cmp *ssa.Value
5520 if kind == ssa.BoundsIndex || kind == ssa.BoundsIndexU {
5521 cmp = s.newValue2(ssa.OpIsInBounds, types.Types[types.TBOOL], idx, len)
5522 } else {
5523 cmp = s.newValue2(ssa.OpIsSliceInBounds, types.Types[types.TBOOL], idx, len)
5524 }
5525 b := s.endBlock()
5526 b.Kind = ssa.BlockIf
5527 b.SetControl(cmp)
5528 b.Likely = ssa.BranchLikely
5529 b.AddEdgeTo(bNext)
5530 b.AddEdgeTo(bPanic)
5531
5532 s.startBlock(bPanic)
5533 if Arch.LinkArch.Family == sys.Wasm {
5534
5535
5536 s.rtcall(BoundsCheckFunc[kind], false, nil, idx, len)
5537 } else {
5538 mem := s.newValue3I(ssa.OpPanicBounds, types.TypeMem, int64(kind), idx, len, s.mem())
5539 s.endBlock().SetControl(mem)
5540 }
5541 s.startBlock(bNext)
5542
5543
5544 if base.Flag.Cfg.SpectreIndex {
5545 op := ssa.OpSpectreIndex
5546 if kind != ssa.BoundsIndex && kind != ssa.BoundsIndexU {
5547 op = ssa.OpSpectreSliceIndex
5548 }
5549 idx = s.newValue2(op, types.Types[types.TINT], idx, len)
5550 }
5551
5552 return idx
5553 }
5554
5555
5556 func (s *state) check(cmp *ssa.Value, fn *obj.LSym) {
5557 b := s.endBlock()
5558 b.Kind = ssa.BlockIf
5559 b.SetControl(cmp)
5560 b.Likely = ssa.BranchLikely
5561 bNext := s.f.NewBlock(ssa.BlockPlain)
5562 line := s.peekPos()
5563 pos := base.Ctxt.PosTable.Pos(line)
5564 fl := funcLine{f: fn, base: pos.Base(), line: pos.Line()}
5565 bPanic := s.panics[fl]
5566 if bPanic == nil {
5567 bPanic = s.f.NewBlock(ssa.BlockPlain)
5568 s.panics[fl] = bPanic
5569 s.startBlock(bPanic)
5570
5571
5572 s.rtcall(fn, false, nil)
5573 }
5574 b.AddEdgeTo(bNext)
5575 b.AddEdgeTo(bPanic)
5576 s.startBlock(bNext)
5577 }
5578
5579 func (s *state) intDivide(n ir.Node, a, b *ssa.Value) *ssa.Value {
5580 needcheck := true
5581 switch b.Op {
5582 case ssa.OpConst8, ssa.OpConst16, ssa.OpConst32, ssa.OpConst64:
5583 if b.AuxInt != 0 {
5584 needcheck = false
5585 }
5586 }
5587 if needcheck {
5588
5589 cmp := s.newValue2(s.ssaOp(ir.ONE, n.Type()), types.Types[types.TBOOL], b, s.zeroVal(n.Type()))
5590 s.check(cmp, ir.Syms.Panicdivide)
5591 }
5592 return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
5593 }
5594
5595
5596
5597
5598
5599 func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args ...*ssa.Value) []*ssa.Value {
5600 s.prevCall = nil
5601
5602 off := base.Ctxt.Arch.FixedFrameSize
5603 var callArgs []*ssa.Value
5604 var callArgTypes []*types.Type
5605
5606 for _, arg := range args {
5607 t := arg.Type
5608 off = types.RoundUp(off, t.Alignment())
5609 size := t.Size()
5610 callArgs = append(callArgs, arg)
5611 callArgTypes = append(callArgTypes, t)
5612 off += size
5613 }
5614 off = types.RoundUp(off, int64(types.RegSize))
5615
5616
5617 var call *ssa.Value
5618 aux := ssa.StaticAuxCall(fn, s.f.ABIDefault.ABIAnalyzeTypes(callArgTypes, results))
5619 callArgs = append(callArgs, s.mem())
5620 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5621 call.AddArgs(callArgs...)
5622 s.vars[memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(results)), call)
5623
5624 if !returns {
5625
5626 b := s.endBlock()
5627 b.Kind = ssa.BlockExit
5628 b.SetControl(call)
5629 call.AuxInt = off - base.Ctxt.Arch.FixedFrameSize
5630 if len(results) > 0 {
5631 s.Fatalf("panic call can't have results")
5632 }
5633 return nil
5634 }
5635
5636
5637 res := make([]*ssa.Value, len(results))
5638 for i, t := range results {
5639 off = types.RoundUp(off, t.Alignment())
5640 res[i] = s.resultOfCall(call, int64(i), t)
5641 off += t.Size()
5642 }
5643 off = types.RoundUp(off, int64(types.PtrSize))
5644
5645
5646 call.AuxInt = off
5647
5648 return res
5649 }
5650
5651
5652 func (s *state) storeType(t *types.Type, left, right *ssa.Value, skip skipMask, leftIsStmt bool) {
5653 s.instrument(t, left, instrumentWrite)
5654
5655 if skip == 0 && (!t.HasPointers() || ssa.IsStackAddr(left)) {
5656
5657 s.vars[memVar] = s.newValue3Apos(ssa.OpStore, types.TypeMem, t, left, right, s.mem(), leftIsStmt)
5658 return
5659 }
5660
5661
5662
5663
5664
5665
5666 s.storeTypeScalars(t, left, right, skip)
5667 if skip&skipPtr == 0 && t.HasPointers() {
5668 s.storeTypePtrs(t, left, right)
5669 }
5670 }
5671
5672
5673 func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip skipMask) {
5674 switch {
5675 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex() || t.IsSIMD():
5676 s.store(t, left, right)
5677 case t.IsPtrShaped():
5678 if t.IsPtr() && t.Elem().NotInHeap() {
5679 s.store(t, left, right)
5680 }
5681
5682 case t.IsString():
5683 if skip&skipLen != 0 {
5684 return
5685 }
5686 len := s.newValue1(ssa.OpStringLen, types.Types[types.TINT], right)
5687 lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
5688 s.store(types.Types[types.TINT], lenAddr, len)
5689 case t.IsSlice():
5690 if skip&skipLen == 0 {
5691 len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], right)
5692 lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
5693 s.store(types.Types[types.TINT], lenAddr, len)
5694 }
5695 if skip&skipCap == 0 {
5696 cap := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], right)
5697 capAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, 2*s.config.PtrSize, left)
5698 s.store(types.Types[types.TINT], capAddr, cap)
5699 }
5700 case t.IsInterface():
5701
5702 itab := s.newValue1(ssa.OpITab, s.f.Config.Types.BytePtr, right)
5703 s.store(types.Types[types.TUINTPTR], left, itab)
5704 case isStructNotSIMD(t):
5705 n := t.NumFields()
5706 for i := 0; i < n; i++ {
5707 ft := t.FieldType(i)
5708 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
5709 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
5710 s.storeTypeScalars(ft, addr, val, 0)
5711 }
5712 case t.IsArray() && t.Size() == 0:
5713
5714 case t.IsArray() && t.NumElem() == 1:
5715 s.storeTypeScalars(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right), 0)
5716 default:
5717 s.Fatalf("bad write barrier type %v", t)
5718 }
5719 }
5720
5721
5722 func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
5723 switch {
5724 case t.IsPtrShaped():
5725 if t.IsPtr() && t.Elem().NotInHeap() {
5726 break
5727 }
5728 s.store(t, left, right)
5729 case t.IsString():
5730 ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right)
5731 s.store(s.f.Config.Types.BytePtr, left, ptr)
5732 case t.IsSlice():
5733 elType := types.NewPtr(t.Elem())
5734 ptr := s.newValue1(ssa.OpSlicePtr, elType, right)
5735 s.store(elType, left, ptr)
5736 case t.IsInterface():
5737
5738 idata := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, right)
5739 idataAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.BytePtrPtr, s.config.PtrSize, left)
5740 s.store(s.f.Config.Types.BytePtr, idataAddr, idata)
5741 case isStructNotSIMD(t):
5742 n := t.NumFields()
5743 for i := 0; i < n; i++ {
5744 ft := t.FieldType(i)
5745 if !ft.HasPointers() {
5746 continue
5747 }
5748 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
5749 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
5750 s.storeTypePtrs(ft, addr, val)
5751 }
5752 case t.IsArray() && t.Size() == 0:
5753
5754 case t.IsArray() && t.NumElem() == 1:
5755 s.storeTypePtrs(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right))
5756 default:
5757 s.Fatalf("bad write barrier type %v", t)
5758 }
5759 }
5760
5761
5762 func (s *state) putArg(n ir.Node, t *types.Type) *ssa.Value {
5763 var a *ssa.Value
5764 if !ssa.CanSSA(t) {
5765 a = s.newValue2(ssa.OpDereference, t, s.addr(n), s.mem())
5766 } else {
5767 a = s.expr(n)
5768 }
5769 return a
5770 }
5771
5772
5773
5774
5775 func (s *state) slice(v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value) {
5776 t := v.Type
5777 var ptr, len, cap *ssa.Value
5778 switch {
5779 case t.IsSlice():
5780 ptr = s.newValue1(ssa.OpSlicePtr, types.NewPtr(t.Elem()), v)
5781 len = s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], v)
5782 cap = s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], v)
5783 case t.IsString():
5784 ptr = s.newValue1(ssa.OpStringPtr, types.NewPtr(types.Types[types.TUINT8]), v)
5785 len = s.newValue1(ssa.OpStringLen, types.Types[types.TINT], v)
5786 cap = len
5787 case t.IsPtr():
5788 if !t.Elem().IsArray() {
5789 s.Fatalf("bad ptr to array in slice %v\n", t)
5790 }
5791 nv := s.nilCheck(v)
5792 ptr = s.newValue1(ssa.OpCopy, types.NewPtr(t.Elem().Elem()), nv)
5793 len = s.constInt(types.Types[types.TINT], t.Elem().NumElem())
5794 cap = len
5795 default:
5796 s.Fatalf("bad type in slice %v\n", t)
5797 }
5798
5799
5800 if i == nil {
5801 i = s.constInt(types.Types[types.TINT], 0)
5802 }
5803 if j == nil {
5804 j = len
5805 }
5806 three := true
5807 if k == nil {
5808 three = false
5809 k = cap
5810 }
5811
5812
5813
5814
5815 if three {
5816 if k != cap {
5817 kind := ssa.BoundsSlice3Alen
5818 if t.IsSlice() {
5819 kind = ssa.BoundsSlice3Acap
5820 }
5821 k = s.boundsCheck(k, cap, kind, bounded)
5822 }
5823 if j != k {
5824 j = s.boundsCheck(j, k, ssa.BoundsSlice3B, bounded)
5825 }
5826 i = s.boundsCheck(i, j, ssa.BoundsSlice3C, bounded)
5827 } else {
5828 if j != k {
5829 kind := ssa.BoundsSliceAlen
5830 if t.IsSlice() {
5831 kind = ssa.BoundsSliceAcap
5832 }
5833 j = s.boundsCheck(j, k, kind, bounded)
5834 }
5835 i = s.boundsCheck(i, j, ssa.BoundsSliceB, bounded)
5836 }
5837
5838
5839 subOp := s.ssaOp(ir.OSUB, types.Types[types.TINT])
5840 mulOp := s.ssaOp(ir.OMUL, types.Types[types.TINT])
5841 andOp := s.ssaOp(ir.OAND, types.Types[types.TINT])
5842
5843
5844
5845
5846
5847 rlen := s.newValue2(subOp, types.Types[types.TINT], j, i)
5848 rcap := rlen
5849 if j != k && !t.IsString() {
5850 rcap = s.newValue2(subOp, types.Types[types.TINT], k, i)
5851 }
5852
5853 if (i.Op == ssa.OpConst64 || i.Op == ssa.OpConst32) && i.AuxInt == 0 {
5854
5855 return ptr, rlen, rcap
5856 }
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872 stride := s.constInt(types.Types[types.TINT], ptr.Type.Elem().Size())
5873
5874
5875 delta := s.newValue2(mulOp, types.Types[types.TINT], i, stride)
5876
5877
5878
5879 mask := s.newValue1(ssa.OpSlicemask, types.Types[types.TINT], rcap)
5880 delta = s.newValue2(andOp, types.Types[types.TINT], delta, mask)
5881
5882
5883 rptr := s.newValue2(ssa.OpAddPtr, ptr.Type, ptr, delta)
5884
5885 return rptr, rlen, rcap
5886 }
5887
5888 type u642fcvtTab struct {
5889 leq, cvt2F, and, rsh, or, add ssa.Op
5890 one func(*state, *types.Type, int64) *ssa.Value
5891 }
5892
5893 var u64_f64 = u642fcvtTab{
5894 leq: ssa.OpLeq64,
5895 cvt2F: ssa.OpCvt64to64F,
5896 and: ssa.OpAnd64,
5897 rsh: ssa.OpRsh64Ux64,
5898 or: ssa.OpOr64,
5899 add: ssa.OpAdd64F,
5900 one: (*state).constInt64,
5901 }
5902
5903 var u64_f32 = u642fcvtTab{
5904 leq: ssa.OpLeq64,
5905 cvt2F: ssa.OpCvt64to32F,
5906 and: ssa.OpAnd64,
5907 rsh: ssa.OpRsh64Ux64,
5908 or: ssa.OpOr64,
5909 add: ssa.OpAdd32F,
5910 one: (*state).constInt64,
5911 }
5912
5913 func (s *state) uint64Tofloat64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5914 return s.uint64Tofloat(&u64_f64, n, x, ft, tt)
5915 }
5916
5917 func (s *state) uint64Tofloat32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5918 return s.uint64Tofloat(&u64_f32, n, x, ft, tt)
5919 }
5920
5921 func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947 cmp := s.newValue2(cvttab.leq, types.Types[types.TBOOL], s.zeroVal(ft), x)
5948
5949 b := s.endBlock()
5950 b.Kind = ssa.BlockIf
5951 b.SetControl(cmp)
5952 b.Likely = ssa.BranchLikely
5953
5954 bThen := s.f.NewBlock(ssa.BlockPlain)
5955 bElse := s.f.NewBlock(ssa.BlockPlain)
5956 bAfter := s.f.NewBlock(ssa.BlockPlain)
5957
5958 b.AddEdgeTo(bThen)
5959 s.startBlock(bThen)
5960 a0 := s.newValue1(cvttab.cvt2F, tt, x)
5961 s.vars[n] = a0
5962 s.endBlock()
5963 bThen.AddEdgeTo(bAfter)
5964
5965 b.AddEdgeTo(bElse)
5966 s.startBlock(bElse)
5967 one := cvttab.one(s, ft, 1)
5968 y := s.newValue2(cvttab.and, ft, x, one)
5969 z := s.newValue2(cvttab.rsh, ft, x, one)
5970 z = s.newValue2(cvttab.or, ft, z, y)
5971 a := s.newValue1(cvttab.cvt2F, tt, z)
5972 a1 := s.newValue2(cvttab.add, tt, a, a)
5973 s.vars[n] = a1
5974 s.endBlock()
5975 bElse.AddEdgeTo(bAfter)
5976
5977 s.startBlock(bAfter)
5978 return s.variable(n, n.Type())
5979 }
5980
5981 type u322fcvtTab struct {
5982 cvtI2F, cvtF2F ssa.Op
5983 }
5984
5985 var u32_f64 = u322fcvtTab{
5986 cvtI2F: ssa.OpCvt32to64F,
5987 cvtF2F: ssa.OpCopy,
5988 }
5989
5990 var u32_f32 = u322fcvtTab{
5991 cvtI2F: ssa.OpCvt32to32F,
5992 cvtF2F: ssa.OpCvt64Fto32F,
5993 }
5994
5995 func (s *state) uint32Tofloat64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5996 return s.uint32Tofloat(&u32_f64, n, x, ft, tt)
5997 }
5998
5999 func (s *state) uint32Tofloat32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6000 return s.uint32Tofloat(&u32_f32, n, x, ft, tt)
6001 }
6002
6003 func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6004
6005
6006
6007
6008
6009 cmp := s.newValue2(ssa.OpLeq32, types.Types[types.TBOOL], s.zeroVal(ft), x)
6010 b := s.endBlock()
6011 b.Kind = ssa.BlockIf
6012 b.SetControl(cmp)
6013 b.Likely = ssa.BranchLikely
6014
6015 bThen := s.f.NewBlock(ssa.BlockPlain)
6016 bElse := s.f.NewBlock(ssa.BlockPlain)
6017 bAfter := s.f.NewBlock(ssa.BlockPlain)
6018
6019 b.AddEdgeTo(bThen)
6020 s.startBlock(bThen)
6021 a0 := s.newValue1(cvttab.cvtI2F, tt, x)
6022 s.vars[n] = a0
6023 s.endBlock()
6024 bThen.AddEdgeTo(bAfter)
6025
6026 b.AddEdgeTo(bElse)
6027 s.startBlock(bElse)
6028 a1 := s.newValue1(ssa.OpCvt32to64F, types.Types[types.TFLOAT64], x)
6029 twoToThe32 := s.constFloat64(types.Types[types.TFLOAT64], float64(1<<32))
6030 a2 := s.newValue2(ssa.OpAdd64F, types.Types[types.TFLOAT64], a1, twoToThe32)
6031 a3 := s.newValue1(cvttab.cvtF2F, tt, a2)
6032
6033 s.vars[n] = a3
6034 s.endBlock()
6035 bElse.AddEdgeTo(bAfter)
6036
6037 s.startBlock(bAfter)
6038 return s.variable(n, n.Type())
6039 }
6040
6041
6042 func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
6043 if !n.X.Type().IsMap() && !n.X.Type().IsChan() {
6044 s.Fatalf("node must be a map or a channel")
6045 }
6046 if n.X.Type().IsChan() && n.Op() == ir.OLEN {
6047 s.Fatalf("cannot inline len(chan)")
6048 }
6049 if n.X.Type().IsChan() && n.Op() == ir.OCAP {
6050 s.Fatalf("cannot inline cap(chan)")
6051 }
6052 if n.X.Type().IsMap() && n.Op() == ir.OCAP {
6053 s.Fatalf("cannot inline cap(map)")
6054 }
6055
6056
6057
6058
6059
6060
6061
6062
6063 lenType := n.Type()
6064 nilValue := s.constNil(types.Types[types.TUINTPTR])
6065 cmp := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], x, nilValue)
6066 b := s.endBlock()
6067 b.Kind = ssa.BlockIf
6068 b.SetControl(cmp)
6069 b.Likely = ssa.BranchUnlikely
6070
6071 bThen := s.f.NewBlock(ssa.BlockPlain)
6072 bElse := s.f.NewBlock(ssa.BlockPlain)
6073 bAfter := s.f.NewBlock(ssa.BlockPlain)
6074
6075
6076 b.AddEdgeTo(bThen)
6077 s.startBlock(bThen)
6078 s.vars[n] = s.zeroVal(lenType)
6079 s.endBlock()
6080 bThen.AddEdgeTo(bAfter)
6081
6082 b.AddEdgeTo(bElse)
6083 s.startBlock(bElse)
6084 switch n.Op() {
6085 case ir.OLEN:
6086 if n.X.Type().IsMap() {
6087
6088 loadType := reflectdata.MapType().Field(0).Type
6089 load := s.load(loadType, x)
6090 s.vars[n] = s.conv(nil, load, loadType, lenType)
6091 } else {
6092
6093 s.vars[n] = s.load(lenType, x)
6094 }
6095 case ir.OCAP:
6096
6097 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Size(), x)
6098 s.vars[n] = s.load(lenType, sw)
6099 default:
6100 s.Fatalf("op must be OLEN or OCAP")
6101 }
6102 s.endBlock()
6103 bElse.AddEdgeTo(bAfter)
6104
6105 s.startBlock(bAfter)
6106 return s.variable(n, lenType)
6107 }
6108
6109 type f2uCvtTab struct {
6110 ltf, cvt2U, subf, or ssa.Op
6111 floatValue func(*state, *types.Type, float64) *ssa.Value
6112 intValue func(*state, *types.Type, int64) *ssa.Value
6113 cutoff uint64
6114 }
6115
6116 var f32_u64 = f2uCvtTab{
6117 ltf: ssa.OpLess32F,
6118 cvt2U: ssa.OpCvt32Fto64,
6119 subf: ssa.OpSub32F,
6120 or: ssa.OpOr64,
6121 floatValue: (*state).constFloat32,
6122 intValue: (*state).constInt64,
6123 cutoff: 1 << 63,
6124 }
6125
6126 var f64_u64 = f2uCvtTab{
6127 ltf: ssa.OpLess64F,
6128 cvt2U: ssa.OpCvt64Fto64,
6129 subf: ssa.OpSub64F,
6130 or: ssa.OpOr64,
6131 floatValue: (*state).constFloat64,
6132 intValue: (*state).constInt64,
6133 cutoff: 1 << 63,
6134 }
6135
6136 var f32_u32 = f2uCvtTab{
6137 ltf: ssa.OpLess32F,
6138 cvt2U: ssa.OpCvt32Fto32,
6139 subf: ssa.OpSub32F,
6140 or: ssa.OpOr32,
6141 floatValue: (*state).constFloat32,
6142 intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
6143 cutoff: 1 << 31,
6144 }
6145
6146 var f64_u32 = f2uCvtTab{
6147 ltf: ssa.OpLess64F,
6148 cvt2U: ssa.OpCvt64Fto32,
6149 subf: ssa.OpSub64F,
6150 or: ssa.OpOr32,
6151 floatValue: (*state).constFloat64,
6152 intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
6153 cutoff: 1 << 31,
6154 }
6155
6156 func (s *state) float32ToUint64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6157 return s.floatToUint(&f32_u64, n, x, ft, tt)
6158 }
6159 func (s *state) float64ToUint64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6160 return s.floatToUint(&f64_u64, n, x, ft, tt)
6161 }
6162
6163 func (s *state) float32ToUint32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6164 return s.floatToUint(&f32_u32, n, x, ft, tt)
6165 }
6166
6167 func (s *state) float64ToUint32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6168 return s.floatToUint(&f64_u32, n, x, ft, tt)
6169 }
6170
6171 func (s *state) floatToUint(cvttab *f2uCvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185 cutoff := cvttab.floatValue(s, ft, float64(cvttab.cutoff))
6186 cmp := s.newValueOrSfCall2(cvttab.ltf, types.Types[types.TBOOL], x, cutoff)
6187 b := s.endBlock()
6188 b.Kind = ssa.BlockIf
6189 b.SetControl(cmp)
6190 b.Likely = ssa.BranchLikely
6191
6192 var bThen, bZero *ssa.Block
6193
6194 newConversion := base.ConvertHash.MatchPosWithInfo(n.Pos(), "U", nil)
6195 if newConversion {
6196 bZero = s.f.NewBlock(ssa.BlockPlain)
6197 bThen = s.f.NewBlock(ssa.BlockIf)
6198 } else {
6199 bThen = s.f.NewBlock(ssa.BlockPlain)
6200 }
6201
6202 bElse := s.f.NewBlock(ssa.BlockPlain)
6203 bAfter := s.f.NewBlock(ssa.BlockPlain)
6204
6205 b.AddEdgeTo(bThen)
6206 s.startBlock(bThen)
6207 a0 := s.newValueOrSfCall1(cvttab.cvt2U, tt, x)
6208 s.vars[n] = a0
6209
6210 if newConversion {
6211 cmpz := s.newValueOrSfCall2(cvttab.ltf, types.Types[types.TBOOL], x, cvttab.floatValue(s, ft, 0.0))
6212 s.endBlock()
6213 bThen.SetControl(cmpz)
6214 bThen.AddEdgeTo(bZero)
6215 bThen.Likely = ssa.BranchUnlikely
6216 bThen.AddEdgeTo(bAfter)
6217
6218 s.startBlock(bZero)
6219 s.vars[n] = cvttab.intValue(s, tt, 0)
6220 s.endBlock()
6221 bZero.AddEdgeTo(bAfter)
6222 } else {
6223 s.endBlock()
6224 bThen.AddEdgeTo(bAfter)
6225 }
6226
6227 b.AddEdgeTo(bElse)
6228 s.startBlock(bElse)
6229 y := s.newValueOrSfCall2(cvttab.subf, ft, x, cutoff)
6230 y = s.newValueOrSfCall1(cvttab.cvt2U, tt, y)
6231 z := cvttab.intValue(s, tt, int64(-cvttab.cutoff))
6232 a1 := s.newValue2(cvttab.or, tt, y, z)
6233 s.vars[n] = a1
6234 s.endBlock()
6235 bElse.AddEdgeTo(bAfter)
6236
6237 s.startBlock(bAfter)
6238 return s.variable(n, n.Type())
6239 }
6240
6241
6242
6243
6244 func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
6245 iface := s.expr(n.X)
6246 target := s.reflectType(n.Type())
6247 var targetItab *ssa.Value
6248 if n.ITab != nil {
6249 targetItab = s.expr(n.ITab)
6250 }
6251
6252 if n.UseNilPanic {
6253 if commaok {
6254 base.Fatalf("unexpected *ir.TypeAssertExpr with UseNilPanic == true && commaok == true")
6255 }
6256 if n.Type().IsInterface() {
6257
6258
6259 base.Fatalf("unexpected *ir.TypeAssertExpr with UseNilPanic == true && Type().IsInterface() == true")
6260 }
6261 typs := s.f.Config.Types
6262 iface = s.newValue2(
6263 ssa.OpIMake,
6264 iface.Type,
6265 s.nilCheck(s.newValue1(ssa.OpITab, typs.BytePtr, iface)),
6266 s.newValue1(ssa.OpIData, typs.BytePtr, iface),
6267 )
6268 }
6269
6270 return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, nil, target, targetItab, commaok, n.Descriptor)
6271 }
6272
6273 func (s *state) dynamicDottype(n *ir.DynamicTypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
6274 iface := s.expr(n.X)
6275 var source, target, targetItab *ssa.Value
6276 if n.SrcRType != nil {
6277 source = s.expr(n.SrcRType)
6278 }
6279 if !n.X.Type().IsEmptyInterface() && !n.Type().IsInterface() {
6280 byteptr := s.f.Config.Types.BytePtr
6281 targetItab = s.expr(n.ITab)
6282
6283
6284 target = s.load(byteptr, s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), targetItab))
6285 } else {
6286 target = s.expr(n.RType)
6287 }
6288 return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, source, target, targetItab, commaok, nil)
6289 }
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299 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) {
6300 typs := s.f.Config.Types
6301 byteptr := typs.BytePtr
6302 if dst.IsInterface() {
6303 if dst.IsEmptyInterface() {
6304
6305
6306 if base.Debug.TypeAssert > 0 {
6307 base.WarnfAt(pos, "type assertion inlined")
6308 }
6309
6310
6311 itab := s.newValue1(ssa.OpITab, byteptr, iface)
6312
6313 cond := s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6314
6315 if src.IsEmptyInterface() && commaok {
6316
6317 return iface, cond
6318 }
6319
6320
6321 b := s.endBlock()
6322 b.Kind = ssa.BlockIf
6323 b.SetControl(cond)
6324 b.Likely = ssa.BranchLikely
6325 bOk := s.f.NewBlock(ssa.BlockPlain)
6326 bFail := s.f.NewBlock(ssa.BlockPlain)
6327 b.AddEdgeTo(bOk)
6328 b.AddEdgeTo(bFail)
6329
6330 if !commaok {
6331
6332 s.startBlock(bFail)
6333 s.rtcall(ir.Syms.Panicnildottype, false, nil, target)
6334
6335
6336 s.startBlock(bOk)
6337 if src.IsEmptyInterface() {
6338 res = iface
6339 return
6340 }
6341
6342 off := s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab)
6343 typ := s.load(byteptr, off)
6344 idata := s.newValue1(ssa.OpIData, byteptr, iface)
6345 res = s.newValue2(ssa.OpIMake, dst, typ, idata)
6346 return
6347 }
6348
6349 s.startBlock(bOk)
6350
6351
6352 off := s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab)
6353 s.vars[typVar] = s.load(byteptr, off)
6354 s.endBlock()
6355
6356
6357 s.startBlock(bFail)
6358 s.vars[typVar] = itab
6359 s.endBlock()
6360
6361
6362 bEnd := s.f.NewBlock(ssa.BlockPlain)
6363 bOk.AddEdgeTo(bEnd)
6364 bFail.AddEdgeTo(bEnd)
6365 s.startBlock(bEnd)
6366 idata := s.newValue1(ssa.OpIData, byteptr, iface)
6367 res = s.newValue2(ssa.OpIMake, dst, s.variable(typVar, byteptr), idata)
6368 resok = cond
6369 delete(s.vars, typVar)
6370 return
6371 }
6372
6373 if base.Debug.TypeAssert > 0 {
6374 base.WarnfAt(pos, "type assertion not inlined")
6375 }
6376
6377 itab := s.newValue1(ssa.OpITab, byteptr, iface)
6378 data := s.newValue1(ssa.OpIData, types.Types[types.TUNSAFEPTR], iface)
6379
6380
6381 bNil := s.f.NewBlock(ssa.BlockPlain)
6382 bNonNil := s.f.NewBlock(ssa.BlockPlain)
6383 bMerge := s.f.NewBlock(ssa.BlockPlain)
6384 cond := s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6385 b := s.endBlock()
6386 b.Kind = ssa.BlockIf
6387 b.SetControl(cond)
6388 b.Likely = ssa.BranchLikely
6389 b.AddEdgeTo(bNonNil)
6390 b.AddEdgeTo(bNil)
6391
6392 s.startBlock(bNil)
6393 if commaok {
6394 s.vars[typVar] = itab
6395 b := s.endBlock()
6396 b.AddEdgeTo(bMerge)
6397 } else {
6398
6399 s.rtcall(ir.Syms.Panicnildottype, false, nil, target)
6400 }
6401
6402
6403 s.startBlock(bNonNil)
6404 typ := itab
6405 if !src.IsEmptyInterface() {
6406 typ = s.load(byteptr, s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab))
6407 }
6408
6409
6410 var d *ssa.Value
6411 if descriptor != nil {
6412 d = s.newValue1A(ssa.OpAddr, byteptr, descriptor, s.sb)
6413 if base.Flag.N == 0 && rtabi.UseInterfaceSwitchCache(Arch.LinkArch.Family) {
6414
6415
6416 if intrinsics.lookup(Arch.LinkArch.Arch, "internal/runtime/atomic", "Loadp") == nil {
6417 s.Fatalf("atomic load not available")
6418 }
6419
6420 var mul, and, add, zext ssa.Op
6421 if s.config.PtrSize == 4 {
6422 mul = ssa.OpMul32
6423 and = ssa.OpAnd32
6424 add = ssa.OpAdd32
6425 zext = ssa.OpCopy
6426 } else {
6427 mul = ssa.OpMul64
6428 and = ssa.OpAnd64
6429 add = ssa.OpAdd64
6430 zext = ssa.OpZeroExt32to64
6431 }
6432
6433 loopHead := s.f.NewBlock(ssa.BlockPlain)
6434 loopBody := s.f.NewBlock(ssa.BlockPlain)
6435 cacheHit := s.f.NewBlock(ssa.BlockPlain)
6436 cacheMiss := s.f.NewBlock(ssa.BlockPlain)
6437
6438
6439
6440 atomicLoad := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(typs.BytePtr, types.TypeMem), d, s.mem())
6441 cache := s.newValue1(ssa.OpSelect0, typs.BytePtr, atomicLoad)
6442 s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, atomicLoad)
6443
6444
6445 var hash *ssa.Value
6446 if src.IsEmptyInterface() {
6447 hash = s.newValue2(ssa.OpLoad, typs.UInt32, s.newValue1I(ssa.OpOffPtr, typs.UInt32Ptr, rttype.Type.OffsetOf("Hash"), typ), s.mem())
6448 } else {
6449 hash = s.newValue2(ssa.OpLoad, typs.UInt32, s.newValue1I(ssa.OpOffPtr, typs.UInt32Ptr, rttype.ITab.OffsetOf("Hash"), itab), s.mem())
6450 }
6451 hash = s.newValue1(zext, typs.Uintptr, hash)
6452 s.vars[hashVar] = hash
6453
6454 mask := s.newValue2(ssa.OpLoad, typs.Uintptr, cache, s.mem())
6455
6456 b := s.endBlock()
6457 b.AddEdgeTo(loopHead)
6458
6459
6460
6461 s.startBlock(loopHead)
6462 idx := s.newValue2(and, typs.Uintptr, s.variable(hashVar, typs.Uintptr), mask)
6463 idx = s.newValue2(mul, typs.Uintptr, idx, s.uintptrConstant(uint64(2*s.config.PtrSize)))
6464 idx = s.newValue2(add, typs.Uintptr, idx, s.uintptrConstant(uint64(s.config.PtrSize)))
6465 e := s.newValue2(ssa.OpAddPtr, typs.UintptrPtr, cache, idx)
6466
6467 s.vars[hashVar] = s.newValue2(add, typs.Uintptr, s.variable(hashVar, typs.Uintptr), s.uintptrConstant(1))
6468
6469
6470
6471 eTyp := s.newValue2(ssa.OpLoad, typs.Uintptr, e, s.mem())
6472 cmp1 := s.newValue2(ssa.OpEqPtr, typs.Bool, typ, eTyp)
6473 b = s.endBlock()
6474 b.Kind = ssa.BlockIf
6475 b.SetControl(cmp1)
6476 b.AddEdgeTo(cacheHit)
6477 b.AddEdgeTo(loopBody)
6478
6479
6480
6481 s.startBlock(loopBody)
6482 cmp2 := s.newValue2(ssa.OpEqPtr, typs.Bool, eTyp, s.constNil(typs.BytePtr))
6483 b = s.endBlock()
6484 b.Kind = ssa.BlockIf
6485 b.SetControl(cmp2)
6486 b.AddEdgeTo(cacheMiss)
6487 b.AddEdgeTo(loopHead)
6488
6489
6490
6491 s.startBlock(cacheHit)
6492 eItab := s.newValue2(ssa.OpLoad, typs.BytePtr, s.newValue1I(ssa.OpOffPtr, typs.BytePtrPtr, s.config.PtrSize, e), s.mem())
6493 s.vars[typVar] = eItab
6494 b = s.endBlock()
6495 b.AddEdgeTo(bMerge)
6496
6497
6498 s.startBlock(cacheMiss)
6499 }
6500 }
6501
6502
6503 if descriptor != nil {
6504 itab = s.rtcall(ir.Syms.TypeAssert, true, []*types.Type{byteptr}, d, typ)[0]
6505 } else {
6506 var fn *obj.LSym
6507 if commaok {
6508 fn = ir.Syms.AssertE2I2
6509 } else {
6510 fn = ir.Syms.AssertE2I
6511 }
6512 itab = s.rtcall(fn, true, []*types.Type{byteptr}, target, typ)[0]
6513 }
6514 s.vars[typVar] = itab
6515 b = s.endBlock()
6516 b.AddEdgeTo(bMerge)
6517
6518
6519 s.startBlock(bMerge)
6520 itab = s.variable(typVar, byteptr)
6521 var ok *ssa.Value
6522 if commaok {
6523 ok = s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6524 }
6525 return s.newValue2(ssa.OpIMake, dst, itab, data), ok
6526 }
6527
6528 if base.Debug.TypeAssert > 0 {
6529 base.WarnfAt(pos, "type assertion inlined")
6530 }
6531
6532
6533 direct := types.IsDirectIface(dst)
6534 itab := s.newValue1(ssa.OpITab, byteptr, iface)
6535 if base.Debug.TypeAssert > 0 {
6536 base.WarnfAt(pos, "type assertion inlined")
6537 }
6538 var wantedFirstWord *ssa.Value
6539 if src.IsEmptyInterface() {
6540
6541 wantedFirstWord = target
6542 } else {
6543
6544 wantedFirstWord = targetItab
6545 }
6546
6547 var tmp ir.Node
6548 var addr *ssa.Value
6549 if commaok && !ssa.CanSSA(dst) {
6550
6551
6552 tmp, addr = s.temp(pos, dst)
6553 }
6554
6555 cond := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], itab, wantedFirstWord)
6556 b := s.endBlock()
6557 b.Kind = ssa.BlockIf
6558 b.SetControl(cond)
6559 b.Likely = ssa.BranchLikely
6560
6561 bOk := s.f.NewBlock(ssa.BlockPlain)
6562 bFail := s.f.NewBlock(ssa.BlockPlain)
6563 b.AddEdgeTo(bOk)
6564 b.AddEdgeTo(bFail)
6565
6566 if !commaok {
6567
6568 s.startBlock(bFail)
6569 taddr := source
6570 if taddr == nil {
6571 taddr = s.reflectType(src)
6572 }
6573 if src.IsEmptyInterface() {
6574 s.rtcall(ir.Syms.PanicdottypeE, false, nil, itab, target, taddr)
6575 } else {
6576 s.rtcall(ir.Syms.PanicdottypeI, false, nil, itab, target, taddr)
6577 }
6578
6579
6580 s.startBlock(bOk)
6581 if direct {
6582 return s.newValue1(ssa.OpIData, dst, iface), nil
6583 }
6584 p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
6585 return s.load(dst, p), nil
6586 }
6587
6588
6589
6590 bEnd := s.f.NewBlock(ssa.BlockPlain)
6591
6592
6593 valVar := ssaMarker("val")
6594
6595
6596 s.startBlock(bOk)
6597 if tmp == nil {
6598 if direct {
6599 s.vars[valVar] = s.newValue1(ssa.OpIData, dst, iface)
6600 } else {
6601 p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
6602 s.vars[valVar] = s.load(dst, p)
6603 }
6604 } else {
6605 p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
6606 s.move(dst, addr, p)
6607 }
6608 s.vars[okVar] = s.constBool(true)
6609 s.endBlock()
6610 bOk.AddEdgeTo(bEnd)
6611
6612
6613 s.startBlock(bFail)
6614 if tmp == nil {
6615 s.vars[valVar] = s.zeroVal(dst)
6616 } else {
6617 s.zero(dst, addr)
6618 }
6619 s.vars[okVar] = s.constBool(false)
6620 s.endBlock()
6621 bFail.AddEdgeTo(bEnd)
6622
6623
6624 s.startBlock(bEnd)
6625 if tmp == nil {
6626 res = s.variable(valVar, dst)
6627 delete(s.vars, valVar)
6628 } else {
6629 res = s.load(dst, addr)
6630 }
6631 resok = s.variable(okVar, types.Types[types.TBOOL])
6632 delete(s.vars, okVar)
6633 return res, resok
6634 }
6635
6636
6637 func (s *state) temp(pos src.XPos, t *types.Type) (*ir.Name, *ssa.Value) {
6638 tmp := typecheck.TempAt(pos, s.curfn, t)
6639 if t.HasPointers() || (ssa.IsMergeCandidate(tmp) && t != deferstruct()) {
6640 s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp, s.mem())
6641 }
6642 addr := s.addr(tmp)
6643 return tmp, addr
6644 }
6645
6646
6647 func (s *state) variable(n ir.Node, t *types.Type) *ssa.Value {
6648 v := s.vars[n]
6649 if v != nil {
6650 return v
6651 }
6652 v = s.fwdVars[n]
6653 if v != nil {
6654 return v
6655 }
6656
6657 if s.curBlock == s.f.Entry {
6658
6659 s.f.Fatalf("value %v (%v) incorrectly live at entry", n, v)
6660 }
6661
6662
6663 v = s.newValue0A(ssa.OpFwdRef, t, fwdRefAux{N: n})
6664 s.fwdVars[n] = v
6665 if n.Op() == ir.ONAME {
6666 s.addNamedValue(n.(*ir.Name), v)
6667 }
6668 return v
6669 }
6670
6671 func (s *state) mem() *ssa.Value {
6672 return s.variable(memVar, types.TypeMem)
6673 }
6674
6675 func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) {
6676 if n.Class == ir.Pxxx {
6677
6678 return
6679 }
6680 if ir.IsAutoTmp(n) {
6681
6682 return
6683 }
6684 if n.Class == ir.PPARAMOUT {
6685
6686
6687 return
6688 }
6689 loc := ssa.LocalSlot{N: n, Type: n.Type(), Off: 0}
6690 values, ok := s.f.NamedValues[loc]
6691 if !ok {
6692 s.f.Names = append(s.f.Names, &loc)
6693 s.f.CanonicalLocalSlots[loc] = &loc
6694 }
6695 s.f.NamedValues[loc] = append(values, v)
6696 }
6697
6698
6699 type Branch struct {
6700 P *obj.Prog
6701 B *ssa.Block
6702 }
6703
6704
6705 type State struct {
6706 ABI obj.ABI
6707
6708 pp *objw.Progs
6709
6710
6711
6712 Branches []Branch
6713
6714
6715 JumpTables []*ssa.Block
6716
6717
6718 bstart []*obj.Prog
6719
6720 maxarg int64
6721
6722
6723
6724 livenessMap liveness.Map
6725
6726
6727
6728 partLiveArgs map[*ir.Name]bool
6729
6730
6731
6732
6733 lineRunStart *obj.Prog
6734
6735
6736 OnWasmStackSkipped int
6737 }
6738
6739 func (s *State) FuncInfo() *obj.FuncInfo {
6740 return s.pp.CurFunc.LSym.Func()
6741 }
6742
6743
6744 func (s *State) Prog(as obj.As) *obj.Prog {
6745 p := s.pp.Prog(as)
6746 if objw.LosesStmtMark(as) {
6747 return p
6748 }
6749
6750
6751 if s.lineRunStart == nil || s.lineRunStart.Pos.Line() != p.Pos.Line() {
6752 s.lineRunStart = p
6753 } else if p.Pos.IsStmt() == src.PosIsStmt {
6754 s.lineRunStart.Pos = s.lineRunStart.Pos.WithIsStmt()
6755 p.Pos = p.Pos.WithNotStmt()
6756 }
6757 return p
6758 }
6759
6760
6761 func (s *State) Pc() *obj.Prog {
6762 return s.pp.Next
6763 }
6764
6765
6766 func (s *State) SetPos(pos src.XPos) {
6767 s.pp.Pos = pos
6768 }
6769
6770
6771
6772
6773 func (s *State) Br(op obj.As, target *ssa.Block) *obj.Prog {
6774 p := s.Prog(op)
6775 p.To.Type = obj.TYPE_BRANCH
6776 s.Branches = append(s.Branches, Branch{P: p, B: target})
6777 return p
6778 }
6779
6780
6781
6782
6783
6784
6785 func (s *State) DebugFriendlySetPosFrom(v *ssa.Value) {
6786 switch v.Op {
6787 case ssa.OpPhi, ssa.OpCopy, ssa.OpLoadReg, ssa.OpStoreReg:
6788
6789 s.SetPos(v.Pos.WithNotStmt())
6790 default:
6791 p := v.Pos
6792 if p != src.NoXPos {
6793
6794
6795
6796
6797 if p.IsStmt() != src.PosIsStmt {
6798 if s.pp.Pos.IsStmt() == src.PosIsStmt && s.pp.Pos.SameFileAndLine(p) {
6799
6800
6801
6802
6803
6804
6805
6806
6807
6808
6809
6810
6811
6812 return
6813 }
6814 p = p.WithNotStmt()
6815
6816 }
6817 s.SetPos(p)
6818 } else {
6819 s.SetPos(s.pp.Pos.WithNotStmt())
6820 }
6821 }
6822 }
6823
6824
6825 func emitArgInfo(e *ssafn, f *ssa.Func, pp *objw.Progs) {
6826 ft := e.curfn.Type()
6827 if ft.NumRecvs() == 0 && ft.NumParams() == 0 {
6828 return
6829 }
6830
6831 x := EmitArgInfo(e.curfn, f.OwnAux.ABIInfo())
6832 x.Set(obj.AttrContentAddressable, true)
6833 e.curfn.LSym.Func().ArgInfo = x
6834
6835
6836 p := pp.Prog(obj.AFUNCDATA)
6837 p.From.SetConst(rtabi.FUNCDATA_ArgInfo)
6838 p.To.Type = obj.TYPE_MEM
6839 p.To.Name = obj.NAME_EXTERN
6840 p.To.Sym = x
6841 }
6842
6843
6844 func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
6845 x := base.Ctxt.Lookup(fmt.Sprintf("%s.arginfo%d", f.LSym.Name, f.ABI))
6846 x.Align = 1
6847
6848
6849
6850
6851 PtrSize := int64(types.PtrSize)
6852 uintptrTyp := types.Types[types.TUINTPTR]
6853
6854 isAggregate := func(t *types.Type) bool {
6855 return isStructNotSIMD(t) || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice()
6856 }
6857
6858 wOff := 0
6859 n := 0
6860 writebyte := func(o uint8) { wOff = objw.Uint8(x, wOff, o) }
6861
6862
6863 write1 := func(sz, offset int64) {
6864 if offset >= rtabi.TraceArgsSpecial {
6865 writebyte(rtabi.TraceArgsOffsetTooLarge)
6866 } else {
6867 writebyte(uint8(offset))
6868 writebyte(uint8(sz))
6869 }
6870 n++
6871 }
6872
6873
6874
6875 var visitType func(baseOffset int64, t *types.Type, depth int) bool
6876 visitType = func(baseOffset int64, t *types.Type, depth int) bool {
6877 if n >= rtabi.TraceArgsLimit {
6878 writebyte(rtabi.TraceArgsDotdotdot)
6879 return false
6880 }
6881 if !isAggregate(t) {
6882 write1(t.Size(), baseOffset)
6883 return true
6884 }
6885 writebyte(rtabi.TraceArgsStartAgg)
6886 depth++
6887 if depth >= rtabi.TraceArgsMaxDepth {
6888 writebyte(rtabi.TraceArgsDotdotdot)
6889 writebyte(rtabi.TraceArgsEndAgg)
6890 n++
6891 return true
6892 }
6893 switch {
6894 case t.IsInterface(), t.IsString():
6895 _ = visitType(baseOffset, uintptrTyp, depth) &&
6896 visitType(baseOffset+PtrSize, uintptrTyp, depth)
6897 case t.IsSlice():
6898 _ = visitType(baseOffset, uintptrTyp, depth) &&
6899 visitType(baseOffset+PtrSize, uintptrTyp, depth) &&
6900 visitType(baseOffset+PtrSize*2, uintptrTyp, depth)
6901 case t.IsComplex():
6902 _ = visitType(baseOffset, types.FloatForComplex(t), depth) &&
6903 visitType(baseOffset+t.Size()/2, types.FloatForComplex(t), depth)
6904 case t.IsArray():
6905 if t.NumElem() == 0 {
6906 n++
6907 break
6908 }
6909 for i := int64(0); i < t.NumElem(); i++ {
6910 if !visitType(baseOffset, t.Elem(), depth) {
6911 break
6912 }
6913 baseOffset += t.Elem().Size()
6914 }
6915 case isStructNotSIMD(t):
6916 if t.NumFields() == 0 {
6917 n++
6918 break
6919 }
6920 for _, field := range t.Fields() {
6921 if !visitType(baseOffset+field.Offset, field.Type, depth) {
6922 break
6923 }
6924 }
6925 }
6926 writebyte(rtabi.TraceArgsEndAgg)
6927 return true
6928 }
6929
6930 start := 0
6931 if strings.Contains(f.LSym.Name, "[") {
6932
6933 start = 1
6934 }
6935
6936 for _, a := range abiInfo.InParams()[start:] {
6937 if !visitType(a.FrameOffset(abiInfo), a.Type, 0) {
6938 break
6939 }
6940 }
6941 writebyte(rtabi.TraceArgsEndSeq)
6942 if wOff > rtabi.TraceArgsMaxLen {
6943 base.Fatalf("ArgInfo too large")
6944 }
6945
6946 return x
6947 }
6948
6949
6950 func emitWrappedFuncInfo(e *ssafn, pp *objw.Progs) {
6951 if base.Ctxt.Flag_linkshared {
6952
6953
6954 return
6955 }
6956
6957 wfn := e.curfn.WrappedFunc
6958 if wfn == nil {
6959 return
6960 }
6961
6962 wsym := wfn.Linksym()
6963 x := base.Ctxt.LookupInit(fmt.Sprintf("%s.wrapinfo", wsym.Name), func(x *obj.LSym) {
6964 objw.SymPtrOff(x, 0, wsym)
6965 x.Set(obj.AttrContentAddressable, true)
6966 x.Align = 4
6967 })
6968 e.curfn.LSym.Func().WrapInfo = x
6969
6970
6971 p := pp.Prog(obj.AFUNCDATA)
6972 p.From.SetConst(rtabi.FUNCDATA_WrapInfo)
6973 p.To.Type = obj.TYPE_MEM
6974 p.To.Name = obj.NAME_EXTERN
6975 p.To.Sym = x
6976 }
6977
6978
6979 func genssa(f *ssa.Func, pp *objw.Progs) {
6980 var s State
6981 s.ABI = f.OwnAux.Fn.ABI()
6982
6983 e := f.Frontend().(*ssafn)
6984
6985 gatherPrintInfo := f.PrintOrHtmlSSA || ssa.GenssaDump[f.Name]
6986
6987 var lv *liveness.Liveness
6988 s.livenessMap, s.partLiveArgs, lv = liveness.Compute(e.curfn, f, e.stkptrsize, pp, gatherPrintInfo)
6989 emitArgInfo(e, f, pp)
6990 argLiveBlockMap, argLiveValueMap := liveness.ArgLiveness(e.curfn, f, pp)
6991
6992 openDeferInfo := e.curfn.LSym.Func().OpenCodedDeferInfo
6993 if openDeferInfo != nil {
6994
6995
6996 p := pp.Prog(obj.AFUNCDATA)
6997 p.From.SetConst(rtabi.FUNCDATA_OpenCodedDeferInfo)
6998 p.To.Type = obj.TYPE_MEM
6999 p.To.Name = obj.NAME_EXTERN
7000 p.To.Sym = openDeferInfo
7001 }
7002
7003 emitWrappedFuncInfo(e, pp)
7004
7005
7006 s.bstart = make([]*obj.Prog, f.NumBlocks())
7007 s.pp = pp
7008 var progToValue map[*obj.Prog]*ssa.Value
7009 var progToBlock map[*obj.Prog]*ssa.Block
7010 var valueToProgAfter []*obj.Prog
7011 if gatherPrintInfo {
7012 progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
7013 progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
7014 f.Logf("genssa %s\n", f.Name)
7015 progToBlock[s.pp.Next] = f.Blocks[0]
7016 }
7017
7018 if base.Ctxt.Flag_locationlists {
7019 if cap(f.Cache.ValueToProgAfter) < f.NumValues() {
7020 f.Cache.ValueToProgAfter = make([]*obj.Prog, f.NumValues())
7021 }
7022 valueToProgAfter = f.Cache.ValueToProgAfter[:f.NumValues()]
7023 clear(valueToProgAfter)
7024 }
7025
7026
7027
7028 firstPos := src.NoXPos
7029 for _, v := range f.Entry.Values {
7030 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 {
7031 firstPos = v.Pos
7032 v.Pos = firstPos.WithDefaultStmt()
7033 break
7034 }
7035 }
7036
7037
7038
7039
7040 var inlMarks map[*obj.Prog]int32
7041 var inlMarkList []*obj.Prog
7042
7043
7044
7045 var inlMarksByPos map[src.XPos][]*obj.Prog
7046
7047 var argLiveIdx int = -1
7048
7049
7050
7051
7052
7053 var hotAlign, hotRequire int64
7054
7055 if base.Debug.AlignHot > 0 {
7056 switch base.Ctxt.Arch.Name {
7057
7058
7059
7060
7061
7062 case "amd64", "386":
7063
7064
7065
7066 hotAlign = 64
7067 hotRequire = 31
7068 }
7069 }
7070
7071
7072 for i, b := range f.Blocks {
7073
7074 s.lineRunStart = nil
7075 s.SetPos(s.pp.Pos.WithNotStmt())
7076
7077 if hotAlign > 0 && b.Hotness&ssa.HotPgoInitial == ssa.HotPgoInitial {
7078
7079
7080
7081
7082
7083 p := s.pp.Prog(obj.APCALIGNMAX)
7084 p.From.SetConst(hotAlign)
7085 p.To.SetConst(hotRequire)
7086 }
7087
7088 s.bstart[b.ID] = s.pp.Next
7089
7090 if idx, ok := argLiveBlockMap[b.ID]; ok && idx != argLiveIdx {
7091 argLiveIdx = idx
7092 p := s.pp.Prog(obj.APCDATA)
7093 p.From.SetConst(rtabi.PCDATA_ArgLiveIndex)
7094 p.To.SetConst(int64(idx))
7095 }
7096
7097
7098 Arch.SSAMarkMoves(&s, b)
7099 for _, v := range b.Values {
7100 x := s.pp.Next
7101 s.DebugFriendlySetPosFrom(v)
7102
7103 if v.Op.ResultInArg0() && v.ResultReg() != v.Args[0].Reg() {
7104 v.Fatalf("input[0] and output not in same register %s", v.LongString())
7105 }
7106
7107 switch v.Op {
7108 case ssa.OpInitMem:
7109
7110 case ssa.OpArg:
7111
7112 case ssa.OpSP, ssa.OpSB:
7113
7114 case ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN, ssa.OpMakeResult:
7115
7116 case ssa.OpGetG:
7117
7118
7119 case ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive, ssa.OpWBend:
7120
7121 case ssa.OpPhi:
7122 CheckLoweredPhi(v)
7123 case ssa.OpConvert:
7124
7125 if v.Args[0].Reg() != v.Reg() {
7126 v.Fatalf("OpConvert should be a no-op: %s; %s", v.Args[0].LongString(), v.LongString())
7127 }
7128 case ssa.OpInlMark:
7129 p := Arch.Ginsnop(s.pp)
7130 if inlMarks == nil {
7131 inlMarks = map[*obj.Prog]int32{}
7132 inlMarksByPos = map[src.XPos][]*obj.Prog{}
7133 }
7134 inlMarks[p] = v.AuxInt32()
7135 inlMarkList = append(inlMarkList, p)
7136 pos := v.Pos.AtColumn1()
7137 inlMarksByPos[pos] = append(inlMarksByPos[pos], p)
7138 firstPos = src.NoXPos
7139
7140 default:
7141
7142 if firstPos != src.NoXPos && v.Op != ssa.OpArgIntReg && v.Op != ssa.OpArgFloatReg && v.Op != ssa.OpLoadReg && v.Op != ssa.OpStoreReg {
7143 s.SetPos(firstPos)
7144 firstPos = src.NoXPos
7145 }
7146
7147
7148 s.pp.NextLive = s.livenessMap.Get(v)
7149 s.pp.NextUnsafe = s.livenessMap.GetUnsafe(v)
7150
7151
7152 Arch.SSAGenValue(&s, v)
7153 }
7154
7155 if idx, ok := argLiveValueMap[v.ID]; ok && idx != argLiveIdx {
7156 argLiveIdx = idx
7157 p := s.pp.Prog(obj.APCDATA)
7158 p.From.SetConst(rtabi.PCDATA_ArgLiveIndex)
7159 p.To.SetConst(int64(idx))
7160 }
7161
7162 if base.Ctxt.Flag_locationlists {
7163 valueToProgAfter[v.ID] = s.pp.Next
7164 }
7165
7166 if gatherPrintInfo {
7167 for ; x != s.pp.Next; x = x.Link {
7168 progToValue[x] = v
7169 }
7170 }
7171 }
7172
7173 if s.bstart[b.ID] == s.pp.Next && len(b.Succs) == 1 && b.Succs[0].Block() == b {
7174 p := Arch.Ginsnop(s.pp)
7175 p.Pos = p.Pos.WithIsStmt()
7176 if b.Pos == src.NoXPos {
7177 b.Pos = p.Pos
7178 if b.Pos == src.NoXPos {
7179 b.Pos = s.pp.Text.Pos
7180 }
7181 }
7182 b.Pos = b.Pos.WithBogusLine()
7183 }
7184
7185
7186
7187
7188
7189 s.pp.NextUnsafe = s.livenessMap.GetUnsafeBlock(b)
7190
7191
7192 var next *ssa.Block
7193 if i < len(f.Blocks)-1 && base.Flag.N == 0 {
7194
7195
7196
7197
7198 next = f.Blocks[i+1]
7199 }
7200 x := s.pp.Next
7201 s.SetPos(b.Pos)
7202 Arch.SSAGenBlock(&s, b, next)
7203 if gatherPrintInfo {
7204 for ; x != s.pp.Next; x = x.Link {
7205 progToBlock[x] = b
7206 }
7207 }
7208 }
7209 if f.Blocks[len(f.Blocks)-1].Kind == ssa.BlockExit {
7210
7211
7212
7213
7214 Arch.Ginsnop(s.pp)
7215 }
7216 if openDeferInfo != nil {
7217
7218
7219
7220
7221
7222
7223
7224
7225 s.pp.NextLive = s.livenessMap.DeferReturn
7226 p := s.pp.Prog(obj.ACALL)
7227 p.To.Type = obj.TYPE_MEM
7228 p.To.Name = obj.NAME_EXTERN
7229 p.To.Sym = ir.Syms.Deferreturn
7230
7231
7232
7233
7234
7235 for _, o := range f.OwnAux.ABIInfo().OutParams() {
7236 n := o.Name
7237 rts, offs := o.RegisterTypesAndOffsets()
7238 for i := range o.Registers {
7239 Arch.LoadRegResult(&s, f, rts[i], ssa.ObjRegForAbiReg(o.Registers[i], f.Config), n, offs[i])
7240 }
7241 }
7242
7243 s.pp.Prog(obj.ARET)
7244 }
7245
7246 if inlMarks != nil {
7247 hasCall := false
7248
7249
7250
7251
7252 for p := s.pp.Text; p != nil; p = p.Link {
7253 if p.As == obj.ANOP || p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT ||
7254 p.As == obj.APCALIGN || p.As == obj.APCALIGNMAX || Arch.LinkArch.Family == sys.Wasm {
7255
7256
7257
7258
7259
7260 continue
7261 }
7262 if _, ok := inlMarks[p]; ok {
7263
7264
7265 continue
7266 }
7267 if p.As == obj.ACALL || p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
7268 hasCall = true
7269 }
7270 pos := p.Pos.AtColumn1()
7271 marks := inlMarksByPos[pos]
7272 if len(marks) == 0 {
7273 continue
7274 }
7275 for _, m := range marks {
7276
7277
7278
7279 p.Pos = p.Pos.WithIsStmt()
7280 s.pp.CurFunc.LSym.Func().AddInlMark(p, inlMarks[m])
7281
7282 m.As = obj.ANOP
7283 m.Pos = src.NoXPos
7284 m.From = obj.Addr{}
7285 m.To = obj.Addr{}
7286 }
7287 delete(inlMarksByPos, pos)
7288 }
7289
7290 for _, p := range inlMarkList {
7291 if p.As != obj.ANOP {
7292 s.pp.CurFunc.LSym.Func().AddInlMark(p, inlMarks[p])
7293 }
7294 }
7295
7296 if e.stksize == 0 && !hasCall {
7297
7298
7299
7300
7301
7302
7303 for p := s.pp.Text; p != nil; p = p.Link {
7304 if p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT || p.As == obj.ANOP {
7305 continue
7306 }
7307 if base.Ctxt.PosTable.Pos(p.Pos).Base().InliningIndex() >= 0 {
7308
7309 nop := Arch.Ginsnop(s.pp)
7310 nop.Pos = e.curfn.Pos().WithIsStmt()
7311
7312
7313
7314
7315
7316 for x := s.pp.Text; x != nil; x = x.Link {
7317 if x.Link == nop {
7318 x.Link = nop.Link
7319 break
7320 }
7321 }
7322
7323 for x := s.pp.Text; x != nil; x = x.Link {
7324 if x.Link == p {
7325 nop.Link = p
7326 x.Link = nop
7327 break
7328 }
7329 }
7330 }
7331 break
7332 }
7333 }
7334 }
7335
7336 if base.Ctxt.Flag_locationlists {
7337 var debugInfo *ssa.FuncDebug
7338 debugInfo = e.curfn.DebugInfo.(*ssa.FuncDebug)
7339
7340
7341 debugInfo.EntryID = f.Entry.ID
7342 if e.curfn.ABI == obj.ABIInternal && base.Flag.N != 0 {
7343 ssa.BuildFuncDebugNoOptimized(base.Ctxt, f, base.Debug.LocationLists > 1, StackOffset, debugInfo)
7344 } else {
7345 ssa.BuildFuncDebug(base.Ctxt, f, base.Debug.LocationLists, StackOffset, debugInfo)
7346 }
7347 bstart := s.bstart
7348 idToIdx := make([]int, f.NumBlocks())
7349 for i, b := range f.Blocks {
7350 idToIdx[b.ID] = i
7351 }
7352
7353
7354
7355 debugInfo.GetPC = func(b, v ssa.ID) int64 {
7356 switch v {
7357 case ssa.BlockStart.ID:
7358 if b == f.Entry.ID {
7359 return 0
7360
7361 }
7362 return bstart[b].Pc
7363 case ssa.BlockEnd.ID:
7364 blk := f.Blocks[idToIdx[b]]
7365 nv := len(blk.Values)
7366 return valueToProgAfter[blk.Values[nv-1].ID].Pc
7367 case ssa.FuncEnd.ID:
7368 return e.curfn.LSym.Size
7369 default:
7370 return valueToProgAfter[v].Pc
7371 }
7372 }
7373 }
7374
7375
7376 for _, br := range s.Branches {
7377 br.P.To.SetTarget(s.bstart[br.B.ID])
7378 if br.P.Pos.IsStmt() != src.PosIsStmt {
7379 br.P.Pos = br.P.Pos.WithNotStmt()
7380 } else if v0 := br.B.FirstPossibleStmtValue(); v0 != nil && v0.Pos.Line() == br.P.Pos.Line() && v0.Pos.IsStmt() == src.PosIsStmt {
7381 br.P.Pos = br.P.Pos.WithNotStmt()
7382 }
7383
7384 }
7385
7386
7387 for _, jt := range s.JumpTables {
7388
7389 targets := make([]*obj.Prog, len(jt.Succs))
7390 for i, e := range jt.Succs {
7391 targets[i] = s.bstart[e.Block().ID]
7392 }
7393
7394
7395
7396 fi := s.pp.CurFunc.LSym.Func()
7397 fi.JumpTables = append(fi.JumpTables, obj.JumpTable{Sym: jt.Aux.(*obj.LSym), Targets: targets})
7398 }
7399
7400 if e.log {
7401 filename := ""
7402 for p := s.pp.Text; p != nil; p = p.Link {
7403 if p.Pos.IsKnown() && p.InnermostFilename() != filename {
7404 filename = p.InnermostFilename()
7405 f.Logf("# %s\n", filename)
7406 }
7407
7408 var s string
7409 if v, ok := progToValue[p]; ok {
7410 s = v.String()
7411 } else if b, ok := progToBlock[p]; ok {
7412 s = b.String()
7413 } else {
7414 s = " "
7415 }
7416 f.Logf(" %-6s\t%.5d (%s)\t%s\n", s, p.Pc, p.InnermostLineNumber(), p.InstructionString())
7417 }
7418 }
7419 if f.HTMLWriter != nil {
7420 var buf strings.Builder
7421 buf.WriteString("<code>")
7422 buf.WriteString("<dl class=\"ssa-gen\">")
7423 filename := ""
7424
7425 liveness := lv.Format(nil)
7426 if liveness != "" {
7427 buf.WriteString("<dt class=\"ssa-prog-src\"></dt><dd class=\"ssa-prog\">")
7428 buf.WriteString(html.EscapeString("# " + liveness))
7429 buf.WriteString("</dd>")
7430 }
7431
7432 for p := s.pp.Text; p != nil; p = p.Link {
7433
7434
7435 if p.Pos.IsKnown() && p.InnermostFilename() != filename {
7436 filename = p.InnermostFilename()
7437 buf.WriteString("<dt class=\"ssa-prog-src\"></dt><dd class=\"ssa-prog\">")
7438 buf.WriteString(html.EscapeString("# " + filename))
7439 buf.WriteString("</dd>")
7440 }
7441
7442 buf.WriteString("<dt class=\"ssa-prog-src\">")
7443 if v, ok := progToValue[p]; ok {
7444
7445
7446 if p.As != obj.APCDATA {
7447 if liveness := lv.Format(v); liveness != "" {
7448
7449 buf.WriteString("</dt><dd class=\"ssa-prog\">")
7450 buf.WriteString(html.EscapeString("# " + liveness))
7451 buf.WriteString("</dd>")
7452
7453 buf.WriteString("<dt class=\"ssa-prog-src\">")
7454 }
7455 }
7456
7457 buf.WriteString(v.HTML())
7458 } else if b, ok := progToBlock[p]; ok {
7459 buf.WriteString("<b>" + b.HTML() + "</b>")
7460 }
7461 buf.WriteString("</dt>")
7462 buf.WriteString("<dd class=\"ssa-prog\">")
7463 fmt.Fprintf(&buf, "%.5d <span class=\"l%v line-number\">(%s)</span> %s", p.Pc, p.InnermostLineNumber(), p.InnermostLineNumberHTML(), html.EscapeString(p.InstructionString()))
7464 buf.WriteString("</dd>")
7465 }
7466 buf.WriteString("</dl>")
7467 buf.WriteString("</code>")
7468 f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String())
7469 }
7470 if ssa.GenssaDump[f.Name] {
7471 fi := f.DumpFileForPhase("genssa")
7472 if fi != nil {
7473
7474
7475 inliningDiffers := func(a, b []src.Pos) bool {
7476 if len(a) != len(b) {
7477 return true
7478 }
7479 for i := range a {
7480 if a[i].Filename() != b[i].Filename() {
7481 return true
7482 }
7483 if i != len(a)-1 && a[i].Line() != b[i].Line() {
7484 return true
7485 }
7486 }
7487 return false
7488 }
7489
7490 var allPosOld []src.Pos
7491 var allPos []src.Pos
7492
7493 for p := s.pp.Text; p != nil; p = p.Link {
7494 if p.Pos.IsKnown() {
7495 allPos = allPos[:0]
7496 p.Ctxt.AllPos(p.Pos, func(pos src.Pos) { allPos = append(allPos, pos) })
7497 if inliningDiffers(allPos, allPosOld) {
7498 for _, pos := range allPos {
7499 fmt.Fprintf(fi, "# %s:%d\n", pos.Filename(), pos.Line())
7500 }
7501 allPos, allPosOld = allPosOld, allPos
7502 }
7503 }
7504
7505 var s string
7506 if v, ok := progToValue[p]; ok {
7507 s = v.String()
7508 } else if b, ok := progToBlock[p]; ok {
7509 s = b.String()
7510 } else {
7511 s = " "
7512 }
7513 fmt.Fprintf(fi, " %-6s\t%.5d %s\t%s\n", s, p.Pc, ssa.StmtString(p.Pos), p.InstructionString())
7514 }
7515 fi.Close()
7516 }
7517 }
7518
7519 defframe(&s, e, f)
7520
7521 f.HTMLWriter.Close()
7522 f.HTMLWriter = nil
7523 }
7524
7525 func defframe(s *State, e *ssafn, f *ssa.Func) {
7526 pp := s.pp
7527
7528 s.maxarg = types.RoundUp(s.maxarg, e.stkalign)
7529 frame := s.maxarg + e.stksize
7530 if Arch.PadFrame != nil {
7531 frame = Arch.PadFrame(frame)
7532 }
7533
7534
7535 pp.Text.To.Type = obj.TYPE_TEXTSIZE
7536 pp.Text.To.Val = int32(types.RoundUp(f.OwnAux.ArgWidth(), int64(types.RegSize)))
7537 pp.Text.To.Offset = frame
7538
7539 p := pp.Text
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550 if f.OwnAux.ABIInfo().InRegistersUsed() != 0 && base.Flag.N == 0 {
7551
7552
7553 type nameOff struct {
7554 n *ir.Name
7555 off int64
7556 }
7557 partLiveArgsSpilled := make(map[nameOff]bool)
7558 for _, v := range f.Entry.Values {
7559 if v.Op.IsCall() {
7560 break
7561 }
7562 if v.Op != ssa.OpStoreReg || v.Args[0].Op != ssa.OpArgIntReg {
7563 continue
7564 }
7565 n, off := ssa.AutoVar(v)
7566 if n.Class != ir.PPARAM || n.Addrtaken() || !ssa.CanSSA(n.Type()) || !s.partLiveArgs[n] {
7567 continue
7568 }
7569 partLiveArgsSpilled[nameOff{n, off}] = true
7570 }
7571
7572
7573 for _, a := range f.OwnAux.ABIInfo().InParams() {
7574 n := a.Name
7575 if n == nil || n.Addrtaken() || !ssa.CanSSA(n.Type()) || !s.partLiveArgs[n] || len(a.Registers) <= 1 {
7576 continue
7577 }
7578 rts, offs := a.RegisterTypesAndOffsets()
7579 for i := range a.Registers {
7580 if !rts[i].HasPointers() {
7581 continue
7582 }
7583 if partLiveArgsSpilled[nameOff{n, offs[i]}] {
7584 continue
7585 }
7586 reg := ssa.ObjRegForAbiReg(a.Registers[i], f.Config)
7587 p = Arch.SpillArgReg(pp, p, f, rts[i], reg, n, offs[i])
7588 }
7589 }
7590 }
7591
7592
7593
7594
7595 var lo, hi int64
7596
7597
7598
7599 var state uint32
7600
7601
7602
7603 for _, n := range e.curfn.Dcl {
7604 if !n.Needzero() {
7605 continue
7606 }
7607 if n.Class != ir.PAUTO {
7608 e.Fatalf(n.Pos(), "needzero class %d", n.Class)
7609 }
7610 if n.Type().Size()%int64(types.PtrSize) != 0 || n.FrameOffset()%int64(types.PtrSize) != 0 || n.Type().Size() == 0 {
7611 e.Fatalf(n.Pos(), "var %L has size %d offset %d", n, n.Type().Size(), n.Offset_)
7612 }
7613
7614 if lo != hi && n.FrameOffset()+n.Type().Size() >= lo-int64(2*types.RegSize) {
7615
7616 lo = n.FrameOffset()
7617 continue
7618 }
7619
7620
7621 p = Arch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
7622
7623
7624 lo = n.FrameOffset()
7625 hi = lo + n.Type().Size()
7626 }
7627
7628
7629 Arch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
7630 }
7631
7632
7633 type IndexJump struct {
7634 Jump obj.As
7635 Index int
7636 }
7637
7638 func (s *State) oneJump(b *ssa.Block, jump *IndexJump) {
7639 p := s.Br(jump.Jump, b.Succs[jump.Index].Block())
7640 p.Pos = b.Pos
7641 }
7642
7643
7644
7645 func (s *State) CombJump(b, next *ssa.Block, jumps *[2][2]IndexJump) {
7646 switch next {
7647 case b.Succs[0].Block():
7648 s.oneJump(b, &jumps[0][0])
7649 s.oneJump(b, &jumps[0][1])
7650 case b.Succs[1].Block():
7651 s.oneJump(b, &jumps[1][0])
7652 s.oneJump(b, &jumps[1][1])
7653 default:
7654 var q *obj.Prog
7655 if b.Likely != ssa.BranchUnlikely {
7656 s.oneJump(b, &jumps[1][0])
7657 s.oneJump(b, &jumps[1][1])
7658 q = s.Br(obj.AJMP, b.Succs[1].Block())
7659 } else {
7660 s.oneJump(b, &jumps[0][0])
7661 s.oneJump(b, &jumps[0][1])
7662 q = s.Br(obj.AJMP, b.Succs[0].Block())
7663 }
7664 q.Pos = b.Pos
7665 }
7666 }
7667
7668
7669 func AddAux(a *obj.Addr, v *ssa.Value) {
7670 AddAux2(a, v, v.AuxInt)
7671 }
7672 func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
7673 if a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR {
7674 v.Fatalf("bad AddAux addr %v", a)
7675 }
7676
7677 a.Offset += offset
7678
7679
7680 if v.Aux == nil {
7681 return
7682 }
7683
7684 switch n := v.Aux.(type) {
7685 case *ssa.AuxCall:
7686 a.Name = obj.NAME_EXTERN
7687 a.Sym = n.Fn
7688 case *obj.LSym:
7689 a.Name = obj.NAME_EXTERN
7690 a.Sym = n
7691 case *ir.Name:
7692 if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
7693 a.Name = obj.NAME_PARAM
7694 } else {
7695 a.Name = obj.NAME_AUTO
7696 }
7697 a.Sym = n.Linksym()
7698 a.Offset += n.FrameOffset()
7699 default:
7700 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
7701 }
7702 }
7703
7704
7705
7706 func (s *state) extendIndex(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
7707 size := idx.Type.Size()
7708 if size == s.config.PtrSize {
7709 return idx
7710 }
7711 if size > s.config.PtrSize {
7712
7713
7714 var lo *ssa.Value
7715 if idx.Type.IsSigned() {
7716 lo = s.newValue1(ssa.OpInt64Lo, types.Types[types.TINT], idx)
7717 } else {
7718 lo = s.newValue1(ssa.OpInt64Lo, types.Types[types.TUINT], idx)
7719 }
7720 if bounded || base.Flag.B != 0 {
7721 return lo
7722 }
7723 bNext := s.f.NewBlock(ssa.BlockPlain)
7724 bPanic := s.f.NewBlock(ssa.BlockExit)
7725 hi := s.newValue1(ssa.OpInt64Hi, types.Types[types.TUINT32], idx)
7726 cmp := s.newValue2(ssa.OpEq32, types.Types[types.TBOOL], hi, s.constInt32(types.Types[types.TUINT32], 0))
7727 if !idx.Type.IsSigned() {
7728 switch kind {
7729 case ssa.BoundsIndex:
7730 kind = ssa.BoundsIndexU
7731 case ssa.BoundsSliceAlen:
7732 kind = ssa.BoundsSliceAlenU
7733 case ssa.BoundsSliceAcap:
7734 kind = ssa.BoundsSliceAcapU
7735 case ssa.BoundsSliceB:
7736 kind = ssa.BoundsSliceBU
7737 case ssa.BoundsSlice3Alen:
7738 kind = ssa.BoundsSlice3AlenU
7739 case ssa.BoundsSlice3Acap:
7740 kind = ssa.BoundsSlice3AcapU
7741 case ssa.BoundsSlice3B:
7742 kind = ssa.BoundsSlice3BU
7743 case ssa.BoundsSlice3C:
7744 kind = ssa.BoundsSlice3CU
7745 }
7746 }
7747 b := s.endBlock()
7748 b.Kind = ssa.BlockIf
7749 b.SetControl(cmp)
7750 b.Likely = ssa.BranchLikely
7751 b.AddEdgeTo(bNext)
7752 b.AddEdgeTo(bPanic)
7753
7754 s.startBlock(bPanic)
7755 mem := s.newValue4I(ssa.OpPanicExtend, types.TypeMem, int64(kind), hi, lo, len, s.mem())
7756 s.endBlock().SetControl(mem)
7757 s.startBlock(bNext)
7758
7759 return lo
7760 }
7761
7762
7763 var op ssa.Op
7764 if idx.Type.IsSigned() {
7765 switch 10*size + s.config.PtrSize {
7766 case 14:
7767 op = ssa.OpSignExt8to32
7768 case 18:
7769 op = ssa.OpSignExt8to64
7770 case 24:
7771 op = ssa.OpSignExt16to32
7772 case 28:
7773 op = ssa.OpSignExt16to64
7774 case 48:
7775 op = ssa.OpSignExt32to64
7776 default:
7777 s.Fatalf("bad signed index extension %s", idx.Type)
7778 }
7779 } else {
7780 switch 10*size + s.config.PtrSize {
7781 case 14:
7782 op = ssa.OpZeroExt8to32
7783 case 18:
7784 op = ssa.OpZeroExt8to64
7785 case 24:
7786 op = ssa.OpZeroExt16to32
7787 case 28:
7788 op = ssa.OpZeroExt16to64
7789 case 48:
7790 op = ssa.OpZeroExt32to64
7791 default:
7792 s.Fatalf("bad unsigned index extension %s", idx.Type)
7793 }
7794 }
7795 return s.newValue1(op, types.Types[types.TINT], idx)
7796 }
7797
7798
7799
7800 func CheckLoweredPhi(v *ssa.Value) {
7801 if v.Op != ssa.OpPhi {
7802 v.Fatalf("CheckLoweredPhi called with non-phi value: %v", v.LongString())
7803 }
7804 if v.Type.IsMemory() {
7805 return
7806 }
7807 f := v.Block.Func
7808 loc := f.RegAlloc[v.ID]
7809 for _, a := range v.Args {
7810 if aloc := f.RegAlloc[a.ID]; aloc != loc {
7811 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)
7812 }
7813 }
7814 }
7815
7816
7817
7818
7819
7820 func CheckLoweredGetClosurePtr(v *ssa.Value) {
7821 entry := v.Block.Func.Entry
7822 if entry != v.Block {
7823 base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
7824 }
7825 for _, w := range entry.Values {
7826 if w == v {
7827 break
7828 }
7829 switch w.Op {
7830 case ssa.OpArgIntReg, ssa.OpArgFloatReg:
7831
7832 default:
7833 base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
7834 }
7835 }
7836 }
7837
7838
7839 func CheckArgReg(v *ssa.Value) {
7840 entry := v.Block.Func.Entry
7841 if entry != v.Block {
7842 base.Fatalf("in %s, badly placed ArgIReg or ArgFReg: %v %v", v.Block.Func.Name, v.Block, v)
7843 }
7844 }
7845
7846 func AddrAuto(a *obj.Addr, v *ssa.Value) {
7847 n, off := ssa.AutoVar(v)
7848 a.Type = obj.TYPE_MEM
7849 a.Sym = n.Linksym()
7850 a.Reg = int16(Arch.REGSP)
7851 a.Offset = n.FrameOffset() + off
7852 if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
7853 a.Name = obj.NAME_PARAM
7854 } else {
7855 a.Name = obj.NAME_AUTO
7856 }
7857 }
7858
7859
7860
7861 func (s *State) Call(v *ssa.Value) *obj.Prog {
7862 pPosIsStmt := s.pp.Pos.IsStmt()
7863 s.PrepareCall(v)
7864
7865 p := s.Prog(obj.ACALL)
7866 if pPosIsStmt == src.PosIsStmt {
7867 p.Pos = v.Pos.WithIsStmt()
7868 } else {
7869 p.Pos = v.Pos.WithNotStmt()
7870 }
7871 if sym, ok := v.Aux.(*ssa.AuxCall); ok && sym.Fn != nil {
7872 p.To.Type = obj.TYPE_MEM
7873 p.To.Name = obj.NAME_EXTERN
7874 p.To.Sym = sym.Fn
7875 } else {
7876
7877 switch Arch.LinkArch.Family {
7878 case sys.AMD64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X, sys.Wasm:
7879 p.To.Type = obj.TYPE_REG
7880 case sys.ARM, sys.ARM64, sys.Loong64, sys.MIPS, sys.MIPS64:
7881 p.To.Type = obj.TYPE_MEM
7882 default:
7883 base.Fatalf("unknown indirect call family")
7884 }
7885 p.To.Reg = v.Args[0].Reg()
7886 }
7887 return p
7888 }
7889
7890
7891
7892 func (s *State) TailCall(v *ssa.Value) *obj.Prog {
7893 p := s.Call(v)
7894 p.As = obj.ARET
7895 return p
7896 }
7897
7898
7899
7900
7901 func (s *State) PrepareCall(v *ssa.Value) {
7902 idx := s.livenessMap.Get(v)
7903 if !idx.StackMapValid() {
7904
7905 if sym, ok := v.Aux.(*ssa.AuxCall); !ok || !(sym.Fn == ir.Syms.WBZero || sym.Fn == ir.Syms.WBMove) {
7906 base.Fatalf("missing stack map index for %v", v.LongString())
7907 }
7908 }
7909
7910 call, ok := v.Aux.(*ssa.AuxCall)
7911
7912 if ok {
7913
7914
7915 if nowritebarrierrecCheck != nil {
7916 nowritebarrierrecCheck.recordCall(s.pp.CurFunc, call.Fn, v.Pos)
7917 }
7918 }
7919
7920 if s.maxarg < v.AuxInt {
7921 s.maxarg = v.AuxInt
7922 }
7923 }
7924
7925
7926
7927 func (s *State) UseArgs(n int64) {
7928 if s.maxarg < n {
7929 s.maxarg = n
7930 }
7931 }
7932
7933
7934 func fieldIdx(n *ir.SelectorExpr) int {
7935 t := n.X.Type()
7936 if !isStructNotSIMD(t) {
7937 panic("ODOT's LHS is not a struct")
7938 }
7939
7940 for i, f := range t.Fields() {
7941 if f.Sym == n.Sel {
7942 if f.Offset != n.Offset() {
7943 panic("field offset doesn't match")
7944 }
7945 return i
7946 }
7947 }
7948 panic(fmt.Sprintf("can't find field in expr %v\n", n))
7949
7950
7951
7952 }
7953
7954
7955
7956 type ssafn struct {
7957 curfn *ir.Func
7958 strings map[string]*obj.LSym
7959 stksize int64
7960 stkptrsize int64
7961
7962
7963
7964
7965
7966 stkalign int64
7967
7968 log bool
7969 }
7970
7971
7972
7973 func (e *ssafn) StringData(s string) *obj.LSym {
7974 if aux, ok := e.strings[s]; ok {
7975 return aux
7976 }
7977 if e.strings == nil {
7978 e.strings = make(map[string]*obj.LSym)
7979 }
7980 data := staticdata.StringSym(e.curfn.Pos(), s)
7981 e.strings[s] = data
7982 return data
7983 }
7984
7985
7986 func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
7987 node := parent.N
7988
7989 if node.Class != ir.PAUTO || node.Addrtaken() {
7990
7991 return ssa.LocalSlot{N: node, Type: t, Off: parent.Off + offset}
7992 }
7993
7994 sym := &types.Sym{Name: node.Sym().Name + suffix, Pkg: types.LocalPkg}
7995 n := e.curfn.NewLocal(parent.N.Pos(), sym, t)
7996 n.SetUsed(true)
7997 n.SetEsc(ir.EscNever)
7998 types.CalcSize(t)
7999 return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset}
8000 }
8001
8002
8003 func (e *ssafn) Logf(msg string, args ...any) {
8004 if e.log {
8005 fmt.Printf(msg, args...)
8006 }
8007 }
8008
8009 func (e *ssafn) Log() bool {
8010 return e.log
8011 }
8012
8013
8014 func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...any) {
8015 base.Pos = pos
8016 nargs := append([]any{ir.FuncName(e.curfn)}, args...)
8017 base.Fatalf("'%s': "+msg, nargs...)
8018 }
8019
8020
8021
8022 func (e *ssafn) Warnl(pos src.XPos, fmt_ string, args ...any) {
8023 base.WarnfAt(pos, fmt_, args...)
8024 }
8025
8026 func (e *ssafn) Debug_checknil() bool {
8027 return base.Debug.Nil != 0
8028 }
8029
8030 func (e *ssafn) UseWriteBarrier() bool {
8031 return base.Flag.WB
8032 }
8033
8034 func (e *ssafn) Syslook(name string) *obj.LSym {
8035 switch name {
8036 case "goschedguarded":
8037 return ir.Syms.Goschedguarded
8038 case "writeBarrier":
8039 return ir.Syms.WriteBarrier
8040 case "wbZero":
8041 return ir.Syms.WBZero
8042 case "wbMove":
8043 return ir.Syms.WBMove
8044 case "cgoCheckMemmove":
8045 return ir.Syms.CgoCheckMemmove
8046 case "cgoCheckPtrWrite":
8047 return ir.Syms.CgoCheckPtrWrite
8048 }
8049 e.Fatalf(src.NoXPos, "unknown Syslook func %v", name)
8050 return nil
8051 }
8052
8053 func (e *ssafn) Func() *ir.Func {
8054 return e.curfn
8055 }
8056
8057 func clobberBase(n ir.Node) ir.Node {
8058 if n.Op() == ir.ODOT {
8059 n := n.(*ir.SelectorExpr)
8060 if n.X.Type().NumFields() == 1 {
8061 return clobberBase(n.X)
8062 }
8063 }
8064 if n.Op() == ir.OINDEX {
8065 n := n.(*ir.IndexExpr)
8066 if n.X.Type().IsArray() && n.X.Type().NumElem() == 1 {
8067 return clobberBase(n.X)
8068 }
8069 }
8070 return n
8071 }
8072
8073
8074 func callTargetLSym(callee *ir.Name) *obj.LSym {
8075 if callee.Func == nil {
8076
8077
8078
8079 return callee.Linksym()
8080 }
8081
8082 return callee.LinksymABI(callee.Func.ABI)
8083 }
8084
8085
8086 const deferStructFnField = 4
8087
8088 var deferType *types.Type
8089
8090
8091
8092 func deferstruct() *types.Type {
8093 if deferType != nil {
8094 return deferType
8095 }
8096
8097 makefield := func(name string, t *types.Type) *types.Field {
8098 sym := (*types.Pkg)(nil).Lookup(name)
8099 return types.NewField(src.NoXPos, sym, t)
8100 }
8101
8102 fields := []*types.Field{
8103 makefield("heap", types.Types[types.TBOOL]),
8104 makefield("rangefunc", types.Types[types.TBOOL]),
8105 makefield("sp", types.Types[types.TUINTPTR]),
8106 makefield("pc", types.Types[types.TUINTPTR]),
8107
8108
8109
8110 makefield("fn", types.Types[types.TUINTPTR]),
8111 makefield("link", types.Types[types.TUINTPTR]),
8112 makefield("head", types.Types[types.TUINTPTR]),
8113 }
8114 if name := fields[deferStructFnField].Sym.Name; name != "fn" {
8115 base.Fatalf("deferStructFnField is %q, not fn", name)
8116 }
8117
8118 n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.Pkgs.Runtime.Lookup("_defer"))
8119 typ := types.NewNamed(n)
8120 n.SetType(typ)
8121 n.SetTypecheck(1)
8122
8123
8124 typ.SetUnderlying(types.NewStruct(fields))
8125 types.CalcStructSize(typ)
8126
8127 deferType = typ
8128 return typ
8129 }
8130
8131
8132
8133
8134
8135 func SpillSlotAddr(spill ssa.Spill, baseReg int16, extraOffset int64) obj.Addr {
8136 return obj.Addr{
8137 Name: obj.NAME_NONE,
8138 Type: obj.TYPE_MEM,
8139 Reg: baseReg,
8140 Offset: spill.Offset + extraOffset,
8141 }
8142 }
8143
8144 func isStructNotSIMD(t *types.Type) bool {
8145 return t.IsStruct() && !t.IsSIMD()
8146 }
8147
8148 var BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
8149
View as plain text