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
5118
5119
5120
5121
5122
5123 if k == callTail && s.instrumentEnterExit {
5124 s.rtcall(ir.Syms.Racefuncexit, true, nil)
5125 }
5126
5127 callArgs = append(callArgs, s.mem())
5128
5129
5130 switch {
5131 case k == callDefer:
5132 sym := ir.Syms.Deferproc
5133 if dextra != nil {
5134 sym = ir.Syms.Deferprocat
5135 }
5136 aux := ssa.StaticAuxCall(sym, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5137 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5138 case k == callGo:
5139 aux := ssa.StaticAuxCall(ir.Syms.Newproc, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5140 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5141 case closure != nil:
5142
5143
5144
5145
5146
5147 codeptr = s.rawLoad(types.Types[types.TUINTPTR], closure)
5148 aux := ssa.ClosureAuxCall(callABI.ABIAnalyzeTypes(ACArgs, ACResults))
5149 call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure)
5150 case codeptr != nil:
5151
5152 aux := ssa.InterfaceAuxCall(params)
5153 call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr)
5154 if k == callTail {
5155 call.Op = ssa.OpTailLECallInter
5156 stksize = 0
5157 }
5158 case calleeLSym != nil:
5159 aux := ssa.StaticAuxCall(calleeLSym, params)
5160 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5161 if k == callTail {
5162 call.Op = ssa.OpTailLECall
5163 stksize = 0
5164 }
5165 default:
5166 s.Fatalf("bad call type %v %v", n.Op(), n)
5167 }
5168 call.AddArgs(callArgs...)
5169 call.AuxInt = stksize
5170 }
5171 s.prevCall = call
5172 s.vars[memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
5173
5174 for _, v := range n.KeepAlive {
5175 if !v.Addrtaken() {
5176 s.Fatalf("KeepAlive variable %v must have Addrtaken set", v)
5177 }
5178 switch v.Class {
5179 case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
5180 default:
5181 s.Fatalf("KeepAlive variable %v must be Auto or Arg", v)
5182 }
5183 s.vars[memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, v, s.mem())
5184 }
5185
5186
5187 var result *ssa.Value
5188 if len(res) == 0 || k != callNormal {
5189 result = nil
5190 } else {
5191 fp := res[0]
5192 if returnResultAddr {
5193 result = s.resultAddrOfCall(call, 0, fp.Type)
5194 } else {
5195 result = s.newValue1I(ssa.OpSelectN, fp.Type, 0, call)
5196 }
5197 if n.Reshape {
5198 result = s.newValue1(ssa.OpCopy, n.Type(), result)
5199 }
5200 }
5201
5202
5203 if k == callDefer || k == callDeferStack || isCallDeferRangeFunc {
5204 b := s.endBlock()
5205 b.Kind = ssa.BlockDefer
5206 b.SetControl(call)
5207 bNext := s.f.NewBlock(ssa.BlockPlain)
5208 b.AddEdgeTo(bNext)
5209 r := s.f.DeferReturn
5210 if r == nil {
5211 r = s.f.NewBlock(ssa.BlockPlain)
5212 s.startBlock(r)
5213 s.exit()
5214 s.f.DeferReturn = r
5215 }
5216 b.AddEdgeTo(r)
5217 b.Likely = ssa.BranchLikely
5218 s.startBlock(bNext)
5219 }
5220
5221 return result
5222 }
5223
5224
5225
5226 func (s *state) maybeNilCheckClosure(closure *ssa.Value, k callKind) {
5227 if Arch.LinkArch.Family == sys.Wasm || buildcfg.GOOS == "aix" && k != callGo {
5228
5229
5230 s.nilCheck(closure)
5231 }
5232 }
5233
5234
5235
5236 func (s *state) getClosureAndRcvr(fn *ir.SelectorExpr) (*ssa.Value, *ssa.Value) {
5237 i := s.expr(fn.X)
5238 itab := s.newValue1(ssa.OpITab, types.Types[types.TUINTPTR], i)
5239 s.nilCheck(itab)
5240 itabidx := fn.Offset() + rttype.ITab.OffsetOf("Fun")
5241 closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
5242 rcvr := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, i)
5243 return closure, rcvr
5244 }
5245
5246
5247
5248 func etypesign(e types.Kind) int8 {
5249 switch e {
5250 case types.TINT8, types.TINT16, types.TINT32, types.TINT64, types.TINT:
5251 return -1
5252 case types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINT, types.TUINTPTR, types.TUNSAFEPTR:
5253 return +1
5254 }
5255 return 0
5256 }
5257
5258
5259
5260 func (s *state) addr(n ir.Node) *ssa.Value {
5261 if n.Op() != ir.ONAME {
5262 s.pushLine(n.Pos())
5263 defer s.popLine()
5264 }
5265
5266 if s.canSSA(n) {
5267
5268
5269
5270
5271
5272
5273
5274
5275 s.boundsCheckArrayIndex(n)
5276 return s.newValue1A(ssa.OpAddr, n.Type().PtrTo(), ir.Syms.Zerobase, s.sb)
5277 }
5278
5279 t := types.NewPtr(n.Type())
5280 linksymOffset := func(lsym *obj.LSym, offset int64) *ssa.Value {
5281 v := s.entryNewValue1A(ssa.OpAddr, t, lsym, s.sb)
5282
5283 if offset != 0 {
5284 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, offset, v)
5285 }
5286 return v
5287 }
5288 switch n.Op() {
5289 case ir.OLINKSYMOFFSET:
5290 no := n.(*ir.LinksymOffsetExpr)
5291 return linksymOffset(no.Linksym, no.Offset_)
5292 case ir.ONAME:
5293 n := n.(*ir.Name)
5294 if n.Heapaddr != nil {
5295 return s.expr(n.Heapaddr)
5296 }
5297 switch n.Class {
5298 case ir.PEXTERN:
5299
5300 return linksymOffset(n.Linksym(), 0)
5301 case ir.PPARAM:
5302
5303 v := s.decladdrs[n]
5304 if v != nil {
5305 return v
5306 }
5307 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
5308 return nil
5309 case ir.PAUTO:
5310 return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), !ir.IsAutoTmp(n))
5311
5312 case ir.PPARAMOUT:
5313
5314
5315 return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), true)
5316 default:
5317 s.Fatalf("variable address class %v not implemented", n.Class)
5318 return nil
5319 }
5320 case ir.ORESULT:
5321
5322 n := n.(*ir.ResultExpr)
5323 return s.resultAddrOfCall(s.prevCall, n.Index, n.Type())
5324 case ir.OINDEX:
5325 n := n.(*ir.IndexExpr)
5326 if n.X.Type().IsSlice() {
5327 a := s.expr(n.X)
5328 i := s.expr(n.Index)
5329 len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], a)
5330 i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
5331 p := s.newValue1(ssa.OpSlicePtr, t, a)
5332 return s.newValue2(ssa.OpPtrIndex, t, p, i)
5333 } else {
5334 a := s.addr(n.X)
5335 i := s.expr(n.Index)
5336 len := s.constInt(types.Types[types.TINT], n.X.Type().NumElem())
5337 i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
5338 return s.newValue2(ssa.OpPtrIndex, types.NewPtr(n.X.Type().Elem()), a, i)
5339 }
5340 case ir.ODEREF:
5341 n := n.(*ir.StarExpr)
5342 return s.exprPtr(n.X, n.Bounded(), n.Pos())
5343 case ir.ODOT:
5344 n := n.(*ir.SelectorExpr)
5345 p := s.addr(n.X)
5346 return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
5347 case ir.ODOTPTR:
5348 n := n.(*ir.SelectorExpr)
5349 p := s.exprPtr(n.X, n.Bounded(), n.Pos())
5350 return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
5351 case ir.OCONVNOP:
5352 n := n.(*ir.ConvExpr)
5353 if n.Type() == n.X.Type() {
5354 return s.addr(n.X)
5355 }
5356 addr := s.addr(n.X)
5357 return s.newValue1(ssa.OpCopy, t, addr)
5358 case ir.OCALLFUNC, ir.OCALLINTER:
5359 n := n.(*ir.CallExpr)
5360 return s.callAddr(n, callNormal)
5361 case ir.ODOTTYPE, ir.ODYNAMICDOTTYPE:
5362 var v *ssa.Value
5363 if n.Op() == ir.ODOTTYPE {
5364 v, _ = s.dottype(n.(*ir.TypeAssertExpr), false)
5365 } else {
5366 v, _ = s.dynamicDottype(n.(*ir.DynamicTypeAssertExpr), false)
5367 }
5368 if v.Op != ssa.OpLoad {
5369 s.Fatalf("dottype of non-load")
5370 }
5371 if v.Args[1] != s.mem() {
5372 s.Fatalf("memory no longer live from dottype load")
5373 }
5374 return v.Args[0]
5375 default:
5376 s.Fatalf("unhandled addr %v", n.Op())
5377 return nil
5378 }
5379 }
5380
5381
5382
5383 func (s *state) canSSA(n ir.Node) bool {
5384 if base.Flag.N != 0 {
5385 return false
5386 }
5387 for {
5388 nn := n
5389 if nn.Op() == ir.ODOT {
5390 nn := nn.(*ir.SelectorExpr)
5391 n = nn.X
5392 continue
5393 }
5394 if nn.Op() == ir.OINDEX {
5395 nn := nn.(*ir.IndexExpr)
5396 if nn.X.Type().IsArray() {
5397 n = nn.X
5398 continue
5399 }
5400 }
5401 break
5402 }
5403 if n.Op() != ir.ONAME {
5404 return false
5405 }
5406 return s.canSSAName(n.(*ir.Name)) && ssa.CanSSA(n.Type())
5407 }
5408
5409 func (s *state) canSSAName(name *ir.Name) bool {
5410 if name.Addrtaken() || !name.OnStack() {
5411 return false
5412 }
5413 switch name.Class {
5414 case ir.PPARAMOUT:
5415 if s.hasdefer {
5416
5417
5418
5419
5420
5421 return false
5422 }
5423 if s.cgoUnsafeArgs {
5424
5425
5426 return false
5427 }
5428 }
5429 return true
5430
5431 }
5432
5433
5434 func (s *state) exprPtr(n ir.Node, bounded bool, lineno src.XPos) *ssa.Value {
5435 p := s.expr(n)
5436 if bounded || n.NonNil() {
5437 if s.f.Frontend().Debug_checknil() && lineno.Line() > 1 {
5438 s.f.Warnl(lineno, "removed nil check")
5439 }
5440 return p
5441 }
5442 p = s.nilCheck(p)
5443 return p
5444 }
5445
5446
5447
5448
5449
5450
5451 func (s *state) nilCheck(ptr *ssa.Value) *ssa.Value {
5452 if base.Debug.DisableNil != 0 || s.curfn.NilCheckDisabled() {
5453 return ptr
5454 }
5455 return s.newValue2(ssa.OpNilCheck, ptr.Type, ptr, s.mem())
5456 }
5457
5458
5459 func (s *state) boundsCheckArrayIndex(n ir.Node) {
5460 if n.Op() != ir.OINDEX {
5461 return
5462 }
5463 nn := n.(*ir.IndexExpr)
5464 typ := nn.X.Type()
5465 if typ.IsArray() {
5466 _ = s.expr(nn.X)
5467 idx := s.expr(nn.Index)
5468 len := s.constInt(types.Types[types.TINT], typ.NumElem())
5469 s.boundsCheck(idx, len, ssa.BoundsIndex, nn.Bounded())
5470 }
5471 }
5472
5473
5474
5475
5476
5477
5478
5479 func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
5480 idx = s.extendIndex(idx, len, kind, bounded)
5481
5482 if bounded || base.Flag.B != 0 {
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503 return idx
5504 }
5505
5506 bNext := s.f.NewBlock(ssa.BlockPlain)
5507 bPanic := s.f.NewBlock(ssa.BlockExit)
5508
5509 if !idx.Type.IsSigned() {
5510 switch kind {
5511 case ssa.BoundsIndex:
5512 kind = ssa.BoundsIndexU
5513 case ssa.BoundsSliceAlen:
5514 kind = ssa.BoundsSliceAlenU
5515 case ssa.BoundsSliceAcap:
5516 kind = ssa.BoundsSliceAcapU
5517 case ssa.BoundsSliceB:
5518 kind = ssa.BoundsSliceBU
5519 case ssa.BoundsSlice3Alen:
5520 kind = ssa.BoundsSlice3AlenU
5521 case ssa.BoundsSlice3Acap:
5522 kind = ssa.BoundsSlice3AcapU
5523 case ssa.BoundsSlice3B:
5524 kind = ssa.BoundsSlice3BU
5525 case ssa.BoundsSlice3C:
5526 kind = ssa.BoundsSlice3CU
5527 }
5528 }
5529
5530 var cmp *ssa.Value
5531 if kind == ssa.BoundsIndex || kind == ssa.BoundsIndexU {
5532 cmp = s.newValue2(ssa.OpIsInBounds, types.Types[types.TBOOL], idx, len)
5533 } else {
5534 cmp = s.newValue2(ssa.OpIsSliceInBounds, types.Types[types.TBOOL], idx, len)
5535 }
5536 b := s.endBlock()
5537 b.Kind = ssa.BlockIf
5538 b.SetControl(cmp)
5539 b.Likely = ssa.BranchLikely
5540 b.AddEdgeTo(bNext)
5541 b.AddEdgeTo(bPanic)
5542
5543 s.startBlock(bPanic)
5544 if Arch.LinkArch.Family == sys.Wasm {
5545
5546
5547 s.rtcall(BoundsCheckFunc[kind], false, nil, idx, len)
5548 } else {
5549 mem := s.newValue3I(ssa.OpPanicBounds, types.TypeMem, int64(kind), idx, len, s.mem())
5550 s.endBlock().SetControl(mem)
5551 }
5552 s.startBlock(bNext)
5553
5554
5555 if base.Flag.Cfg.SpectreIndex {
5556 op := ssa.OpSpectreIndex
5557 if kind != ssa.BoundsIndex && kind != ssa.BoundsIndexU {
5558 op = ssa.OpSpectreSliceIndex
5559 }
5560 idx = s.newValue2(op, types.Types[types.TINT], idx, len)
5561 }
5562
5563 return idx
5564 }
5565
5566
5567 func (s *state) check(cmp *ssa.Value, fn *obj.LSym) {
5568 b := s.endBlock()
5569 b.Kind = ssa.BlockIf
5570 b.SetControl(cmp)
5571 b.Likely = ssa.BranchLikely
5572 bNext := s.f.NewBlock(ssa.BlockPlain)
5573 line := s.peekPos()
5574 pos := base.Ctxt.PosTable.Pos(line)
5575 fl := funcLine{f: fn, base: pos.Base(), line: pos.Line()}
5576 bPanic := s.panics[fl]
5577 if bPanic == nil {
5578 bPanic = s.f.NewBlock(ssa.BlockPlain)
5579 s.panics[fl] = bPanic
5580 s.startBlock(bPanic)
5581
5582
5583 s.rtcall(fn, false, nil)
5584 }
5585 b.AddEdgeTo(bNext)
5586 b.AddEdgeTo(bPanic)
5587 s.startBlock(bNext)
5588 }
5589
5590 func (s *state) intDivide(n ir.Node, a, b *ssa.Value) *ssa.Value {
5591 needcheck := true
5592 switch b.Op {
5593 case ssa.OpConst8, ssa.OpConst16, ssa.OpConst32, ssa.OpConst64:
5594 if b.AuxInt != 0 {
5595 needcheck = false
5596 }
5597 }
5598 if needcheck {
5599
5600 cmp := s.newValue2(s.ssaOp(ir.ONE, n.Type()), types.Types[types.TBOOL], b, s.zeroVal(n.Type()))
5601 s.check(cmp, ir.Syms.Panicdivide)
5602 }
5603 return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
5604 }
5605
5606
5607
5608
5609
5610 func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args ...*ssa.Value) []*ssa.Value {
5611 s.prevCall = nil
5612
5613 off := base.Ctxt.Arch.FixedFrameSize
5614 var callArgs []*ssa.Value
5615 var callArgTypes []*types.Type
5616
5617 for _, arg := range args {
5618 t := arg.Type
5619 off = types.RoundUp(off, t.Alignment())
5620 size := t.Size()
5621 callArgs = append(callArgs, arg)
5622 callArgTypes = append(callArgTypes, t)
5623 off += size
5624 }
5625 off = types.RoundUp(off, int64(types.RegSize))
5626
5627
5628 var call *ssa.Value
5629 aux := ssa.StaticAuxCall(fn, s.f.ABIDefault.ABIAnalyzeTypes(callArgTypes, results))
5630 callArgs = append(callArgs, s.mem())
5631 call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
5632 call.AddArgs(callArgs...)
5633 s.vars[memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(results)), call)
5634
5635 if !returns {
5636
5637 b := s.endBlock()
5638 b.Kind = ssa.BlockExit
5639 b.SetControl(call)
5640 call.AuxInt = off - base.Ctxt.Arch.FixedFrameSize
5641 if len(results) > 0 {
5642 s.Fatalf("panic call can't have results")
5643 }
5644 return nil
5645 }
5646
5647
5648 res := make([]*ssa.Value, len(results))
5649 for i, t := range results {
5650 off = types.RoundUp(off, t.Alignment())
5651 res[i] = s.resultOfCall(call, int64(i), t)
5652 off += t.Size()
5653 }
5654 off = types.RoundUp(off, int64(types.PtrSize))
5655
5656
5657 call.AuxInt = off
5658
5659 return res
5660 }
5661
5662
5663 func (s *state) storeType(t *types.Type, left, right *ssa.Value, skip skipMask, leftIsStmt bool) {
5664 s.instrument(t, left, instrumentWrite)
5665
5666 if skip == 0 && (!t.HasPointers() || ssa.IsStackAddr(left)) {
5667
5668 s.vars[memVar] = s.newValue3Apos(ssa.OpStore, types.TypeMem, t, left, right, s.mem(), leftIsStmt)
5669 return
5670 }
5671
5672
5673
5674
5675
5676
5677 s.storeTypeScalars(t, left, right, skip)
5678 if skip&skipPtr == 0 && t.HasPointers() {
5679 s.storeTypePtrs(t, left, right)
5680 }
5681 }
5682
5683
5684 func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip skipMask) {
5685 switch {
5686 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex() || t.IsSIMD():
5687 s.store(t, left, right)
5688 case t.IsPtrShaped():
5689 if t.IsPtr() && t.Elem().NotInHeap() {
5690 s.store(t, left, right)
5691 }
5692
5693 case t.IsString():
5694 if skip&skipLen != 0 {
5695 return
5696 }
5697 len := s.newValue1(ssa.OpStringLen, types.Types[types.TINT], right)
5698 lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
5699 s.store(types.Types[types.TINT], lenAddr, len)
5700 case t.IsSlice():
5701 if skip&skipLen == 0 {
5702 len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], right)
5703 lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
5704 s.store(types.Types[types.TINT], lenAddr, len)
5705 }
5706 if skip&skipCap == 0 {
5707 cap := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], right)
5708 capAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, 2*s.config.PtrSize, left)
5709 s.store(types.Types[types.TINT], capAddr, cap)
5710 }
5711 case t.IsInterface():
5712
5713 itab := s.newValue1(ssa.OpITab, s.f.Config.Types.BytePtr, right)
5714 s.store(types.Types[types.TUINTPTR], left, itab)
5715 case isStructNotSIMD(t):
5716 n := t.NumFields()
5717 for i := 0; i < n; i++ {
5718 ft := t.FieldType(i)
5719 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
5720 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
5721 s.storeTypeScalars(ft, addr, val, 0)
5722 }
5723 case t.IsArray() && t.Size() == 0:
5724
5725 case t.IsArray() && t.NumElem() == 1:
5726 s.storeTypeScalars(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right), 0)
5727 default:
5728 s.Fatalf("bad write barrier type %v", t)
5729 }
5730 }
5731
5732
5733 func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
5734 switch {
5735 case t.IsPtrShaped():
5736 if t.IsPtr() && t.Elem().NotInHeap() {
5737 break
5738 }
5739 s.store(t, left, right)
5740 case t.IsString():
5741 ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right)
5742 s.store(s.f.Config.Types.BytePtr, left, ptr)
5743 case t.IsSlice():
5744 elType := types.NewPtr(t.Elem())
5745 ptr := s.newValue1(ssa.OpSlicePtr, elType, right)
5746 s.store(elType, left, ptr)
5747 case t.IsInterface():
5748
5749 idata := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, right)
5750 idataAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.BytePtrPtr, s.config.PtrSize, left)
5751 s.store(s.f.Config.Types.BytePtr, idataAddr, idata)
5752 case isStructNotSIMD(t):
5753 n := t.NumFields()
5754 for i := 0; i < n; i++ {
5755 ft := t.FieldType(i)
5756 if !ft.HasPointers() {
5757 continue
5758 }
5759 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
5760 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
5761 s.storeTypePtrs(ft, addr, val)
5762 }
5763 case t.IsArray() && t.Size() == 0:
5764
5765 case t.IsArray() && t.NumElem() == 1:
5766 s.storeTypePtrs(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right))
5767 default:
5768 s.Fatalf("bad write barrier type %v", t)
5769 }
5770 }
5771
5772
5773 func (s *state) putArg(n ir.Node, t *types.Type) *ssa.Value {
5774 var a *ssa.Value
5775 if !ssa.CanSSA(t) {
5776 a = s.newValue2(ssa.OpDereference, t, s.addr(n), s.mem())
5777 } else {
5778 a = s.expr(n)
5779 }
5780 return a
5781 }
5782
5783
5784
5785
5786 func (s *state) slice(v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value) {
5787 t := v.Type
5788 var ptr, len, cap *ssa.Value
5789 switch {
5790 case t.IsSlice():
5791 ptr = s.newValue1(ssa.OpSlicePtr, types.NewPtr(t.Elem()), v)
5792 len = s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], v)
5793 cap = s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], v)
5794 case t.IsString():
5795 ptr = s.newValue1(ssa.OpStringPtr, types.NewPtr(types.Types[types.TUINT8]), v)
5796 len = s.newValue1(ssa.OpStringLen, types.Types[types.TINT], v)
5797 cap = len
5798 case t.IsPtr():
5799 if !t.Elem().IsArray() {
5800 s.Fatalf("bad ptr to array in slice %v\n", t)
5801 }
5802 nv := s.nilCheck(v)
5803 ptr = s.newValue1(ssa.OpCopy, types.NewPtr(t.Elem().Elem()), nv)
5804 len = s.constInt(types.Types[types.TINT], t.Elem().NumElem())
5805 cap = len
5806 default:
5807 s.Fatalf("bad type in slice %v\n", t)
5808 }
5809
5810
5811 if i == nil {
5812 i = s.constInt(types.Types[types.TINT], 0)
5813 }
5814 if j == nil {
5815 j = len
5816 }
5817 three := true
5818 if k == nil {
5819 three = false
5820 k = cap
5821 }
5822
5823
5824
5825
5826 if three {
5827 if k != cap {
5828 kind := ssa.BoundsSlice3Alen
5829 if t.IsSlice() {
5830 kind = ssa.BoundsSlice3Acap
5831 }
5832 k = s.boundsCheck(k, cap, kind, bounded)
5833 }
5834 if j != k {
5835 j = s.boundsCheck(j, k, ssa.BoundsSlice3B, bounded)
5836 }
5837 i = s.boundsCheck(i, j, ssa.BoundsSlice3C, bounded)
5838 } else {
5839 if j != k {
5840 kind := ssa.BoundsSliceAlen
5841 if t.IsSlice() {
5842 kind = ssa.BoundsSliceAcap
5843 }
5844 j = s.boundsCheck(j, k, kind, bounded)
5845 }
5846 i = s.boundsCheck(i, j, ssa.BoundsSliceB, bounded)
5847 }
5848
5849
5850 subOp := s.ssaOp(ir.OSUB, types.Types[types.TINT])
5851 mulOp := s.ssaOp(ir.OMUL, types.Types[types.TINT])
5852 andOp := s.ssaOp(ir.OAND, types.Types[types.TINT])
5853
5854
5855
5856
5857
5858 rlen := s.newValue2(subOp, types.Types[types.TINT], j, i)
5859 rcap := rlen
5860 if j != k && !t.IsString() {
5861 rcap = s.newValue2(subOp, types.Types[types.TINT], k, i)
5862 }
5863
5864 if (i.Op == ssa.OpConst64 || i.Op == ssa.OpConst32) && i.AuxInt == 0 {
5865
5866 return ptr, rlen, rcap
5867 }
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883 stride := s.constInt(types.Types[types.TINT], ptr.Type.Elem().Size())
5884
5885
5886 delta := s.newValue2(mulOp, types.Types[types.TINT], i, stride)
5887
5888
5889
5890 mask := s.newValue1(ssa.OpSlicemask, types.Types[types.TINT], rcap)
5891 delta = s.newValue2(andOp, types.Types[types.TINT], delta, mask)
5892
5893
5894 rptr := s.newValue2(ssa.OpAddPtr, ptr.Type, ptr, delta)
5895
5896 return rptr, rlen, rcap
5897 }
5898
5899 type u642fcvtTab struct {
5900 leq, cvt2F, and, rsh, or, add ssa.Op
5901 one func(*state, *types.Type, int64) *ssa.Value
5902 }
5903
5904 var u64_f64 = u642fcvtTab{
5905 leq: ssa.OpLeq64,
5906 cvt2F: ssa.OpCvt64to64F,
5907 and: ssa.OpAnd64,
5908 rsh: ssa.OpRsh64Ux64,
5909 or: ssa.OpOr64,
5910 add: ssa.OpAdd64F,
5911 one: (*state).constInt64,
5912 }
5913
5914 var u64_f32 = u642fcvtTab{
5915 leq: ssa.OpLeq64,
5916 cvt2F: ssa.OpCvt64to32F,
5917 and: ssa.OpAnd64,
5918 rsh: ssa.OpRsh64Ux64,
5919 or: ssa.OpOr64,
5920 add: ssa.OpAdd32F,
5921 one: (*state).constInt64,
5922 }
5923
5924 func (s *state) uint64Tofloat64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5925 return s.uint64Tofloat(&u64_f64, n, x, ft, tt)
5926 }
5927
5928 func (s *state) uint64Tofloat32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5929 return s.uint64Tofloat(&u64_f32, n, x, ft, tt)
5930 }
5931
5932 func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958 cmp := s.newValue2(cvttab.leq, types.Types[types.TBOOL], s.zeroVal(ft), x)
5959
5960 b := s.endBlock()
5961 b.Kind = ssa.BlockIf
5962 b.SetControl(cmp)
5963 b.Likely = ssa.BranchLikely
5964
5965 bThen := s.f.NewBlock(ssa.BlockPlain)
5966 bElse := s.f.NewBlock(ssa.BlockPlain)
5967 bAfter := s.f.NewBlock(ssa.BlockPlain)
5968
5969 b.AddEdgeTo(bThen)
5970 s.startBlock(bThen)
5971 a0 := s.newValue1(cvttab.cvt2F, tt, x)
5972 s.vars[n] = a0
5973 s.endBlock()
5974 bThen.AddEdgeTo(bAfter)
5975
5976 b.AddEdgeTo(bElse)
5977 s.startBlock(bElse)
5978 one := cvttab.one(s, ft, 1)
5979 y := s.newValue2(cvttab.and, ft, x, one)
5980 z := s.newValue2(cvttab.rsh, ft, x, one)
5981 z = s.newValue2(cvttab.or, ft, z, y)
5982 a := s.newValue1(cvttab.cvt2F, tt, z)
5983 a1 := s.newValue2(cvttab.add, tt, a, a)
5984 s.vars[n] = a1
5985 s.endBlock()
5986 bElse.AddEdgeTo(bAfter)
5987
5988 s.startBlock(bAfter)
5989 return s.variable(n, n.Type())
5990 }
5991
5992 type u322fcvtTab struct {
5993 cvtI2F, cvtF2F ssa.Op
5994 }
5995
5996 var u32_f64 = u322fcvtTab{
5997 cvtI2F: ssa.OpCvt32to64F,
5998 cvtF2F: ssa.OpCopy,
5999 }
6000
6001 var u32_f32 = u322fcvtTab{
6002 cvtI2F: ssa.OpCvt32to32F,
6003 cvtF2F: ssa.OpCvt64Fto32F,
6004 }
6005
6006 func (s *state) uint32Tofloat64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6007 return s.uint32Tofloat(&u32_f64, n, x, ft, tt)
6008 }
6009
6010 func (s *state) uint32Tofloat32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6011 return s.uint32Tofloat(&u32_f32, n, x, ft, tt)
6012 }
6013
6014 func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6015
6016
6017
6018
6019
6020 cmp := s.newValue2(ssa.OpLeq32, types.Types[types.TBOOL], s.zeroVal(ft), x)
6021 b := s.endBlock()
6022 b.Kind = ssa.BlockIf
6023 b.SetControl(cmp)
6024 b.Likely = ssa.BranchLikely
6025
6026 bThen := s.f.NewBlock(ssa.BlockPlain)
6027 bElse := s.f.NewBlock(ssa.BlockPlain)
6028 bAfter := s.f.NewBlock(ssa.BlockPlain)
6029
6030 b.AddEdgeTo(bThen)
6031 s.startBlock(bThen)
6032 a0 := s.newValue1(cvttab.cvtI2F, tt, x)
6033 s.vars[n] = a0
6034 s.endBlock()
6035 bThen.AddEdgeTo(bAfter)
6036
6037 b.AddEdgeTo(bElse)
6038 s.startBlock(bElse)
6039 a1 := s.newValue1(ssa.OpCvt32to64F, types.Types[types.TFLOAT64], x)
6040 twoToThe32 := s.constFloat64(types.Types[types.TFLOAT64], float64(1<<32))
6041 a2 := s.newValue2(ssa.OpAdd64F, types.Types[types.TFLOAT64], a1, twoToThe32)
6042 a3 := s.newValue1(cvttab.cvtF2F, tt, a2)
6043
6044 s.vars[n] = a3
6045 s.endBlock()
6046 bElse.AddEdgeTo(bAfter)
6047
6048 s.startBlock(bAfter)
6049 return s.variable(n, n.Type())
6050 }
6051
6052
6053 func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
6054 if !n.X.Type().IsMap() && !n.X.Type().IsChan() {
6055 s.Fatalf("node must be a map or a channel")
6056 }
6057 if n.X.Type().IsChan() && n.Op() == ir.OLEN {
6058 s.Fatalf("cannot inline len(chan)")
6059 }
6060 if n.X.Type().IsChan() && n.Op() == ir.OCAP {
6061 s.Fatalf("cannot inline cap(chan)")
6062 }
6063 if n.X.Type().IsMap() && n.Op() == ir.OCAP {
6064 s.Fatalf("cannot inline cap(map)")
6065 }
6066
6067
6068
6069
6070
6071
6072
6073
6074 lenType := n.Type()
6075 nilValue := s.constNil(types.Types[types.TUINTPTR])
6076 cmp := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], x, nilValue)
6077 b := s.endBlock()
6078 b.Kind = ssa.BlockIf
6079 b.SetControl(cmp)
6080 b.Likely = ssa.BranchUnlikely
6081
6082 bThen := s.f.NewBlock(ssa.BlockPlain)
6083 bElse := s.f.NewBlock(ssa.BlockPlain)
6084 bAfter := s.f.NewBlock(ssa.BlockPlain)
6085
6086
6087 b.AddEdgeTo(bThen)
6088 s.startBlock(bThen)
6089 s.vars[n] = s.zeroVal(lenType)
6090 s.endBlock()
6091 bThen.AddEdgeTo(bAfter)
6092
6093 b.AddEdgeTo(bElse)
6094 s.startBlock(bElse)
6095 switch n.Op() {
6096 case ir.OLEN:
6097 if n.X.Type().IsMap() {
6098
6099 loadType := reflectdata.MapType().Field(0).Type
6100 load := s.load(loadType, x)
6101 s.vars[n] = s.conv(nil, load, loadType, lenType)
6102 } else {
6103
6104 s.vars[n] = s.load(lenType, x)
6105 }
6106 case ir.OCAP:
6107
6108 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Size(), x)
6109 s.vars[n] = s.load(lenType, sw)
6110 default:
6111 s.Fatalf("op must be OLEN or OCAP")
6112 }
6113 s.endBlock()
6114 bElse.AddEdgeTo(bAfter)
6115
6116 s.startBlock(bAfter)
6117 return s.variable(n, lenType)
6118 }
6119
6120 type f2uCvtTab struct {
6121 ltf, cvt2U, subf, or ssa.Op
6122 floatValue func(*state, *types.Type, float64) *ssa.Value
6123 intValue func(*state, *types.Type, int64) *ssa.Value
6124 cutoff uint64
6125 }
6126
6127 var f32_u64 = f2uCvtTab{
6128 ltf: ssa.OpLess32F,
6129 cvt2U: ssa.OpCvt32Fto64,
6130 subf: ssa.OpSub32F,
6131 or: ssa.OpOr64,
6132 floatValue: (*state).constFloat32,
6133 intValue: (*state).constInt64,
6134 cutoff: 1 << 63,
6135 }
6136
6137 var f64_u64 = f2uCvtTab{
6138 ltf: ssa.OpLess64F,
6139 cvt2U: ssa.OpCvt64Fto64,
6140 subf: ssa.OpSub64F,
6141 or: ssa.OpOr64,
6142 floatValue: (*state).constFloat64,
6143 intValue: (*state).constInt64,
6144 cutoff: 1 << 63,
6145 }
6146
6147 var f32_u32 = f2uCvtTab{
6148 ltf: ssa.OpLess32F,
6149 cvt2U: ssa.OpCvt32Fto32,
6150 subf: ssa.OpSub32F,
6151 or: ssa.OpOr32,
6152 floatValue: (*state).constFloat32,
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 var f64_u32 = f2uCvtTab{
6158 ltf: ssa.OpLess64F,
6159 cvt2U: ssa.OpCvt64Fto32,
6160 subf: ssa.OpSub64F,
6161 or: ssa.OpOr32,
6162 floatValue: (*state).constFloat64,
6163 intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
6164 cutoff: 1 << 31,
6165 }
6166
6167 func (s *state) float32ToUint64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6168 return s.floatToUint(&f32_u64, n, x, ft, tt)
6169 }
6170 func (s *state) float64ToUint64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6171 return s.floatToUint(&f64_u64, n, x, ft, tt)
6172 }
6173
6174 func (s *state) float32ToUint32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6175 return s.floatToUint(&f32_u32, n, x, ft, tt)
6176 }
6177
6178 func (s *state) float64ToUint32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6179 return s.floatToUint(&f64_u32, n, x, ft, tt)
6180 }
6181
6182 func (s *state) floatToUint(cvttab *f2uCvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196 cutoff := cvttab.floatValue(s, ft, float64(cvttab.cutoff))
6197 cmp := s.newValueOrSfCall2(cvttab.ltf, types.Types[types.TBOOL], x, cutoff)
6198 b := s.endBlock()
6199 b.Kind = ssa.BlockIf
6200 b.SetControl(cmp)
6201 b.Likely = ssa.BranchLikely
6202
6203 var bThen, bZero *ssa.Block
6204
6205 newConversion := base.ConvertHash.MatchPosWithInfo(n.Pos(), "U", nil)
6206 if newConversion {
6207 bZero = s.f.NewBlock(ssa.BlockPlain)
6208 bThen = s.f.NewBlock(ssa.BlockIf)
6209 } else {
6210 bThen = s.f.NewBlock(ssa.BlockPlain)
6211 }
6212
6213 bElse := s.f.NewBlock(ssa.BlockPlain)
6214 bAfter := s.f.NewBlock(ssa.BlockPlain)
6215
6216 b.AddEdgeTo(bThen)
6217 s.startBlock(bThen)
6218 a0 := s.newValueOrSfCall1(cvttab.cvt2U, tt, x)
6219 s.vars[n] = a0
6220
6221 if newConversion {
6222 cmpz := s.newValueOrSfCall2(cvttab.ltf, types.Types[types.TBOOL], x, cvttab.floatValue(s, ft, 0.0))
6223 s.endBlock()
6224 bThen.SetControl(cmpz)
6225 bThen.AddEdgeTo(bZero)
6226 bThen.Likely = ssa.BranchUnlikely
6227 bThen.AddEdgeTo(bAfter)
6228
6229 s.startBlock(bZero)
6230 s.vars[n] = cvttab.intValue(s, tt, 0)
6231 s.endBlock()
6232 bZero.AddEdgeTo(bAfter)
6233 } else {
6234 s.endBlock()
6235 bThen.AddEdgeTo(bAfter)
6236 }
6237
6238 b.AddEdgeTo(bElse)
6239 s.startBlock(bElse)
6240 y := s.newValueOrSfCall2(cvttab.subf, ft, x, cutoff)
6241 y = s.newValueOrSfCall1(cvttab.cvt2U, tt, y)
6242 z := cvttab.intValue(s, tt, int64(-cvttab.cutoff))
6243 a1 := s.newValue2(cvttab.or, tt, y, z)
6244 s.vars[n] = a1
6245 s.endBlock()
6246 bElse.AddEdgeTo(bAfter)
6247
6248 s.startBlock(bAfter)
6249 return s.variable(n, n.Type())
6250 }
6251
6252
6253
6254
6255 func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
6256 iface := s.expr(n.X)
6257 target := s.reflectType(n.Type())
6258 var targetItab *ssa.Value
6259 if n.ITab != nil {
6260 targetItab = s.expr(n.ITab)
6261 }
6262
6263 if n.UseNilPanic {
6264 if commaok {
6265 base.Fatalf("unexpected *ir.TypeAssertExpr with UseNilPanic == true && commaok == true")
6266 }
6267 if n.Type().IsInterface() {
6268
6269
6270 base.Fatalf("unexpected *ir.TypeAssertExpr with UseNilPanic == true && Type().IsInterface() == true")
6271 }
6272 typs := s.f.Config.Types
6273 iface = s.newValue2(
6274 ssa.OpIMake,
6275 iface.Type,
6276 s.nilCheck(s.newValue1(ssa.OpITab, typs.BytePtr, iface)),
6277 s.newValue1(ssa.OpIData, typs.BytePtr, iface),
6278 )
6279 }
6280
6281 return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, nil, target, targetItab, commaok, n.Descriptor)
6282 }
6283
6284 func (s *state) dynamicDottype(n *ir.DynamicTypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
6285 iface := s.expr(n.X)
6286 var source, target, targetItab *ssa.Value
6287 if n.SrcRType != nil {
6288 source = s.expr(n.SrcRType)
6289 }
6290 if !n.X.Type().IsEmptyInterface() && !n.Type().IsInterface() {
6291 byteptr := s.f.Config.Types.BytePtr
6292 targetItab = s.expr(n.ITab)
6293
6294
6295 target = s.load(byteptr, s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), targetItab))
6296 } else {
6297 target = s.expr(n.RType)
6298 }
6299 return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, source, target, targetItab, commaok, nil)
6300 }
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310 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) {
6311 typs := s.f.Config.Types
6312 byteptr := typs.BytePtr
6313 if dst.IsInterface() {
6314 if dst.IsEmptyInterface() {
6315
6316
6317 if base.Debug.TypeAssert > 0 {
6318 base.WarnfAt(pos, "type assertion inlined")
6319 }
6320
6321
6322 itab := s.newValue1(ssa.OpITab, byteptr, iface)
6323
6324 cond := s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6325
6326 if src.IsEmptyInterface() && commaok {
6327
6328 return iface, cond
6329 }
6330
6331
6332 b := s.endBlock()
6333 b.Kind = ssa.BlockIf
6334 b.SetControl(cond)
6335 b.Likely = ssa.BranchLikely
6336 bOk := s.f.NewBlock(ssa.BlockPlain)
6337 bFail := s.f.NewBlock(ssa.BlockPlain)
6338 b.AddEdgeTo(bOk)
6339 b.AddEdgeTo(bFail)
6340
6341 if !commaok {
6342
6343 s.startBlock(bFail)
6344 s.rtcall(ir.Syms.Panicnildottype, false, nil, target)
6345
6346
6347 s.startBlock(bOk)
6348 if src.IsEmptyInterface() {
6349 res = iface
6350 return
6351 }
6352
6353 off := s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab)
6354 typ := s.load(byteptr, off)
6355 idata := s.newValue1(ssa.OpIData, byteptr, iface)
6356 res = s.newValue2(ssa.OpIMake, dst, typ, idata)
6357 return
6358 }
6359
6360 s.startBlock(bOk)
6361
6362
6363 off := s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab)
6364 s.vars[typVar] = s.load(byteptr, off)
6365 s.endBlock()
6366
6367
6368 s.startBlock(bFail)
6369 s.vars[typVar] = itab
6370 s.endBlock()
6371
6372
6373 bEnd := s.f.NewBlock(ssa.BlockPlain)
6374 bOk.AddEdgeTo(bEnd)
6375 bFail.AddEdgeTo(bEnd)
6376 s.startBlock(bEnd)
6377 idata := s.newValue1(ssa.OpIData, byteptr, iface)
6378 res = s.newValue2(ssa.OpIMake, dst, s.variable(typVar, byteptr), idata)
6379 resok = cond
6380 delete(s.vars, typVar)
6381 return
6382 }
6383
6384 if base.Debug.TypeAssert > 0 {
6385 base.WarnfAt(pos, "type assertion not inlined")
6386 }
6387
6388 itab := s.newValue1(ssa.OpITab, byteptr, iface)
6389 data := s.newValue1(ssa.OpIData, types.Types[types.TUNSAFEPTR], iface)
6390
6391
6392 bNil := s.f.NewBlock(ssa.BlockPlain)
6393 bNonNil := s.f.NewBlock(ssa.BlockPlain)
6394 bMerge := s.f.NewBlock(ssa.BlockPlain)
6395 cond := s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6396 b := s.endBlock()
6397 b.Kind = ssa.BlockIf
6398 b.SetControl(cond)
6399 b.Likely = ssa.BranchLikely
6400 b.AddEdgeTo(bNonNil)
6401 b.AddEdgeTo(bNil)
6402
6403 s.startBlock(bNil)
6404 if commaok {
6405 s.vars[typVar] = itab
6406 b := s.endBlock()
6407 b.AddEdgeTo(bMerge)
6408 } else {
6409
6410 s.rtcall(ir.Syms.Panicnildottype, false, nil, target)
6411 }
6412
6413
6414 s.startBlock(bNonNil)
6415 typ := itab
6416 if !src.IsEmptyInterface() {
6417 typ = s.load(byteptr, s.newValue1I(ssa.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab))
6418 }
6419
6420
6421 var d *ssa.Value
6422 if descriptor != nil {
6423 d = s.newValue1A(ssa.OpAddr, byteptr, descriptor, s.sb)
6424 if base.Flag.N == 0 && rtabi.UseInterfaceSwitchCache(Arch.LinkArch.Family) {
6425
6426
6427 if intrinsics.lookup(Arch.LinkArch.Arch, "internal/runtime/atomic", "Loadp") == nil {
6428 s.Fatalf("atomic load not available")
6429 }
6430
6431 var mul, and, add, zext ssa.Op
6432 if s.config.PtrSize == 4 {
6433 mul = ssa.OpMul32
6434 and = ssa.OpAnd32
6435 add = ssa.OpAdd32
6436 zext = ssa.OpCopy
6437 } else {
6438 mul = ssa.OpMul64
6439 and = ssa.OpAnd64
6440 add = ssa.OpAdd64
6441 zext = ssa.OpZeroExt32to64
6442 }
6443
6444 loopHead := s.f.NewBlock(ssa.BlockPlain)
6445 loopBody := s.f.NewBlock(ssa.BlockPlain)
6446 cacheHit := s.f.NewBlock(ssa.BlockPlain)
6447 cacheMiss := s.f.NewBlock(ssa.BlockPlain)
6448
6449
6450
6451 atomicLoad := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(typs.BytePtr, types.TypeMem), d, s.mem())
6452 cache := s.newValue1(ssa.OpSelect0, typs.BytePtr, atomicLoad)
6453 s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, atomicLoad)
6454
6455
6456 var hash *ssa.Value
6457 if src.IsEmptyInterface() {
6458 hash = s.newValue2(ssa.OpLoad, typs.UInt32, s.newValue1I(ssa.OpOffPtr, typs.UInt32Ptr, rttype.Type.OffsetOf("Hash"), typ), s.mem())
6459 } else {
6460 hash = s.newValue2(ssa.OpLoad, typs.UInt32, s.newValue1I(ssa.OpOffPtr, typs.UInt32Ptr, rttype.ITab.OffsetOf("Hash"), itab), s.mem())
6461 }
6462 hash = s.newValue1(zext, typs.Uintptr, hash)
6463 s.vars[hashVar] = hash
6464
6465 mask := s.newValue2(ssa.OpLoad, typs.Uintptr, cache, s.mem())
6466
6467 b := s.endBlock()
6468 b.AddEdgeTo(loopHead)
6469
6470
6471
6472 s.startBlock(loopHead)
6473 idx := s.newValue2(and, typs.Uintptr, s.variable(hashVar, typs.Uintptr), mask)
6474 idx = s.newValue2(mul, typs.Uintptr, idx, s.uintptrConstant(uint64(2*s.config.PtrSize)))
6475 idx = s.newValue2(add, typs.Uintptr, idx, s.uintptrConstant(uint64(s.config.PtrSize)))
6476 e := s.newValue2(ssa.OpAddPtr, typs.UintptrPtr, cache, idx)
6477
6478 s.vars[hashVar] = s.newValue2(add, typs.Uintptr, s.variable(hashVar, typs.Uintptr), s.uintptrConstant(1))
6479
6480
6481
6482 eTyp := s.newValue2(ssa.OpLoad, typs.Uintptr, e, s.mem())
6483 cmp1 := s.newValue2(ssa.OpEqPtr, typs.Bool, typ, eTyp)
6484 b = s.endBlock()
6485 b.Kind = ssa.BlockIf
6486 b.SetControl(cmp1)
6487 b.AddEdgeTo(cacheHit)
6488 b.AddEdgeTo(loopBody)
6489
6490
6491
6492 s.startBlock(loopBody)
6493 cmp2 := s.newValue2(ssa.OpEqPtr, typs.Bool, eTyp, s.constNil(typs.BytePtr))
6494 b = s.endBlock()
6495 b.Kind = ssa.BlockIf
6496 b.SetControl(cmp2)
6497 b.AddEdgeTo(cacheMiss)
6498 b.AddEdgeTo(loopHead)
6499
6500
6501
6502 s.startBlock(cacheHit)
6503 eItab := s.newValue2(ssa.OpLoad, typs.BytePtr, s.newValue1I(ssa.OpOffPtr, typs.BytePtrPtr, s.config.PtrSize, e), s.mem())
6504 s.vars[typVar] = eItab
6505 b = s.endBlock()
6506 b.AddEdgeTo(bMerge)
6507
6508
6509 s.startBlock(cacheMiss)
6510 }
6511 }
6512
6513
6514 if descriptor != nil {
6515 itab = s.rtcall(ir.Syms.TypeAssert, true, []*types.Type{byteptr}, d, typ)[0]
6516 } else {
6517 var fn *obj.LSym
6518 if commaok {
6519 fn = ir.Syms.AssertE2I2
6520 } else {
6521 fn = ir.Syms.AssertE2I
6522 }
6523 itab = s.rtcall(fn, true, []*types.Type{byteptr}, target, typ)[0]
6524 }
6525 s.vars[typVar] = itab
6526 b = s.endBlock()
6527 b.AddEdgeTo(bMerge)
6528
6529
6530 s.startBlock(bMerge)
6531 itab = s.variable(typVar, byteptr)
6532 var ok *ssa.Value
6533 if commaok {
6534 ok = s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6535 }
6536 return s.newValue2(ssa.OpIMake, dst, itab, data), ok
6537 }
6538
6539 if base.Debug.TypeAssert > 0 {
6540 base.WarnfAt(pos, "type assertion inlined")
6541 }
6542
6543
6544 direct := types.IsDirectIface(dst)
6545 itab := s.newValue1(ssa.OpITab, byteptr, iface)
6546 if base.Debug.TypeAssert > 0 {
6547 base.WarnfAt(pos, "type assertion inlined")
6548 }
6549 var wantedFirstWord *ssa.Value
6550 if src.IsEmptyInterface() {
6551
6552 wantedFirstWord = target
6553 } else {
6554
6555 wantedFirstWord = targetItab
6556 }
6557
6558 var tmp ir.Node
6559 var addr *ssa.Value
6560 if commaok && !ssa.CanSSA(dst) {
6561
6562
6563 tmp, addr = s.temp(pos, dst)
6564 }
6565
6566 cond := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], itab, wantedFirstWord)
6567 b := s.endBlock()
6568 b.Kind = ssa.BlockIf
6569 b.SetControl(cond)
6570 b.Likely = ssa.BranchLikely
6571
6572 bOk := s.f.NewBlock(ssa.BlockPlain)
6573 bFail := s.f.NewBlock(ssa.BlockPlain)
6574 b.AddEdgeTo(bOk)
6575 b.AddEdgeTo(bFail)
6576
6577 if !commaok {
6578
6579 s.startBlock(bFail)
6580 taddr := source
6581 if taddr == nil {
6582 taddr = s.reflectType(src)
6583 }
6584 if src.IsEmptyInterface() {
6585 s.rtcall(ir.Syms.PanicdottypeE, false, nil, itab, target, taddr)
6586 } else {
6587 s.rtcall(ir.Syms.PanicdottypeI, false, nil, itab, target, taddr)
6588 }
6589
6590
6591 s.startBlock(bOk)
6592 if direct {
6593 return s.newValue1(ssa.OpIData, dst, iface), nil
6594 }
6595 p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
6596 return s.load(dst, p), nil
6597 }
6598
6599
6600
6601 bEnd := s.f.NewBlock(ssa.BlockPlain)
6602
6603
6604 valVar := ssaMarker("val")
6605
6606
6607 s.startBlock(bOk)
6608 if tmp == nil {
6609 if direct {
6610 s.vars[valVar] = s.newValue1(ssa.OpIData, dst, iface)
6611 } else {
6612 p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
6613 s.vars[valVar] = s.load(dst, p)
6614 }
6615 } else {
6616 p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
6617 s.move(dst, addr, p)
6618 }
6619 s.vars[okVar] = s.constBool(true)
6620 s.endBlock()
6621 bOk.AddEdgeTo(bEnd)
6622
6623
6624 s.startBlock(bFail)
6625 if tmp == nil {
6626 s.vars[valVar] = s.zeroVal(dst)
6627 } else {
6628 s.zero(dst, addr)
6629 }
6630 s.vars[okVar] = s.constBool(false)
6631 s.endBlock()
6632 bFail.AddEdgeTo(bEnd)
6633
6634
6635 s.startBlock(bEnd)
6636 if tmp == nil {
6637 res = s.variable(valVar, dst)
6638 delete(s.vars, valVar)
6639 } else {
6640 res = s.load(dst, addr)
6641 }
6642 resok = s.variable(okVar, types.Types[types.TBOOL])
6643 delete(s.vars, okVar)
6644 return res, resok
6645 }
6646
6647
6648 func (s *state) temp(pos src.XPos, t *types.Type) (*ir.Name, *ssa.Value) {
6649 tmp := typecheck.TempAt(pos, s.curfn, t)
6650 if t.HasPointers() || (ssa.IsMergeCandidate(tmp) && t != deferstruct()) {
6651 s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp, s.mem())
6652 }
6653 addr := s.addr(tmp)
6654 return tmp, addr
6655 }
6656
6657
6658 func (s *state) variable(n ir.Node, t *types.Type) *ssa.Value {
6659 v := s.vars[n]
6660 if v != nil {
6661 return v
6662 }
6663 v = s.fwdVars[n]
6664 if v != nil {
6665 return v
6666 }
6667
6668 if s.curBlock == s.f.Entry {
6669
6670 s.f.Fatalf("value %v (%v) incorrectly live at entry", n, v)
6671 }
6672
6673
6674 v = s.newValue0A(ssa.OpFwdRef, t, fwdRefAux{N: n})
6675 s.fwdVars[n] = v
6676 if n.Op() == ir.ONAME {
6677 s.addNamedValue(n.(*ir.Name), v)
6678 }
6679 return v
6680 }
6681
6682 func (s *state) mem() *ssa.Value {
6683 return s.variable(memVar, types.TypeMem)
6684 }
6685
6686 func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) {
6687 if n.Class == ir.Pxxx {
6688
6689 return
6690 }
6691 if ir.IsAutoTmp(n) {
6692
6693 return
6694 }
6695 if n.Class == ir.PPARAMOUT {
6696
6697
6698 return
6699 }
6700 loc := ssa.LocalSlot{N: n, Type: n.Type(), Off: 0}
6701 values, ok := s.f.NamedValues[loc]
6702 if !ok {
6703 s.f.Names = append(s.f.Names, &loc)
6704 s.f.CanonicalLocalSlots[loc] = &loc
6705 }
6706 s.f.NamedValues[loc] = append(values, v)
6707 }
6708
6709
6710 type Branch struct {
6711 P *obj.Prog
6712 B *ssa.Block
6713 }
6714
6715
6716 type State struct {
6717 ABI obj.ABI
6718
6719 pp *objw.Progs
6720
6721
6722
6723 Branches []Branch
6724
6725
6726 JumpTables []*ssa.Block
6727
6728
6729 bstart []*obj.Prog
6730
6731 maxarg int64
6732
6733
6734
6735 livenessMap liveness.Map
6736
6737
6738
6739 partLiveArgs map[*ir.Name]bool
6740
6741
6742
6743
6744 lineRunStart *obj.Prog
6745
6746
6747 OnWasmStackSkipped int
6748 }
6749
6750 func (s *State) FuncInfo() *obj.FuncInfo {
6751 return s.pp.CurFunc.LSym.Func()
6752 }
6753
6754
6755 func (s *State) Prog(as obj.As) *obj.Prog {
6756 p := s.pp.Prog(as)
6757 if objw.LosesStmtMark(as) {
6758 return p
6759 }
6760
6761
6762 if s.lineRunStart == nil || s.lineRunStart.Pos.Line() != p.Pos.Line() {
6763 s.lineRunStart = p
6764 } else if p.Pos.IsStmt() == src.PosIsStmt {
6765 s.lineRunStart.Pos = s.lineRunStart.Pos.WithIsStmt()
6766 p.Pos = p.Pos.WithNotStmt()
6767 }
6768 return p
6769 }
6770
6771
6772 func (s *State) Pc() *obj.Prog {
6773 return s.pp.Next
6774 }
6775
6776
6777 func (s *State) SetPos(pos src.XPos) {
6778 s.pp.Pos = pos
6779 }
6780
6781
6782
6783
6784 func (s *State) Br(op obj.As, target *ssa.Block) *obj.Prog {
6785 p := s.Prog(op)
6786 p.To.Type = obj.TYPE_BRANCH
6787 s.Branches = append(s.Branches, Branch{P: p, B: target})
6788 return p
6789 }
6790
6791
6792
6793
6794
6795
6796 func (s *State) DebugFriendlySetPosFrom(v *ssa.Value) {
6797 switch v.Op {
6798 case ssa.OpPhi, ssa.OpCopy, ssa.OpLoadReg, ssa.OpStoreReg:
6799
6800 s.SetPos(v.Pos.WithNotStmt())
6801 default:
6802 p := v.Pos
6803 if p != src.NoXPos {
6804
6805
6806
6807
6808 if p.IsStmt() != src.PosIsStmt {
6809 if s.pp.Pos.IsStmt() == src.PosIsStmt && s.pp.Pos.SameFileAndLine(p) {
6810
6811
6812
6813
6814
6815
6816
6817
6818
6819
6820
6821
6822
6823 return
6824 }
6825 p = p.WithNotStmt()
6826
6827 }
6828 s.SetPos(p)
6829 } else {
6830 s.SetPos(s.pp.Pos.WithNotStmt())
6831 }
6832 }
6833 }
6834
6835
6836 func emitArgInfo(e *ssafn, f *ssa.Func, pp *objw.Progs) {
6837 ft := e.curfn.Type()
6838 if ft.NumRecvs() == 0 && ft.NumParams() == 0 {
6839 return
6840 }
6841
6842 x := EmitArgInfo(e.curfn, f.OwnAux.ABIInfo())
6843 x.Set(obj.AttrContentAddressable, true)
6844 e.curfn.LSym.Func().ArgInfo = x
6845
6846
6847 p := pp.Prog(obj.AFUNCDATA)
6848 p.From.SetConst(rtabi.FUNCDATA_ArgInfo)
6849 p.To.Type = obj.TYPE_MEM
6850 p.To.Name = obj.NAME_EXTERN
6851 p.To.Sym = x
6852 }
6853
6854
6855 func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
6856 x := base.Ctxt.Lookup(fmt.Sprintf("%s.arginfo%d", f.LSym.Name, f.ABI))
6857 x.Align = 1
6858
6859
6860
6861
6862 PtrSize := int64(types.PtrSize)
6863 uintptrTyp := types.Types[types.TUINTPTR]
6864
6865 isAggregate := func(t *types.Type) bool {
6866 return isStructNotSIMD(t) || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice()
6867 }
6868
6869 wOff := 0
6870 n := 0
6871 writebyte := func(o uint8) { wOff = objw.Uint8(x, wOff, o) }
6872
6873
6874 write1 := func(sz, offset int64) {
6875 if offset >= rtabi.TraceArgsSpecial {
6876 writebyte(rtabi.TraceArgsOffsetTooLarge)
6877 } else {
6878 writebyte(uint8(offset))
6879 writebyte(uint8(sz))
6880 }
6881 n++
6882 }
6883
6884
6885
6886 var visitType func(baseOffset int64, t *types.Type, depth int) bool
6887 visitType = func(baseOffset int64, t *types.Type, depth int) bool {
6888 if n >= rtabi.TraceArgsLimit {
6889 writebyte(rtabi.TraceArgsDotdotdot)
6890 return false
6891 }
6892 if !isAggregate(t) {
6893 write1(t.Size(), baseOffset)
6894 return true
6895 }
6896 writebyte(rtabi.TraceArgsStartAgg)
6897 depth++
6898 if depth >= rtabi.TraceArgsMaxDepth {
6899 writebyte(rtabi.TraceArgsDotdotdot)
6900 writebyte(rtabi.TraceArgsEndAgg)
6901 n++
6902 return true
6903 }
6904 switch {
6905 case t.IsInterface(), t.IsString():
6906 _ = visitType(baseOffset, uintptrTyp, depth) &&
6907 visitType(baseOffset+PtrSize, uintptrTyp, depth)
6908 case t.IsSlice():
6909 _ = visitType(baseOffset, uintptrTyp, depth) &&
6910 visitType(baseOffset+PtrSize, uintptrTyp, depth) &&
6911 visitType(baseOffset+PtrSize*2, uintptrTyp, depth)
6912 case t.IsComplex():
6913 _ = visitType(baseOffset, types.FloatForComplex(t), depth) &&
6914 visitType(baseOffset+t.Size()/2, types.FloatForComplex(t), depth)
6915 case t.IsArray():
6916 if t.NumElem() == 0 {
6917 n++
6918 break
6919 }
6920 for i := int64(0); i < t.NumElem(); i++ {
6921 if !visitType(baseOffset, t.Elem(), depth) {
6922 break
6923 }
6924 baseOffset += t.Elem().Size()
6925 }
6926 case isStructNotSIMD(t):
6927 if t.NumFields() == 0 {
6928 n++
6929 break
6930 }
6931 for _, field := range t.Fields() {
6932 if !visitType(baseOffset+field.Offset, field.Type, depth) {
6933 break
6934 }
6935 }
6936 }
6937 writebyte(rtabi.TraceArgsEndAgg)
6938 return true
6939 }
6940
6941 start := 0
6942 if strings.Contains(f.LSym.Name, "[") {
6943
6944 start = 1
6945 }
6946
6947 for _, a := range abiInfo.InParams()[start:] {
6948 if !visitType(a.FrameOffset(abiInfo), a.Type, 0) {
6949 break
6950 }
6951 }
6952 writebyte(rtabi.TraceArgsEndSeq)
6953 if wOff > rtabi.TraceArgsMaxLen {
6954 base.Fatalf("ArgInfo too large")
6955 }
6956
6957 return x
6958 }
6959
6960
6961 func emitWrappedFuncInfo(e *ssafn, pp *objw.Progs) {
6962 if base.Ctxt.Flag_linkshared {
6963
6964
6965 return
6966 }
6967
6968 wfn := e.curfn.WrappedFunc
6969 if wfn == nil {
6970 return
6971 }
6972
6973 wsym := wfn.Linksym()
6974 x := base.Ctxt.LookupInit(fmt.Sprintf("%s.wrapinfo", wsym.Name), func(x *obj.LSym) {
6975 objw.SymPtrOff(x, 0, wsym)
6976 x.Set(obj.AttrContentAddressable, true)
6977 x.Align = 4
6978 })
6979 e.curfn.LSym.Func().WrapInfo = x
6980
6981
6982 p := pp.Prog(obj.AFUNCDATA)
6983 p.From.SetConst(rtabi.FUNCDATA_WrapInfo)
6984 p.To.Type = obj.TYPE_MEM
6985 p.To.Name = obj.NAME_EXTERN
6986 p.To.Sym = x
6987 }
6988
6989
6990 func genssa(f *ssa.Func, pp *objw.Progs) {
6991 var s State
6992 s.ABI = f.OwnAux.Fn.ABI()
6993
6994 e := f.Frontend().(*ssafn)
6995
6996 gatherPrintInfo := f.PrintOrHtmlSSA || ssa.GenssaDump[f.Name]
6997
6998 var lv *liveness.Liveness
6999 s.livenessMap, s.partLiveArgs, lv = liveness.Compute(e.curfn, f, e.stkptrsize, pp, gatherPrintInfo)
7000 emitArgInfo(e, f, pp)
7001 argLiveBlockMap, argLiveValueMap := liveness.ArgLiveness(e.curfn, f, pp)
7002
7003 openDeferInfo := e.curfn.LSym.Func().OpenCodedDeferInfo
7004 if openDeferInfo != nil {
7005
7006
7007 p := pp.Prog(obj.AFUNCDATA)
7008 p.From.SetConst(rtabi.FUNCDATA_OpenCodedDeferInfo)
7009 p.To.Type = obj.TYPE_MEM
7010 p.To.Name = obj.NAME_EXTERN
7011 p.To.Sym = openDeferInfo
7012 }
7013
7014 emitWrappedFuncInfo(e, pp)
7015
7016
7017 s.bstart = make([]*obj.Prog, f.NumBlocks())
7018 s.pp = pp
7019 var progToValue map[*obj.Prog]*ssa.Value
7020 var progToBlock map[*obj.Prog]*ssa.Block
7021 var valueToProgAfter []*obj.Prog
7022 if gatherPrintInfo {
7023 progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
7024 progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
7025 f.Logf("genssa %s\n", f.Name)
7026 progToBlock[s.pp.Next] = f.Blocks[0]
7027 }
7028
7029 if base.Ctxt.Flag_locationlists {
7030 if cap(f.Cache.ValueToProgAfter) < f.NumValues() {
7031 f.Cache.ValueToProgAfter = make([]*obj.Prog, f.NumValues())
7032 }
7033 valueToProgAfter = f.Cache.ValueToProgAfter[:f.NumValues()]
7034 clear(valueToProgAfter)
7035 }
7036
7037
7038
7039 firstPos := src.NoXPos
7040 for _, v := range f.Entry.Values {
7041 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 {
7042 firstPos = v.Pos
7043 v.Pos = firstPos.WithDefaultStmt()
7044 break
7045 }
7046 }
7047
7048
7049
7050
7051 var inlMarks map[*obj.Prog]int32
7052 var inlMarkList []*obj.Prog
7053
7054
7055
7056 var inlMarksByPos map[src.XPos][]*obj.Prog
7057
7058 var argLiveIdx int = -1
7059
7060
7061
7062
7063
7064 var hotAlign, hotRequire int64
7065
7066 if base.Debug.AlignHot > 0 {
7067 switch base.Ctxt.Arch.Name {
7068
7069
7070
7071
7072
7073 case "amd64", "386":
7074
7075
7076
7077 hotAlign = 64
7078 hotRequire = 31
7079 }
7080 }
7081
7082
7083 for i, b := range f.Blocks {
7084
7085 s.lineRunStart = nil
7086 s.SetPos(s.pp.Pos.WithNotStmt())
7087
7088 if hotAlign > 0 && b.Hotness&ssa.HotPgoInitial == ssa.HotPgoInitial {
7089
7090
7091
7092
7093
7094 p := s.pp.Prog(obj.APCALIGNMAX)
7095 p.From.SetConst(hotAlign)
7096 p.To.SetConst(hotRequire)
7097 }
7098
7099 s.bstart[b.ID] = s.pp.Next
7100
7101 if idx, ok := argLiveBlockMap[b.ID]; ok && idx != argLiveIdx {
7102 argLiveIdx = idx
7103 p := s.pp.Prog(obj.APCDATA)
7104 p.From.SetConst(rtabi.PCDATA_ArgLiveIndex)
7105 p.To.SetConst(int64(idx))
7106 }
7107
7108
7109 Arch.SSAMarkMoves(&s, b)
7110 for _, v := range b.Values {
7111 x := s.pp.Next
7112 s.DebugFriendlySetPosFrom(v)
7113
7114 if v.Op.ResultInArg0() && v.ResultReg() != v.Args[0].Reg() {
7115 v.Fatalf("input[0] and output not in same register %s", v.LongString())
7116 }
7117
7118 switch v.Op {
7119 case ssa.OpInitMem:
7120
7121 case ssa.OpArg:
7122
7123 case ssa.OpSP, ssa.OpSB:
7124
7125 case ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN, ssa.OpMakeResult:
7126
7127 case ssa.OpGetG:
7128
7129
7130 case ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive, ssa.OpWBend:
7131
7132 case ssa.OpPhi:
7133 CheckLoweredPhi(v)
7134 case ssa.OpConvert:
7135
7136 if v.Args[0].Reg() != v.Reg() {
7137 v.Fatalf("OpConvert should be a no-op: %s; %s", v.Args[0].LongString(), v.LongString())
7138 }
7139 case ssa.OpInlMark:
7140 p := Arch.Ginsnop(s.pp)
7141 if inlMarks == nil {
7142 inlMarks = map[*obj.Prog]int32{}
7143 inlMarksByPos = map[src.XPos][]*obj.Prog{}
7144 }
7145 inlMarks[p] = v.AuxInt32()
7146 inlMarkList = append(inlMarkList, p)
7147 pos := v.Pos.AtColumn1()
7148 inlMarksByPos[pos] = append(inlMarksByPos[pos], p)
7149 firstPos = src.NoXPos
7150
7151 default:
7152
7153 if firstPos != src.NoXPos && v.Op != ssa.OpArgIntReg && v.Op != ssa.OpArgFloatReg && v.Op != ssa.OpLoadReg && v.Op != ssa.OpStoreReg {
7154 s.SetPos(firstPos)
7155 firstPos = src.NoXPos
7156 }
7157
7158
7159 s.pp.NextLive = s.livenessMap.Get(v)
7160 s.pp.NextUnsafe = s.livenessMap.GetUnsafe(v)
7161
7162
7163 Arch.SSAGenValue(&s, v)
7164 }
7165
7166 if idx, ok := argLiveValueMap[v.ID]; ok && idx != argLiveIdx {
7167 argLiveIdx = idx
7168 p := s.pp.Prog(obj.APCDATA)
7169 p.From.SetConst(rtabi.PCDATA_ArgLiveIndex)
7170 p.To.SetConst(int64(idx))
7171 }
7172
7173 if base.Ctxt.Flag_locationlists {
7174 valueToProgAfter[v.ID] = s.pp.Next
7175 }
7176
7177 if gatherPrintInfo {
7178 for ; x != s.pp.Next; x = x.Link {
7179 progToValue[x] = v
7180 }
7181 }
7182 }
7183
7184 if s.bstart[b.ID] == s.pp.Next && len(b.Succs) == 1 && b.Succs[0].Block() == b {
7185 p := Arch.Ginsnop(s.pp)
7186 p.Pos = p.Pos.WithIsStmt()
7187 if b.Pos == src.NoXPos {
7188 b.Pos = p.Pos
7189 if b.Pos == src.NoXPos {
7190 b.Pos = s.pp.Text.Pos
7191 }
7192 }
7193 b.Pos = b.Pos.WithBogusLine()
7194 }
7195
7196
7197
7198
7199
7200 s.pp.NextUnsafe = s.livenessMap.GetUnsafeBlock(b)
7201
7202
7203 var next *ssa.Block
7204 if i < len(f.Blocks)-1 && base.Flag.N == 0 {
7205
7206
7207
7208
7209 next = f.Blocks[i+1]
7210 }
7211 x := s.pp.Next
7212 s.SetPos(b.Pos)
7213 Arch.SSAGenBlock(&s, b, next)
7214 if gatherPrintInfo {
7215 for ; x != s.pp.Next; x = x.Link {
7216 progToBlock[x] = b
7217 }
7218 }
7219 }
7220 if f.Blocks[len(f.Blocks)-1].Kind == ssa.BlockExit {
7221
7222
7223
7224
7225 Arch.Ginsnop(s.pp)
7226 }
7227 if openDeferInfo != nil {
7228
7229
7230
7231
7232
7233
7234
7235
7236 s.pp.NextLive = s.livenessMap.DeferReturn
7237 p := s.pp.Prog(obj.ACALL)
7238 p.To.Type = obj.TYPE_MEM
7239 p.To.Name = obj.NAME_EXTERN
7240 p.To.Sym = ir.Syms.Deferreturn
7241
7242
7243
7244
7245
7246 for _, o := range f.OwnAux.ABIInfo().OutParams() {
7247 n := o.Name
7248 rts, offs := o.RegisterTypesAndOffsets()
7249 for i := range o.Registers {
7250 Arch.LoadRegResult(&s, f, rts[i], ssa.ObjRegForAbiReg(o.Registers[i], f.Config), n, offs[i])
7251 }
7252 }
7253
7254 s.pp.Prog(obj.ARET)
7255 }
7256
7257 if inlMarks != nil {
7258 hasCall := false
7259
7260
7261
7262
7263 for p := s.pp.Text; p != nil; p = p.Link {
7264 if p.As == obj.ANOP || p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT ||
7265 p.As == obj.APCALIGN || p.As == obj.APCALIGNMAX || Arch.LinkArch.Family == sys.Wasm {
7266
7267
7268
7269
7270
7271 continue
7272 }
7273 if _, ok := inlMarks[p]; ok {
7274
7275
7276 continue
7277 }
7278 if p.As == obj.ACALL || p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
7279 hasCall = true
7280 }
7281 pos := p.Pos.AtColumn1()
7282 marks := inlMarksByPos[pos]
7283 if len(marks) == 0 {
7284 continue
7285 }
7286 for _, m := range marks {
7287
7288
7289
7290 p.Pos = p.Pos.WithIsStmt()
7291 s.pp.CurFunc.LSym.Func().AddInlMark(p, inlMarks[m])
7292
7293 m.As = obj.ANOP
7294 m.Pos = src.NoXPos
7295 m.From = obj.Addr{}
7296 m.To = obj.Addr{}
7297 }
7298 delete(inlMarksByPos, pos)
7299 }
7300
7301 for _, p := range inlMarkList {
7302 if p.As != obj.ANOP {
7303 s.pp.CurFunc.LSym.Func().AddInlMark(p, inlMarks[p])
7304 }
7305 }
7306
7307 if e.stksize == 0 && !hasCall {
7308
7309
7310
7311
7312
7313
7314 for p := s.pp.Text; p != nil; p = p.Link {
7315 if p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT || p.As == obj.ANOP {
7316 continue
7317 }
7318 if base.Ctxt.PosTable.Pos(p.Pos).Base().InliningIndex() >= 0 {
7319
7320 nop := Arch.Ginsnop(s.pp)
7321 nop.Pos = e.curfn.Pos().WithIsStmt()
7322
7323
7324
7325
7326
7327 for x := s.pp.Text; x != nil; x = x.Link {
7328 if x.Link == nop {
7329 x.Link = nop.Link
7330 break
7331 }
7332 }
7333
7334 for x := s.pp.Text; x != nil; x = x.Link {
7335 if x.Link == p {
7336 nop.Link = p
7337 x.Link = nop
7338 break
7339 }
7340 }
7341 }
7342 break
7343 }
7344 }
7345 }
7346
7347 if base.Ctxt.Flag_locationlists {
7348 var debugInfo *ssa.FuncDebug
7349 debugInfo = e.curfn.DebugInfo.(*ssa.FuncDebug)
7350
7351
7352 debugInfo.EntryID = f.Entry.ID
7353 if e.curfn.ABI == obj.ABIInternal && base.Flag.N != 0 {
7354 ssa.BuildFuncDebugNoOptimized(base.Ctxt, f, base.Debug.LocationLists > 1, StackOffset, debugInfo)
7355 } else {
7356 ssa.BuildFuncDebug(base.Ctxt, f, base.Debug.LocationLists, StackOffset, debugInfo)
7357 }
7358 bstart := s.bstart
7359 idToIdx := make([]int, f.NumBlocks())
7360 for i, b := range f.Blocks {
7361 idToIdx[b.ID] = i
7362 }
7363
7364
7365
7366 debugInfo.GetPC = func(b, v ssa.ID) int64 {
7367 switch v {
7368 case ssa.BlockStart.ID:
7369 if b == f.Entry.ID {
7370 return 0
7371
7372 }
7373 return bstart[b].Pc
7374 case ssa.BlockEnd.ID:
7375 blk := f.Blocks[idToIdx[b]]
7376 nv := len(blk.Values)
7377 return valueToProgAfter[blk.Values[nv-1].ID].Pc
7378 case ssa.FuncEnd.ID:
7379 return e.curfn.LSym.Size
7380 default:
7381 return valueToProgAfter[v].Pc
7382 }
7383 }
7384 }
7385
7386
7387 for _, br := range s.Branches {
7388 br.P.To.SetTarget(s.bstart[br.B.ID])
7389 if br.P.Pos.IsStmt() != src.PosIsStmt {
7390 br.P.Pos = br.P.Pos.WithNotStmt()
7391 } else if v0 := br.B.FirstPossibleStmtValue(); v0 != nil && v0.Pos.Line() == br.P.Pos.Line() && v0.Pos.IsStmt() == src.PosIsStmt {
7392 br.P.Pos = br.P.Pos.WithNotStmt()
7393 }
7394
7395 }
7396
7397
7398 for _, jt := range s.JumpTables {
7399
7400 targets := make([]*obj.Prog, len(jt.Succs))
7401 for i, e := range jt.Succs {
7402 targets[i] = s.bstart[e.Block().ID]
7403 }
7404
7405
7406
7407 fi := s.pp.CurFunc.LSym.Func()
7408 fi.JumpTables = append(fi.JumpTables, obj.JumpTable{Sym: jt.Aux.(*obj.LSym), Targets: targets})
7409 }
7410
7411 if e.log {
7412 filename := ""
7413 for p := s.pp.Text; p != nil; p = p.Link {
7414 if p.Pos.IsKnown() && p.InnermostFilename() != filename {
7415 filename = p.InnermostFilename()
7416 f.Logf("# %s\n", filename)
7417 }
7418
7419 var s string
7420 if v, ok := progToValue[p]; ok {
7421 s = v.String()
7422 } else if b, ok := progToBlock[p]; ok {
7423 s = b.String()
7424 } else {
7425 s = " "
7426 }
7427 f.Logf(" %-6s\t%.5d (%s)\t%s\n", s, p.Pc, p.InnermostLineNumber(), p.InstructionString())
7428 }
7429 }
7430 if f.HTMLWriter != nil {
7431 var buf strings.Builder
7432 buf.WriteString("<code>")
7433 buf.WriteString("<dl class=\"ssa-gen\">")
7434 filename := ""
7435
7436 liveness := lv.Format(nil)
7437 if liveness != "" {
7438 buf.WriteString("<dt class=\"ssa-prog-src\"></dt><dd class=\"ssa-prog\">")
7439 buf.WriteString(html.EscapeString("# " + liveness))
7440 buf.WriteString("</dd>")
7441 }
7442
7443 for p := s.pp.Text; p != nil; p = p.Link {
7444
7445
7446 if p.Pos.IsKnown() && p.InnermostFilename() != filename {
7447 filename = p.InnermostFilename()
7448 buf.WriteString("<dt class=\"ssa-prog-src\"></dt><dd class=\"ssa-prog\">")
7449 buf.WriteString(html.EscapeString("# " + filename))
7450 buf.WriteString("</dd>")
7451 }
7452
7453 buf.WriteString("<dt class=\"ssa-prog-src\">")
7454 if v, ok := progToValue[p]; ok {
7455
7456
7457 if p.As != obj.APCDATA {
7458 if liveness := lv.Format(v); liveness != "" {
7459
7460 buf.WriteString("</dt><dd class=\"ssa-prog\">")
7461 buf.WriteString(html.EscapeString("# " + liveness))
7462 buf.WriteString("</dd>")
7463
7464 buf.WriteString("<dt class=\"ssa-prog-src\">")
7465 }
7466 }
7467
7468 buf.WriteString(v.HTML())
7469 } else if b, ok := progToBlock[p]; ok {
7470 buf.WriteString("<b>" + b.HTML() + "</b>")
7471 }
7472 buf.WriteString("</dt>")
7473 buf.WriteString("<dd class=\"ssa-prog\">")
7474 fmt.Fprintf(&buf, "%.5d <span class=\"l%v line-number\">(%s)</span> %s", p.Pc, p.InnermostLineNumber(), p.InnermostLineNumberHTML(), html.EscapeString(p.InstructionString()))
7475 buf.WriteString("</dd>")
7476 }
7477 buf.WriteString("</dl>")
7478 buf.WriteString("</code>")
7479 f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String())
7480 }
7481 if ssa.GenssaDump[f.Name] {
7482 fi := f.DumpFileForPhase("genssa")
7483 if fi != nil {
7484
7485
7486 inliningDiffers := func(a, b []src.Pos) bool {
7487 if len(a) != len(b) {
7488 return true
7489 }
7490 for i := range a {
7491 if a[i].Filename() != b[i].Filename() {
7492 return true
7493 }
7494 if i != len(a)-1 && a[i].Line() != b[i].Line() {
7495 return true
7496 }
7497 }
7498 return false
7499 }
7500
7501 var allPosOld []src.Pos
7502 var allPos []src.Pos
7503
7504 for p := s.pp.Text; p != nil; p = p.Link {
7505 if p.Pos.IsKnown() {
7506 allPos = allPos[:0]
7507 p.Ctxt.AllPos(p.Pos, func(pos src.Pos) { allPos = append(allPos, pos) })
7508 if inliningDiffers(allPos, allPosOld) {
7509 for _, pos := range allPos {
7510 fmt.Fprintf(fi, "# %s:%d\n", pos.Filename(), pos.Line())
7511 }
7512 allPos, allPosOld = allPosOld, allPos
7513 }
7514 }
7515
7516 var s string
7517 if v, ok := progToValue[p]; ok {
7518 s = v.String()
7519 } else if b, ok := progToBlock[p]; ok {
7520 s = b.String()
7521 } else {
7522 s = " "
7523 }
7524 fmt.Fprintf(fi, " %-6s\t%.5d %s\t%s\n", s, p.Pc, ssa.StmtString(p.Pos), p.InstructionString())
7525 }
7526 fi.Close()
7527 }
7528 }
7529
7530 defframe(&s, e, f)
7531
7532 f.HTMLWriter.Close()
7533 f.HTMLWriter = nil
7534 }
7535
7536 func defframe(s *State, e *ssafn, f *ssa.Func) {
7537 pp := s.pp
7538
7539 s.maxarg = types.RoundUp(s.maxarg, e.stkalign)
7540 frame := s.maxarg + e.stksize
7541 if Arch.PadFrame != nil {
7542 frame = Arch.PadFrame(frame)
7543 }
7544
7545
7546 pp.Text.To.Type = obj.TYPE_TEXTSIZE
7547 pp.Text.To.Val = int32(types.RoundUp(f.OwnAux.ArgWidth(), int64(types.RegSize)))
7548 pp.Text.To.Offset = frame
7549
7550 p := pp.Text
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
7561 if f.OwnAux.ABIInfo().InRegistersUsed() != 0 && base.Flag.N == 0 {
7562
7563
7564 type nameOff struct {
7565 n *ir.Name
7566 off int64
7567 }
7568 partLiveArgsSpilled := make(map[nameOff]bool)
7569 for _, v := range f.Entry.Values {
7570 if v.Op.IsCall() {
7571 break
7572 }
7573 if v.Op != ssa.OpStoreReg || v.Args[0].Op != ssa.OpArgIntReg {
7574 continue
7575 }
7576 n, off := ssa.AutoVar(v)
7577 if n.Class != ir.PPARAM || n.Addrtaken() || !ssa.CanSSA(n.Type()) || !s.partLiveArgs[n] {
7578 continue
7579 }
7580 partLiveArgsSpilled[nameOff{n, off}] = true
7581 }
7582
7583
7584 for _, a := range f.OwnAux.ABIInfo().InParams() {
7585 n := a.Name
7586 if n == nil || n.Addrtaken() || !ssa.CanSSA(n.Type()) || !s.partLiveArgs[n] || len(a.Registers) <= 1 {
7587 continue
7588 }
7589 rts, offs := a.RegisterTypesAndOffsets()
7590 for i := range a.Registers {
7591 if !rts[i].HasPointers() {
7592 continue
7593 }
7594 if partLiveArgsSpilled[nameOff{n, offs[i]}] {
7595 continue
7596 }
7597 reg := ssa.ObjRegForAbiReg(a.Registers[i], f.Config)
7598 p = Arch.SpillArgReg(pp, p, f, rts[i], reg, n, offs[i])
7599 }
7600 }
7601 }
7602
7603
7604
7605
7606 var lo, hi int64
7607
7608
7609
7610 var state uint32
7611
7612
7613
7614 for _, n := range e.curfn.Dcl {
7615 if !n.Needzero() {
7616 continue
7617 }
7618 if n.Class != ir.PAUTO {
7619 e.Fatalf(n.Pos(), "needzero class %d", n.Class)
7620 }
7621 if n.Type().Size()%int64(types.PtrSize) != 0 || n.FrameOffset()%int64(types.PtrSize) != 0 || n.Type().Size() == 0 {
7622 e.Fatalf(n.Pos(), "var %L has size %d offset %d", n, n.Type().Size(), n.Offset_)
7623 }
7624
7625 if lo != hi && n.FrameOffset()+n.Type().Size() >= lo-int64(2*types.RegSize) {
7626
7627 lo = n.FrameOffset()
7628 continue
7629 }
7630
7631
7632 p = Arch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
7633
7634
7635 lo = n.FrameOffset()
7636 hi = lo + n.Type().Size()
7637 }
7638
7639
7640 Arch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
7641 }
7642
7643
7644 type IndexJump struct {
7645 Jump obj.As
7646 Index int
7647 }
7648
7649 func (s *State) oneJump(b *ssa.Block, jump *IndexJump) {
7650 p := s.Br(jump.Jump, b.Succs[jump.Index].Block())
7651 p.Pos = b.Pos
7652 }
7653
7654
7655
7656 func (s *State) CombJump(b, next *ssa.Block, jumps *[2][2]IndexJump) {
7657 switch next {
7658 case b.Succs[0].Block():
7659 s.oneJump(b, &jumps[0][0])
7660 s.oneJump(b, &jumps[0][1])
7661 case b.Succs[1].Block():
7662 s.oneJump(b, &jumps[1][0])
7663 s.oneJump(b, &jumps[1][1])
7664 default:
7665 var q *obj.Prog
7666 if b.Likely != ssa.BranchUnlikely {
7667 s.oneJump(b, &jumps[1][0])
7668 s.oneJump(b, &jumps[1][1])
7669 q = s.Br(obj.AJMP, b.Succs[1].Block())
7670 } else {
7671 s.oneJump(b, &jumps[0][0])
7672 s.oneJump(b, &jumps[0][1])
7673 q = s.Br(obj.AJMP, b.Succs[0].Block())
7674 }
7675 q.Pos = b.Pos
7676 }
7677 }
7678
7679
7680 func AddAux(a *obj.Addr, v *ssa.Value) {
7681 AddAux2(a, v, v.AuxInt)
7682 }
7683 func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
7684 if a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR {
7685 v.Fatalf("bad AddAux addr %v", a)
7686 }
7687
7688 a.Offset += offset
7689
7690
7691 if v.Aux == nil {
7692 return
7693 }
7694
7695 switch n := v.Aux.(type) {
7696 case *ssa.AuxCall:
7697 a.Name = obj.NAME_EXTERN
7698 a.Sym = n.Fn
7699 case *obj.LSym:
7700 a.Name = obj.NAME_EXTERN
7701 a.Sym = n
7702 case *ir.Name:
7703 if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
7704 a.Name = obj.NAME_PARAM
7705 } else {
7706 a.Name = obj.NAME_AUTO
7707 }
7708 a.Sym = n.Linksym()
7709 a.Offset += n.FrameOffset()
7710 default:
7711 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
7712 }
7713 }
7714
7715
7716
7717 func (s *state) extendIndex(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
7718 size := idx.Type.Size()
7719 if size == s.config.PtrSize {
7720 return idx
7721 }
7722 if size > s.config.PtrSize {
7723
7724
7725 var lo *ssa.Value
7726 if idx.Type.IsSigned() {
7727 lo = s.newValue1(ssa.OpInt64Lo, types.Types[types.TINT], idx)
7728 } else {
7729 lo = s.newValue1(ssa.OpInt64Lo, types.Types[types.TUINT], idx)
7730 }
7731 if bounded || base.Flag.B != 0 {
7732 return lo
7733 }
7734 bNext := s.f.NewBlock(ssa.BlockPlain)
7735 bPanic := s.f.NewBlock(ssa.BlockExit)
7736 hi := s.newValue1(ssa.OpInt64Hi, types.Types[types.TUINT32], idx)
7737 cmp := s.newValue2(ssa.OpEq32, types.Types[types.TBOOL], hi, s.constInt32(types.Types[types.TUINT32], 0))
7738 if !idx.Type.IsSigned() {
7739 switch kind {
7740 case ssa.BoundsIndex:
7741 kind = ssa.BoundsIndexU
7742 case ssa.BoundsSliceAlen:
7743 kind = ssa.BoundsSliceAlenU
7744 case ssa.BoundsSliceAcap:
7745 kind = ssa.BoundsSliceAcapU
7746 case ssa.BoundsSliceB:
7747 kind = ssa.BoundsSliceBU
7748 case ssa.BoundsSlice3Alen:
7749 kind = ssa.BoundsSlice3AlenU
7750 case ssa.BoundsSlice3Acap:
7751 kind = ssa.BoundsSlice3AcapU
7752 case ssa.BoundsSlice3B:
7753 kind = ssa.BoundsSlice3BU
7754 case ssa.BoundsSlice3C:
7755 kind = ssa.BoundsSlice3CU
7756 }
7757 }
7758 b := s.endBlock()
7759 b.Kind = ssa.BlockIf
7760 b.SetControl(cmp)
7761 b.Likely = ssa.BranchLikely
7762 b.AddEdgeTo(bNext)
7763 b.AddEdgeTo(bPanic)
7764
7765 s.startBlock(bPanic)
7766 mem := s.newValue4I(ssa.OpPanicExtend, types.TypeMem, int64(kind), hi, lo, len, s.mem())
7767 s.endBlock().SetControl(mem)
7768 s.startBlock(bNext)
7769
7770 return lo
7771 }
7772
7773
7774 var op ssa.Op
7775 if idx.Type.IsSigned() {
7776 switch 10*size + s.config.PtrSize {
7777 case 14:
7778 op = ssa.OpSignExt8to32
7779 case 18:
7780 op = ssa.OpSignExt8to64
7781 case 24:
7782 op = ssa.OpSignExt16to32
7783 case 28:
7784 op = ssa.OpSignExt16to64
7785 case 48:
7786 op = ssa.OpSignExt32to64
7787 default:
7788 s.Fatalf("bad signed index extension %s", idx.Type)
7789 }
7790 } else {
7791 switch 10*size + s.config.PtrSize {
7792 case 14:
7793 op = ssa.OpZeroExt8to32
7794 case 18:
7795 op = ssa.OpZeroExt8to64
7796 case 24:
7797 op = ssa.OpZeroExt16to32
7798 case 28:
7799 op = ssa.OpZeroExt16to64
7800 case 48:
7801 op = ssa.OpZeroExt32to64
7802 default:
7803 s.Fatalf("bad unsigned index extension %s", idx.Type)
7804 }
7805 }
7806 return s.newValue1(op, types.Types[types.TINT], idx)
7807 }
7808
7809
7810
7811 func CheckLoweredPhi(v *ssa.Value) {
7812 if v.Op != ssa.OpPhi {
7813 v.Fatalf("CheckLoweredPhi called with non-phi value: %v", v.LongString())
7814 }
7815 if v.Type.IsMemory() {
7816 return
7817 }
7818 f := v.Block.Func
7819 loc := f.RegAlloc[v.ID]
7820 for _, a := range v.Args {
7821 if aloc := f.RegAlloc[a.ID]; aloc != loc {
7822 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)
7823 }
7824 }
7825 }
7826
7827
7828
7829
7830
7831 func CheckLoweredGetClosurePtr(v *ssa.Value) {
7832 entry := v.Block.Func.Entry
7833 if entry != v.Block {
7834 base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
7835 }
7836 for _, w := range entry.Values {
7837 if w == v {
7838 break
7839 }
7840 switch w.Op {
7841 case ssa.OpArgIntReg, ssa.OpArgFloatReg:
7842
7843 default:
7844 base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
7845 }
7846 }
7847 }
7848
7849
7850 func CheckArgReg(v *ssa.Value) {
7851 entry := v.Block.Func.Entry
7852 if entry != v.Block {
7853 base.Fatalf("in %s, badly placed ArgIReg or ArgFReg: %v %v", v.Block.Func.Name, v.Block, v)
7854 }
7855 }
7856
7857 func AddrAuto(a *obj.Addr, v *ssa.Value) {
7858 n, off := ssa.AutoVar(v)
7859 a.Type = obj.TYPE_MEM
7860 a.Sym = n.Linksym()
7861 a.Reg = int16(Arch.REGSP)
7862 a.Offset = n.FrameOffset() + off
7863 if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
7864 a.Name = obj.NAME_PARAM
7865 } else {
7866 a.Name = obj.NAME_AUTO
7867 }
7868 }
7869
7870
7871
7872 func (s *State) Call(v *ssa.Value) *obj.Prog {
7873 pPosIsStmt := s.pp.Pos.IsStmt()
7874 s.PrepareCall(v)
7875
7876 p := s.Prog(obj.ACALL)
7877 if pPosIsStmt == src.PosIsStmt {
7878 p.Pos = v.Pos.WithIsStmt()
7879 } else {
7880 p.Pos = v.Pos.WithNotStmt()
7881 }
7882 if sym, ok := v.Aux.(*ssa.AuxCall); ok && sym.Fn != nil {
7883 p.To.Type = obj.TYPE_MEM
7884 p.To.Name = obj.NAME_EXTERN
7885 p.To.Sym = sym.Fn
7886 } else {
7887
7888 switch Arch.LinkArch.Family {
7889 case sys.AMD64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X, sys.Wasm:
7890 p.To.Type = obj.TYPE_REG
7891 case sys.ARM, sys.ARM64, sys.Loong64, sys.MIPS, sys.MIPS64:
7892 p.To.Type = obj.TYPE_MEM
7893 default:
7894 base.Fatalf("unknown indirect call family")
7895 }
7896 p.To.Reg = v.Args[0].Reg()
7897 }
7898 return p
7899 }
7900
7901
7902
7903 func (s *State) TailCall(v *ssa.Value) *obj.Prog {
7904 p := s.Call(v)
7905 p.As = obj.ARET
7906 return p
7907 }
7908
7909
7910
7911
7912 func (s *State) PrepareCall(v *ssa.Value) {
7913 idx := s.livenessMap.Get(v)
7914 if !idx.StackMapValid() {
7915
7916 if sym, ok := v.Aux.(*ssa.AuxCall); !ok || !(sym.Fn == ir.Syms.WBZero || sym.Fn == ir.Syms.WBMove) {
7917 base.Fatalf("missing stack map index for %v", v.LongString())
7918 }
7919 }
7920
7921 call, ok := v.Aux.(*ssa.AuxCall)
7922
7923 if ok {
7924
7925
7926 if nowritebarrierrecCheck != nil {
7927 nowritebarrierrecCheck.recordCall(s.pp.CurFunc, call.Fn, v.Pos)
7928 }
7929 }
7930
7931 if s.maxarg < v.AuxInt {
7932 s.maxarg = v.AuxInt
7933 }
7934 }
7935
7936
7937
7938 func (s *State) UseArgs(n int64) {
7939 if s.maxarg < n {
7940 s.maxarg = n
7941 }
7942 }
7943
7944
7945 func fieldIdx(n *ir.SelectorExpr) int {
7946 t := n.X.Type()
7947 if !isStructNotSIMD(t) {
7948 panic("ODOT's LHS is not a struct")
7949 }
7950
7951 for i, f := range t.Fields() {
7952 if f.Sym == n.Sel {
7953 if f.Offset != n.Offset() {
7954 panic("field offset doesn't match")
7955 }
7956 return i
7957 }
7958 }
7959 panic(fmt.Sprintf("can't find field in expr %v\n", n))
7960
7961
7962
7963 }
7964
7965
7966
7967 type ssafn struct {
7968 curfn *ir.Func
7969 strings map[string]*obj.LSym
7970 stksize int64
7971 stkptrsize int64
7972
7973
7974
7975
7976
7977 stkalign int64
7978
7979 log bool
7980 }
7981
7982
7983
7984 func (e *ssafn) StringData(s string) *obj.LSym {
7985 if aux, ok := e.strings[s]; ok {
7986 return aux
7987 }
7988 if e.strings == nil {
7989 e.strings = make(map[string]*obj.LSym)
7990 }
7991 data := staticdata.StringSym(e.curfn.Pos(), s)
7992 e.strings[s] = data
7993 return data
7994 }
7995
7996
7997 func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
7998 node := parent.N
7999
8000 if node.Class != ir.PAUTO || node.Addrtaken() {
8001
8002 return ssa.LocalSlot{N: node, Type: t, Off: parent.Off + offset}
8003 }
8004
8005 sym := &types.Sym{Name: node.Sym().Name + suffix, Pkg: types.LocalPkg}
8006 n := e.curfn.NewLocal(parent.N.Pos(), sym, t)
8007 n.SetUsed(true)
8008 n.SetEsc(ir.EscNever)
8009 types.CalcSize(t)
8010 return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset}
8011 }
8012
8013
8014 func (e *ssafn) Logf(msg string, args ...any) {
8015 if e.log {
8016 fmt.Printf(msg, args...)
8017 }
8018 }
8019
8020 func (e *ssafn) Log() bool {
8021 return e.log
8022 }
8023
8024
8025 func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...any) {
8026 base.Pos = pos
8027 nargs := append([]any{ir.FuncName(e.curfn)}, args...)
8028 base.Fatalf("'%s': "+msg, nargs...)
8029 }
8030
8031
8032
8033 func (e *ssafn) Warnl(pos src.XPos, fmt_ string, args ...any) {
8034 base.WarnfAt(pos, fmt_, args...)
8035 }
8036
8037 func (e *ssafn) Debug_checknil() bool {
8038 return base.Debug.Nil != 0
8039 }
8040
8041 func (e *ssafn) UseWriteBarrier() bool {
8042 return base.Flag.WB
8043 }
8044
8045 func (e *ssafn) Syslook(name string) *obj.LSym {
8046 switch name {
8047 case "goschedguarded":
8048 return ir.Syms.Goschedguarded
8049 case "writeBarrier":
8050 return ir.Syms.WriteBarrier
8051 case "wbZero":
8052 return ir.Syms.WBZero
8053 case "wbMove":
8054 return ir.Syms.WBMove
8055 case "cgoCheckMemmove":
8056 return ir.Syms.CgoCheckMemmove
8057 case "cgoCheckPtrWrite":
8058 return ir.Syms.CgoCheckPtrWrite
8059 }
8060 e.Fatalf(src.NoXPos, "unknown Syslook func %v", name)
8061 return nil
8062 }
8063
8064 func (e *ssafn) Func() *ir.Func {
8065 return e.curfn
8066 }
8067
8068 func clobberBase(n ir.Node) ir.Node {
8069 if n.Op() == ir.ODOT {
8070 n := n.(*ir.SelectorExpr)
8071 if n.X.Type().NumFields() == 1 {
8072 return clobberBase(n.X)
8073 }
8074 }
8075 if n.Op() == ir.OINDEX {
8076 n := n.(*ir.IndexExpr)
8077 if n.X.Type().IsArray() && n.X.Type().NumElem() == 1 {
8078 return clobberBase(n.X)
8079 }
8080 }
8081 return n
8082 }
8083
8084
8085 func callTargetLSym(callee *ir.Name) *obj.LSym {
8086 if callee.Func == nil {
8087
8088
8089
8090 return callee.Linksym()
8091 }
8092
8093 return callee.LinksymABI(callee.Func.ABI)
8094 }
8095
8096
8097 const deferStructFnField = 4
8098
8099 var deferType *types.Type
8100
8101
8102
8103 func deferstruct() *types.Type {
8104 if deferType != nil {
8105 return deferType
8106 }
8107
8108 makefield := func(name string, t *types.Type) *types.Field {
8109 sym := (*types.Pkg)(nil).Lookup(name)
8110 return types.NewField(src.NoXPos, sym, t)
8111 }
8112
8113 fields := []*types.Field{
8114 makefield("heap", types.Types[types.TBOOL]),
8115 makefield("rangefunc", types.Types[types.TBOOL]),
8116 makefield("sp", types.Types[types.TUINTPTR]),
8117 makefield("pc", types.Types[types.TUINTPTR]),
8118
8119
8120
8121 makefield("fn", types.Types[types.TUINTPTR]),
8122 makefield("link", types.Types[types.TUINTPTR]),
8123 makefield("head", types.Types[types.TUINTPTR]),
8124 }
8125 if name := fields[deferStructFnField].Sym.Name; name != "fn" {
8126 base.Fatalf("deferStructFnField is %q, not fn", name)
8127 }
8128
8129 n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.Pkgs.Runtime.Lookup("_defer"))
8130 typ := types.NewNamed(n)
8131 n.SetType(typ)
8132 n.SetTypecheck(1)
8133
8134
8135 typ.SetUnderlying(types.NewStruct(fields))
8136 types.CalcStructSize(typ)
8137
8138 deferType = typ
8139 return typ
8140 }
8141
8142
8143
8144
8145
8146 func SpillSlotAddr(spill ssa.Spill, baseReg int16, extraOffset int64) obj.Addr {
8147 return obj.Addr{
8148 Name: obj.NAME_NONE,
8149 Type: obj.TYPE_MEM,
8150 Reg: baseReg,
8151 Offset: spill.Offset + extraOffset,
8152 }
8153 }
8154
8155 func isStructNotSIMD(t *types.Type) bool {
8156 return t.IsStruct() && !t.IsSIMD()
8157 }
8158
8159 var BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
8160
View as plain text