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