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