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