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