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