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