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 if n.Pos().IsStmt() == src.PosNotStmt {
2051
2052
2053
2054 b.Pos = s.lastPos.WithNotStmt()
2055 } else {
2056 b.Pos = s.lastPos.WithIsStmt()
2057 }
2058 b.AddEdgeTo(to)
2059
2060 case ir.OFOR:
2061
2062
2063 n := n.(*ir.ForStmt)
2064 base.Assert(!n.DistinctVars)
2065 bCond := s.f.NewBlock(block.BlockPlain)
2066 bBody := s.f.NewBlock(block.BlockPlain)
2067 bIncr := s.f.NewBlock(block.BlockPlain)
2068 bEnd := s.f.NewBlock(block.BlockPlain)
2069
2070
2071 bBody.Pos = n.Pos()
2072
2073
2074 b := s.endBlock()
2075 b.AddEdgeTo(bCond)
2076
2077
2078 s.startBlock(bCond)
2079 if n.Cond != nil {
2080 s.condBranch(n.Cond, bBody, bEnd, 1)
2081 } else {
2082 b := s.endBlock()
2083 b.Kind = block.BlockPlain
2084 b.AddEdgeTo(bBody)
2085 }
2086
2087
2088 prevContinue := s.continueTo
2089 prevBreak := s.breakTo
2090 s.continueTo = bIncr
2091 s.breakTo = bEnd
2092 var lab *ssaLabel
2093 if sym := n.Label; sym != nil {
2094
2095 lab = s.label(sym)
2096 lab.continueTarget = bIncr
2097 lab.breakTarget = bEnd
2098 }
2099
2100
2101 s.startBlock(bBody)
2102 s.stmtList(n.Body)
2103
2104
2105 s.continueTo = prevContinue
2106 s.breakTo = prevBreak
2107 if lab != nil {
2108 lab.continueTarget = nil
2109 lab.breakTarget = nil
2110 }
2111
2112
2113 if b := s.endBlock(); b != nil {
2114 b.AddEdgeTo(bIncr)
2115 }
2116
2117
2118 s.startBlock(bIncr)
2119 if n.Post != nil {
2120 s.stmt(n.Post)
2121 }
2122 if b := s.endBlock(); b != nil {
2123 b.AddEdgeTo(bCond)
2124
2125
2126 if b.Pos == src.NoXPos {
2127 b.Pos = bCond.Pos
2128 }
2129 }
2130
2131 s.startBlock(bEnd)
2132
2133 case ir.OSWITCH, ir.OSELECT:
2134
2135
2136 bEnd := s.f.NewBlock(block.BlockPlain)
2137
2138 prevBreak := s.breakTo
2139 s.breakTo = bEnd
2140 var sym *types.Sym
2141 var body ir.Nodes
2142 if n.Op() == ir.OSWITCH {
2143 n := n.(*ir.SwitchStmt)
2144 sym = n.Label
2145 body = n.Compiled
2146 } else {
2147 n := n.(*ir.SelectStmt)
2148 sym = n.Label
2149 body = n.Compiled
2150 }
2151
2152 var lab *ssaLabel
2153 if sym != nil {
2154
2155 lab = s.label(sym)
2156 lab.breakTarget = bEnd
2157 }
2158
2159
2160
2161
2162
2163
2164
2165 if s.curBlock != nil && n.Pos().IsStmt() != src.PosNotStmt {
2166 b := s.endBlock()
2167 b.Pos = n.Pos().WithIsStmt()
2168 bStart := s.f.NewBlock(block.BlockPlain)
2169 b.AddEdgeTo(bStart)
2170 s.startBlock(bStart)
2171 }
2172
2173
2174 s.stmtList(body)
2175
2176 s.breakTo = prevBreak
2177 if lab != nil {
2178 lab.breakTarget = nil
2179 }
2180
2181
2182
2183 if s.curBlock != nil {
2184 m := s.mem()
2185 b := s.endBlock()
2186 b.Kind = block.BlockExit
2187 b.SetControl(m)
2188 }
2189 s.startBlock(bEnd)
2190
2191 case ir.OJUMPTABLE:
2192 n := n.(*ir.JumpTableStmt)
2193
2194
2195 jt := s.f.NewBlock(block.BlockJumpTable)
2196 bEnd := s.f.NewBlock(block.BlockPlain)
2197
2198
2199 idx := s.expr(n.Idx)
2200 unsigned := idx.Type.IsUnsigned()
2201
2202
2203 t := types.Types[types.TUINTPTR]
2204 idx = s.conv(nil, idx, idx.Type, t)
2205
2206
2207
2208
2209
2210
2211
2212 var min, max uint64
2213 if unsigned {
2214 min, _ = constant.Uint64Val(n.Cases[0])
2215 max, _ = constant.Uint64Val(n.Cases[len(n.Cases)-1])
2216 } else {
2217 mn, _ := constant.Int64Val(n.Cases[0])
2218 mx, _ := constant.Int64Val(n.Cases[len(n.Cases)-1])
2219 min = uint64(mn)
2220 max = uint64(mx)
2221 }
2222
2223 idx = s.newValue2(s.ssaOp(ir.OSUB, t), t, idx, s.uintptrConstant(min))
2224 width := s.uintptrConstant(max - min)
2225 cmp := s.newValue2(s.ssaOp(ir.OLE, t), types.Types[types.TBOOL], idx, width)
2226 b := s.endBlock()
2227 b.Kind = block.BlockIf
2228 b.SetControl(cmp)
2229 b.AddEdgeTo(jt)
2230 b.AddEdgeTo(bEnd)
2231 b.Likely = ssa.BranchLikely
2232
2233
2234 s.startBlock(jt)
2235 jt.Pos = n.Pos()
2236 if base.Flag.Cfg.SpectreIndex {
2237 idx = s.newValue2(ssaop.OpSpectreSliceIndex, t, idx, width)
2238 }
2239 jt.SetControl(idx)
2240
2241
2242 table := make([]*ssa.Block, max-min+1)
2243 for i := range table {
2244 table[i] = bEnd
2245 }
2246 for i := range n.Targets {
2247 c := n.Cases[i]
2248 lab := s.label(n.Targets[i])
2249 if lab.target == nil {
2250 lab.target = s.f.NewBlock(block.BlockPlain)
2251 }
2252 var val uint64
2253 if unsigned {
2254 val, _ = constant.Uint64Val(c)
2255 } else {
2256 vl, _ := constant.Int64Val(c)
2257 val = uint64(vl)
2258 }
2259
2260 table[val-min] = lab.target
2261 }
2262 for _, t := range table {
2263 jt.AddEdgeTo(t)
2264 }
2265 s.endBlock()
2266
2267 s.startBlock(bEnd)
2268
2269 case ir.OINTERFACESWITCH:
2270 n := n.(*ir.InterfaceSwitchStmt)
2271 typs := s.f.Config.Types
2272
2273 t := s.expr(n.RuntimeType)
2274 h := s.expr(n.Hash)
2275 d := s.newValue1A(ssaop.OpAddr, typs.BytePtr, n.Descriptor, s.sb)
2276
2277
2278 var merge *ssa.Block
2279 if base.Flag.N == 0 && rtabi.UseInterfaceSwitchCache(Arch.LinkArch.Family) {
2280
2281
2282 if intrinsics.lookup(Arch.LinkArch.Arch, "internal/runtime/atomic", "Loadp") == nil {
2283 s.Fatalf("atomic load not available")
2284 }
2285 merge = s.f.NewBlock(block.BlockPlain)
2286 cacheHit := s.f.NewBlock(block.BlockPlain)
2287 cacheMiss := s.f.NewBlock(block.BlockPlain)
2288 loopHead := s.f.NewBlock(block.BlockPlain)
2289 loopBody := s.f.NewBlock(block.BlockPlain)
2290
2291
2292 var mul, and, add, zext ssaop.Op
2293 if s.config.PtrSize == 4 {
2294 mul = ssaop.OpMul32
2295 and = ssaop.OpAnd32
2296 add = ssaop.OpAdd32
2297 zext = ssaop.OpCopy
2298 } else {
2299 mul = ssaop.OpMul64
2300 and = ssaop.OpAnd64
2301 add = ssaop.OpAdd64
2302 zext = ssaop.OpZeroExt32to64
2303 }
2304
2305
2306
2307 atomicLoad := s.newValue2(ssaop.OpAtomicLoadPtr, types.NewTuple(typs.BytePtr, types.TypeMem), d, s.mem())
2308 cache := s.newValue1(ssaop.OpSelect0, typs.BytePtr, atomicLoad)
2309 s.vars[memVar] = s.newValue1(ssaop.OpSelect1, types.TypeMem, atomicLoad)
2310
2311
2312 s.vars[hashVar] = s.newValue1(zext, typs.Uintptr, h)
2313
2314
2315 mask := s.newValue2(ssaop.OpLoad, typs.Uintptr, cache, s.mem())
2316
2317 b := s.endBlock()
2318 b.AddEdgeTo(loopHead)
2319
2320
2321
2322 s.startBlock(loopHead)
2323 entries := s.newValue2(ssaop.OpAddPtr, typs.UintptrPtr, cache, s.uintptrConstant(uint64(s.config.PtrSize)))
2324 idx := s.newValue2(and, typs.Uintptr, s.variable(hashVar, typs.Uintptr), mask)
2325 idx = s.newValue2(mul, typs.Uintptr, idx, s.uintptrConstant(uint64(3*s.config.PtrSize)))
2326 e := s.newValue2(ssaop.OpAddPtr, typs.UintptrPtr, entries, idx)
2327
2328 s.vars[hashVar] = s.newValue2(add, typs.Uintptr, s.variable(hashVar, typs.Uintptr), s.uintptrConstant(1))
2329
2330
2331
2332 eTyp := s.newValue2(ssaop.OpLoad, typs.Uintptr, e, s.mem())
2333 cmp1 := s.newValue2(ssaop.OpEqPtr, typs.Bool, t, eTyp)
2334 b = s.endBlock()
2335 b.Kind = block.BlockIf
2336 b.SetControl(cmp1)
2337 b.AddEdgeTo(cacheHit)
2338 b.AddEdgeTo(loopBody)
2339
2340
2341
2342 s.startBlock(loopBody)
2343 cmp2 := s.newValue2(ssaop.OpEqPtr, typs.Bool, eTyp, s.constNil(typs.BytePtr))
2344 b = s.endBlock()
2345 b.Kind = block.BlockIf
2346 b.SetControl(cmp2)
2347 b.AddEdgeTo(cacheMiss)
2348 b.AddEdgeTo(loopHead)
2349
2350
2351
2352
2353 s.startBlock(cacheHit)
2354 eCase := s.newValue2(ssaop.OpLoad, typs.Int, s.newValue1I(ssaop.OpOffPtr, typs.IntPtr, s.config.PtrSize, e), s.mem())
2355 eItab := s.newValue2(ssaop.OpLoad, typs.BytePtr, s.newValue1I(ssaop.OpOffPtr, typs.BytePtrPtr, 2*s.config.PtrSize, e), s.mem())
2356 s.assign(n.Case, eCase, false, 0)
2357 s.assign(n.Itab, eItab, false, 0)
2358 b = s.endBlock()
2359 b.AddEdgeTo(merge)
2360
2361
2362 s.startBlock(cacheMiss)
2363 }
2364
2365 r := s.rtcall(ir.Syms.InterfaceSwitch, true, []*types.Type{typs.Int, typs.BytePtr}, d, t)
2366 s.assign(n.Case, r[0], false, 0)
2367 s.assign(n.Itab, r[1], false, 0)
2368
2369 if merge != nil {
2370
2371 b := s.endBlock()
2372 b.Kind = block.BlockPlain
2373 b.AddEdgeTo(merge)
2374 s.startBlock(merge)
2375 }
2376
2377 case ir.OCHECKNIL:
2378 n := n.(*ir.UnaryExpr)
2379 p := s.expr(n.X)
2380 _ = s.nilCheck(p)
2381
2382
2383 case ir.OINLMARK:
2384 n := n.(*ir.InlineMarkStmt)
2385 s.newValue1I(ssaop.OpInlMark, types.TypeVoid, n.Index, s.mem())
2386
2387 default:
2388 s.Fatalf("unhandled stmt %v", n.Op())
2389 }
2390 }
2391
2392
2393
2394 const shareDeferExits = false
2395
2396
2397
2398
2399 func (s *state) exit() *ssa.Block {
2400 if s.hasdefer {
2401 if s.hasOpenDefers {
2402 if shareDeferExits && s.lastDeferExit != nil && len(s.openDefers) == s.lastDeferCount {
2403 if s.curBlock.Kind != block.BlockPlain {
2404 panic("Block for an exit should be BlockPlain")
2405 }
2406 s.curBlock.AddEdgeTo(s.lastDeferExit)
2407 s.endBlock()
2408 return s.lastDeferFinalBlock
2409 }
2410 s.openDeferExit()
2411 } else {
2412
2413
2414
2415
2416
2417
2418
2419
2420 s.pushLine(s.curfn.Endlineno)
2421 s.rtcall(ir.Syms.Deferreturn, true, nil)
2422 s.popLine()
2423 }
2424 }
2425
2426
2427
2428 resultFields := s.curfn.Type().Results()
2429 results := make([]*ssa.Value, len(resultFields)+1, len(resultFields)+1)
2430
2431 for i, f := range resultFields {
2432 n := f.Nname.(*ir.Name)
2433 if s.canSSA(n) {
2434 if !n.IsOutputParamInRegisters() && n.Type().HasPointers() {
2435
2436 s.vars[memVar] = s.newValue1A(ssaop.OpVarDef, types.TypeMem, n, s.mem())
2437 }
2438 results[i] = s.variable(n, n.Type())
2439 } else if !n.OnStack() {
2440
2441 if n.Type().HasPointers() {
2442 s.vars[memVar] = s.newValue1A(ssaop.OpVarDef, types.TypeMem, n, s.mem())
2443 }
2444 ha := s.expr(n.Heapaddr)
2445 s.instrumentFields(n.Type(), ha, instrumentRead)
2446 results[i] = s.newValue2(ssaop.OpDereference, n.Type(), ha, s.mem())
2447 } else {
2448
2449
2450
2451 results[i] = s.newValue2(ssaop.OpDereference, n.Type(), s.addr(n), s.mem())
2452 }
2453 }
2454
2455
2456
2457
2458 if s.instrumentEnterExit {
2459 s.rtcall(ir.Syms.Racefuncexit, true, nil)
2460 }
2461
2462 results[len(results)-1] = s.mem()
2463 m := s.newValue0(ssaop.OpMakeResult, s.f.OwnAux.LateExpansionResultType())
2464 m.AddArgs(results...)
2465
2466 b := s.endBlock()
2467 b.Kind = block.BlockRet
2468 b.SetControl(m)
2469 if s.hasdefer && s.hasOpenDefers {
2470 s.lastDeferFinalBlock = b
2471 }
2472 return b
2473 }
2474
2475 type opAndType struct {
2476 op ir.Op
2477 etype types.Kind
2478 }
2479
2480 var opToSSA = map[opAndType]ssaop.Op{
2481 {ir.OADD, types.TINT8}: ssaop.OpAdd8,
2482 {ir.OADD, types.TUINT8}: ssaop.OpAdd8,
2483 {ir.OADD, types.TINT16}: ssaop.OpAdd16,
2484 {ir.OADD, types.TUINT16}: ssaop.OpAdd16,
2485 {ir.OADD, types.TINT32}: ssaop.OpAdd32,
2486 {ir.OADD, types.TUINT32}: ssaop.OpAdd32,
2487 {ir.OADD, types.TINT64}: ssaop.OpAdd64,
2488 {ir.OADD, types.TUINT64}: ssaop.OpAdd64,
2489 {ir.OADD, types.TFLOAT32}: ssaop.OpAdd32F,
2490 {ir.OADD, types.TFLOAT64}: ssaop.OpAdd64F,
2491
2492 {ir.OSUB, types.TINT8}: ssaop.OpSub8,
2493 {ir.OSUB, types.TUINT8}: ssaop.OpSub8,
2494 {ir.OSUB, types.TINT16}: ssaop.OpSub16,
2495 {ir.OSUB, types.TUINT16}: ssaop.OpSub16,
2496 {ir.OSUB, types.TINT32}: ssaop.OpSub32,
2497 {ir.OSUB, types.TUINT32}: ssaop.OpSub32,
2498 {ir.OSUB, types.TINT64}: ssaop.OpSub64,
2499 {ir.OSUB, types.TUINT64}: ssaop.OpSub64,
2500 {ir.OSUB, types.TFLOAT32}: ssaop.OpSub32F,
2501 {ir.OSUB, types.TFLOAT64}: ssaop.OpSub64F,
2502
2503 {ir.ONOT, types.TBOOL}: ssaop.OpNot,
2504
2505 {ir.ONEG, types.TINT8}: ssaop.OpNeg8,
2506 {ir.ONEG, types.TUINT8}: ssaop.OpNeg8,
2507 {ir.ONEG, types.TINT16}: ssaop.OpNeg16,
2508 {ir.ONEG, types.TUINT16}: ssaop.OpNeg16,
2509 {ir.ONEG, types.TINT32}: ssaop.OpNeg32,
2510 {ir.ONEG, types.TUINT32}: ssaop.OpNeg32,
2511 {ir.ONEG, types.TINT64}: ssaop.OpNeg64,
2512 {ir.ONEG, types.TUINT64}: ssaop.OpNeg64,
2513 {ir.ONEG, types.TFLOAT32}: ssaop.OpNeg32F,
2514 {ir.ONEG, types.TFLOAT64}: ssaop.OpNeg64F,
2515
2516 {ir.OBITNOT, types.TINT8}: ssaop.OpCom8,
2517 {ir.OBITNOT, types.TUINT8}: ssaop.OpCom8,
2518 {ir.OBITNOT, types.TINT16}: ssaop.OpCom16,
2519 {ir.OBITNOT, types.TUINT16}: ssaop.OpCom16,
2520 {ir.OBITNOT, types.TINT32}: ssaop.OpCom32,
2521 {ir.OBITNOT, types.TUINT32}: ssaop.OpCom32,
2522 {ir.OBITNOT, types.TINT64}: ssaop.OpCom64,
2523 {ir.OBITNOT, types.TUINT64}: ssaop.OpCom64,
2524
2525 {ir.OIMAG, types.TCOMPLEX64}: ssaop.OpComplexImag,
2526 {ir.OIMAG, types.TCOMPLEX128}: ssaop.OpComplexImag,
2527 {ir.OREAL, types.TCOMPLEX64}: ssaop.OpComplexReal,
2528 {ir.OREAL, types.TCOMPLEX128}: ssaop.OpComplexReal,
2529
2530 {ir.OMUL, types.TINT8}: ssaop.OpMul8,
2531 {ir.OMUL, types.TUINT8}: ssaop.OpMul8,
2532 {ir.OMUL, types.TINT16}: ssaop.OpMul16,
2533 {ir.OMUL, types.TUINT16}: ssaop.OpMul16,
2534 {ir.OMUL, types.TINT32}: ssaop.OpMul32,
2535 {ir.OMUL, types.TUINT32}: ssaop.OpMul32,
2536 {ir.OMUL, types.TINT64}: ssaop.OpMul64,
2537 {ir.OMUL, types.TUINT64}: ssaop.OpMul64,
2538 {ir.OMUL, types.TFLOAT32}: ssaop.OpMul32F,
2539 {ir.OMUL, types.TFLOAT64}: ssaop.OpMul64F,
2540
2541 {ir.ODIV, types.TFLOAT32}: ssaop.OpDiv32F,
2542 {ir.ODIV, types.TFLOAT64}: ssaop.OpDiv64F,
2543
2544 {ir.ODIV, types.TINT8}: ssaop.OpDiv8,
2545 {ir.ODIV, types.TUINT8}: ssaop.OpDiv8u,
2546 {ir.ODIV, types.TINT16}: ssaop.OpDiv16,
2547 {ir.ODIV, types.TUINT16}: ssaop.OpDiv16u,
2548 {ir.ODIV, types.TINT32}: ssaop.OpDiv32,
2549 {ir.ODIV, types.TUINT32}: ssaop.OpDiv32u,
2550 {ir.ODIV, types.TINT64}: ssaop.OpDiv64,
2551 {ir.ODIV, types.TUINT64}: ssaop.OpDiv64u,
2552
2553 {ir.OMOD, types.TINT8}: ssaop.OpMod8,
2554 {ir.OMOD, types.TUINT8}: ssaop.OpMod8u,
2555 {ir.OMOD, types.TINT16}: ssaop.OpMod16,
2556 {ir.OMOD, types.TUINT16}: ssaop.OpMod16u,
2557 {ir.OMOD, types.TINT32}: ssaop.OpMod32,
2558 {ir.OMOD, types.TUINT32}: ssaop.OpMod32u,
2559 {ir.OMOD, types.TINT64}: ssaop.OpMod64,
2560 {ir.OMOD, types.TUINT64}: ssaop.OpMod64u,
2561
2562 {ir.OAND, types.TINT8}: ssaop.OpAnd8,
2563 {ir.OAND, types.TUINT8}: ssaop.OpAnd8,
2564 {ir.OAND, types.TINT16}: ssaop.OpAnd16,
2565 {ir.OAND, types.TUINT16}: ssaop.OpAnd16,
2566 {ir.OAND, types.TINT32}: ssaop.OpAnd32,
2567 {ir.OAND, types.TUINT32}: ssaop.OpAnd32,
2568 {ir.OAND, types.TINT64}: ssaop.OpAnd64,
2569 {ir.OAND, types.TUINT64}: ssaop.OpAnd64,
2570
2571 {ir.OOR, types.TINT8}: ssaop.OpOr8,
2572 {ir.OOR, types.TUINT8}: ssaop.OpOr8,
2573 {ir.OOR, types.TINT16}: ssaop.OpOr16,
2574 {ir.OOR, types.TUINT16}: ssaop.OpOr16,
2575 {ir.OOR, types.TINT32}: ssaop.OpOr32,
2576 {ir.OOR, types.TUINT32}: ssaop.OpOr32,
2577 {ir.OOR, types.TINT64}: ssaop.OpOr64,
2578 {ir.OOR, types.TUINT64}: ssaop.OpOr64,
2579
2580 {ir.OXOR, types.TINT8}: ssaop.OpXor8,
2581 {ir.OXOR, types.TUINT8}: ssaop.OpXor8,
2582 {ir.OXOR, types.TINT16}: ssaop.OpXor16,
2583 {ir.OXOR, types.TUINT16}: ssaop.OpXor16,
2584 {ir.OXOR, types.TINT32}: ssaop.OpXor32,
2585 {ir.OXOR, types.TUINT32}: ssaop.OpXor32,
2586 {ir.OXOR, types.TINT64}: ssaop.OpXor64,
2587 {ir.OXOR, types.TUINT64}: ssaop.OpXor64,
2588
2589 {ir.OEQ, types.TBOOL}: ssaop.OpEqB,
2590 {ir.OEQ, types.TINT8}: ssaop.OpEq8,
2591 {ir.OEQ, types.TUINT8}: ssaop.OpEq8,
2592 {ir.OEQ, types.TINT16}: ssaop.OpEq16,
2593 {ir.OEQ, types.TUINT16}: ssaop.OpEq16,
2594 {ir.OEQ, types.TINT32}: ssaop.OpEq32,
2595 {ir.OEQ, types.TUINT32}: ssaop.OpEq32,
2596 {ir.OEQ, types.TINT64}: ssaop.OpEq64,
2597 {ir.OEQ, types.TUINT64}: ssaop.OpEq64,
2598 {ir.OEQ, types.TINTER}: ssaop.OpEqInter,
2599 {ir.OEQ, types.TSLICE}: ssaop.OpEqSlice,
2600 {ir.OEQ, types.TFUNC}: ssaop.OpEqPtr,
2601 {ir.OEQ, types.TMAP}: ssaop.OpEqPtr,
2602 {ir.OEQ, types.TCHAN}: ssaop.OpEqPtr,
2603 {ir.OEQ, types.TPTR}: ssaop.OpEqPtr,
2604 {ir.OEQ, types.TUINTPTR}: ssaop.OpEqPtr,
2605 {ir.OEQ, types.TUNSAFEPTR}: ssaop.OpEqPtr,
2606 {ir.OEQ, types.TFLOAT64}: ssaop.OpEq64F,
2607 {ir.OEQ, types.TFLOAT32}: ssaop.OpEq32F,
2608
2609 {ir.ONE, types.TBOOL}: ssaop.OpNeqB,
2610 {ir.ONE, types.TINT8}: ssaop.OpNeq8,
2611 {ir.ONE, types.TUINT8}: ssaop.OpNeq8,
2612 {ir.ONE, types.TINT16}: ssaop.OpNeq16,
2613 {ir.ONE, types.TUINT16}: ssaop.OpNeq16,
2614 {ir.ONE, types.TINT32}: ssaop.OpNeq32,
2615 {ir.ONE, types.TUINT32}: ssaop.OpNeq32,
2616 {ir.ONE, types.TINT64}: ssaop.OpNeq64,
2617 {ir.ONE, types.TUINT64}: ssaop.OpNeq64,
2618 {ir.ONE, types.TINTER}: ssaop.OpNeqInter,
2619 {ir.ONE, types.TSLICE}: ssaop.OpNeqSlice,
2620 {ir.ONE, types.TFUNC}: ssaop.OpNeqPtr,
2621 {ir.ONE, types.TMAP}: ssaop.OpNeqPtr,
2622 {ir.ONE, types.TCHAN}: ssaop.OpNeqPtr,
2623 {ir.ONE, types.TPTR}: ssaop.OpNeqPtr,
2624 {ir.ONE, types.TUINTPTR}: ssaop.OpNeqPtr,
2625 {ir.ONE, types.TUNSAFEPTR}: ssaop.OpNeqPtr,
2626 {ir.ONE, types.TFLOAT64}: ssaop.OpNeq64F,
2627 {ir.ONE, types.TFLOAT32}: ssaop.OpNeq32F,
2628
2629 {ir.OLT, types.TINT8}: ssaop.OpLess8,
2630 {ir.OLT, types.TUINT8}: ssaop.OpLess8U,
2631 {ir.OLT, types.TINT16}: ssaop.OpLess16,
2632 {ir.OLT, types.TUINT16}: ssaop.OpLess16U,
2633 {ir.OLT, types.TINT32}: ssaop.OpLess32,
2634 {ir.OLT, types.TUINT32}: ssaop.OpLess32U,
2635 {ir.OLT, types.TINT64}: ssaop.OpLess64,
2636 {ir.OLT, types.TUINT64}: ssaop.OpLess64U,
2637 {ir.OLT, types.TFLOAT64}: ssaop.OpLess64F,
2638 {ir.OLT, types.TFLOAT32}: ssaop.OpLess32F,
2639
2640 {ir.OLE, types.TINT8}: ssaop.OpLeq8,
2641 {ir.OLE, types.TUINT8}: ssaop.OpLeq8U,
2642 {ir.OLE, types.TINT16}: ssaop.OpLeq16,
2643 {ir.OLE, types.TUINT16}: ssaop.OpLeq16U,
2644 {ir.OLE, types.TINT32}: ssaop.OpLeq32,
2645 {ir.OLE, types.TUINT32}: ssaop.OpLeq32U,
2646 {ir.OLE, types.TINT64}: ssaop.OpLeq64,
2647 {ir.OLE, types.TUINT64}: ssaop.OpLeq64U,
2648 {ir.OLE, types.TFLOAT64}: ssaop.OpLeq64F,
2649 {ir.OLE, types.TFLOAT32}: ssaop.OpLeq32F,
2650 }
2651
2652 func (s *state) concreteEtype(t *types.Type) types.Kind {
2653 e := t.Kind()
2654 switch e {
2655 default:
2656 return e
2657 case types.TINT:
2658 if s.config.PtrSize == 8 {
2659 return types.TINT64
2660 }
2661 return types.TINT32
2662 case types.TUINT:
2663 if s.config.PtrSize == 8 {
2664 return types.TUINT64
2665 }
2666 return types.TUINT32
2667 case types.TUINTPTR:
2668 if s.config.PtrSize == 8 {
2669 return types.TUINT64
2670 }
2671 return types.TUINT32
2672 }
2673 }
2674
2675 func (s *state) ssaOp(op ir.Op, t *types.Type) ssaop.Op {
2676 etype := s.concreteEtype(t)
2677 x, ok := opToSSA[opAndType{op, etype}]
2678 if !ok {
2679 s.Fatalf("unhandled binary op %v %s", op, etype)
2680 }
2681 return x
2682 }
2683
2684 type opAndTwoTypes struct {
2685 op ir.Op
2686 etype1 types.Kind
2687 etype2 types.Kind
2688 }
2689
2690 type twoTypes struct {
2691 etype1 types.Kind
2692 etype2 types.Kind
2693 }
2694
2695 type twoOpsAndType struct {
2696 op1 ssaop.Op
2697 op2 ssaop.Op
2698 intermediateType types.Kind
2699 }
2700
2701 var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
2702
2703 {types.TINT8, types.TFLOAT32}: {ssaop.OpSignExt8to32, ssaop.OpCvt32to32F, types.TINT32},
2704 {types.TINT16, types.TFLOAT32}: {ssaop.OpSignExt16to32, ssaop.OpCvt32to32F, types.TINT32},
2705 {types.TINT32, types.TFLOAT32}: {ssaop.OpCopy, ssaop.OpCvt32to32F, types.TINT32},
2706 {types.TINT64, types.TFLOAT32}: {ssaop.OpCopy, ssaop.OpCvt64to32F, types.TINT64},
2707
2708 {types.TINT8, types.TFLOAT64}: {ssaop.OpSignExt8to32, ssaop.OpCvt32to64F, types.TINT32},
2709 {types.TINT16, types.TFLOAT64}: {ssaop.OpSignExt16to32, ssaop.OpCvt32to64F, types.TINT32},
2710 {types.TINT32, types.TFLOAT64}: {ssaop.OpCopy, ssaop.OpCvt32to64F, types.TINT32},
2711 {types.TINT64, types.TFLOAT64}: {ssaop.OpCopy, ssaop.OpCvt64to64F, types.TINT64},
2712
2713 {types.TFLOAT32, types.TINT8}: {ssaop.OpCvt32Fto32, ssaop.OpTrunc32to8, types.TINT32},
2714 {types.TFLOAT32, types.TINT16}: {ssaop.OpCvt32Fto32, ssaop.OpTrunc32to16, types.TINT32},
2715 {types.TFLOAT32, types.TINT32}: {ssaop.OpCvt32Fto32, ssaop.OpCopy, types.TINT32},
2716 {types.TFLOAT32, types.TINT64}: {ssaop.OpCvt32Fto64, ssaop.OpCopy, types.TINT64},
2717
2718 {types.TFLOAT64, types.TINT8}: {ssaop.OpCvt64Fto32, ssaop.OpTrunc32to8, types.TINT32},
2719 {types.TFLOAT64, types.TINT16}: {ssaop.OpCvt64Fto32, ssaop.OpTrunc32to16, types.TINT32},
2720 {types.TFLOAT64, types.TINT32}: {ssaop.OpCvt64Fto32, ssaop.OpCopy, types.TINT32},
2721 {types.TFLOAT64, types.TINT64}: {ssaop.OpCvt64Fto64, ssaop.OpCopy, types.TINT64},
2722
2723 {types.TUINT8, types.TFLOAT32}: {ssaop.OpZeroExt8to32, ssaop.OpCvt32to32F, types.TINT32},
2724 {types.TUINT16, types.TFLOAT32}: {ssaop.OpZeroExt16to32, ssaop.OpCvt32to32F, types.TINT32},
2725 {types.TUINT32, types.TFLOAT32}: {ssaop.OpZeroExt32to64, ssaop.OpCvt64to32F, types.TINT64},
2726 {types.TUINT64, types.TFLOAT32}: {ssaop.OpCopy, ssaop.OpInvalid, types.TUINT64},
2727
2728 {types.TUINT8, types.TFLOAT64}: {ssaop.OpZeroExt8to32, ssaop.OpCvt32to64F, types.TINT32},
2729 {types.TUINT16, types.TFLOAT64}: {ssaop.OpZeroExt16to32, ssaop.OpCvt32to64F, types.TINT32},
2730 {types.TUINT32, types.TFLOAT64}: {ssaop.OpZeroExt32to64, ssaop.OpCvt64to64F, types.TINT64},
2731 {types.TUINT64, types.TFLOAT64}: {ssaop.OpCopy, ssaop.OpInvalid, types.TUINT64},
2732
2733 {types.TFLOAT32, types.TUINT8}: {ssaop.OpCvt32Fto32, ssaop.OpTrunc32to8, types.TINT32},
2734 {types.TFLOAT32, types.TUINT16}: {ssaop.OpCvt32Fto32, ssaop.OpTrunc32to16, types.TINT32},
2735 {types.TFLOAT32, types.TUINT32}: {ssaop.OpInvalid, ssaop.OpCopy, types.TINT64},
2736 {types.TFLOAT32, types.TUINT64}: {ssaop.OpInvalid, ssaop.OpCopy, types.TUINT64},
2737
2738 {types.TFLOAT64, types.TUINT8}: {ssaop.OpCvt64Fto32, ssaop.OpTrunc32to8, types.TINT32},
2739 {types.TFLOAT64, types.TUINT16}: {ssaop.OpCvt64Fto32, ssaop.OpTrunc32to16, types.TINT32},
2740 {types.TFLOAT64, types.TUINT32}: {ssaop.OpInvalid, ssaop.OpCopy, types.TINT64},
2741 {types.TFLOAT64, types.TUINT64}: {ssaop.OpInvalid, ssaop.OpCopy, types.TUINT64},
2742
2743
2744 {types.TFLOAT64, types.TFLOAT32}: {ssaop.OpCvt64Fto32F, ssaop.OpCopy, types.TFLOAT32},
2745 {types.TFLOAT64, types.TFLOAT64}: {ssaop.OpRound64F, ssaop.OpCopy, types.TFLOAT64},
2746 {types.TFLOAT32, types.TFLOAT32}: {ssaop.OpRound32F, ssaop.OpCopy, types.TFLOAT32},
2747 {types.TFLOAT32, types.TFLOAT64}: {ssaop.OpCvt32Fto64F, ssaop.OpCopy, types.TFLOAT64},
2748 }
2749
2750
2751
2752 var fpConvOpToSSA32 = map[twoTypes]twoOpsAndType{
2753 {types.TUINT32, types.TFLOAT32}: {ssaop.OpCopy, ssaop.OpCvt32Uto32F, types.TUINT32},
2754 {types.TUINT32, types.TFLOAT64}: {ssaop.OpCopy, ssaop.OpCvt32Uto64F, types.TUINT32},
2755 {types.TFLOAT32, types.TUINT32}: {ssaop.OpCvt32Fto32U, ssaop.OpCopy, types.TUINT32},
2756 {types.TFLOAT64, types.TUINT32}: {ssaop.OpCvt64Fto32U, ssaop.OpCopy, types.TUINT32},
2757 }
2758
2759
2760 var uint64fpConvOpToSSA = map[twoTypes]twoOpsAndType{
2761 {types.TUINT64, types.TFLOAT32}: {ssaop.OpCopy, ssaop.OpCvt64Uto32F, types.TUINT64},
2762 {types.TUINT64, types.TFLOAT64}: {ssaop.OpCopy, ssaop.OpCvt64Uto64F, types.TUINT64},
2763 {types.TFLOAT32, types.TUINT64}: {ssaop.OpCvt32Fto64U, ssaop.OpCopy, types.TUINT64},
2764 {types.TFLOAT64, types.TUINT64}: {ssaop.OpCvt64Fto64U, ssaop.OpCopy, types.TUINT64},
2765 }
2766
2767 var shiftOpToSSA = map[opAndTwoTypes]ssaop.Op{
2768 {ir.OLSH, types.TINT8, types.TUINT8}: ssaop.OpLsh8x8,
2769 {ir.OLSH, types.TUINT8, types.TUINT8}: ssaop.OpLsh8x8,
2770 {ir.OLSH, types.TINT8, types.TUINT16}: ssaop.OpLsh8x16,
2771 {ir.OLSH, types.TUINT8, types.TUINT16}: ssaop.OpLsh8x16,
2772 {ir.OLSH, types.TINT8, types.TUINT32}: ssaop.OpLsh8x32,
2773 {ir.OLSH, types.TUINT8, types.TUINT32}: ssaop.OpLsh8x32,
2774 {ir.OLSH, types.TINT8, types.TUINT64}: ssaop.OpLsh8x64,
2775 {ir.OLSH, types.TUINT8, types.TUINT64}: ssaop.OpLsh8x64,
2776
2777 {ir.OLSH, types.TINT16, types.TUINT8}: ssaop.OpLsh16x8,
2778 {ir.OLSH, types.TUINT16, types.TUINT8}: ssaop.OpLsh16x8,
2779 {ir.OLSH, types.TINT16, types.TUINT16}: ssaop.OpLsh16x16,
2780 {ir.OLSH, types.TUINT16, types.TUINT16}: ssaop.OpLsh16x16,
2781 {ir.OLSH, types.TINT16, types.TUINT32}: ssaop.OpLsh16x32,
2782 {ir.OLSH, types.TUINT16, types.TUINT32}: ssaop.OpLsh16x32,
2783 {ir.OLSH, types.TINT16, types.TUINT64}: ssaop.OpLsh16x64,
2784 {ir.OLSH, types.TUINT16, types.TUINT64}: ssaop.OpLsh16x64,
2785
2786 {ir.OLSH, types.TINT32, types.TUINT8}: ssaop.OpLsh32x8,
2787 {ir.OLSH, types.TUINT32, types.TUINT8}: ssaop.OpLsh32x8,
2788 {ir.OLSH, types.TINT32, types.TUINT16}: ssaop.OpLsh32x16,
2789 {ir.OLSH, types.TUINT32, types.TUINT16}: ssaop.OpLsh32x16,
2790 {ir.OLSH, types.TINT32, types.TUINT32}: ssaop.OpLsh32x32,
2791 {ir.OLSH, types.TUINT32, types.TUINT32}: ssaop.OpLsh32x32,
2792 {ir.OLSH, types.TINT32, types.TUINT64}: ssaop.OpLsh32x64,
2793 {ir.OLSH, types.TUINT32, types.TUINT64}: ssaop.OpLsh32x64,
2794
2795 {ir.OLSH, types.TINT64, types.TUINT8}: ssaop.OpLsh64x8,
2796 {ir.OLSH, types.TUINT64, types.TUINT8}: ssaop.OpLsh64x8,
2797 {ir.OLSH, types.TINT64, types.TUINT16}: ssaop.OpLsh64x16,
2798 {ir.OLSH, types.TUINT64, types.TUINT16}: ssaop.OpLsh64x16,
2799 {ir.OLSH, types.TINT64, types.TUINT32}: ssaop.OpLsh64x32,
2800 {ir.OLSH, types.TUINT64, types.TUINT32}: ssaop.OpLsh64x32,
2801 {ir.OLSH, types.TINT64, types.TUINT64}: ssaop.OpLsh64x64,
2802 {ir.OLSH, types.TUINT64, types.TUINT64}: ssaop.OpLsh64x64,
2803
2804 {ir.ORSH, types.TINT8, types.TUINT8}: ssaop.OpRsh8x8,
2805 {ir.ORSH, types.TUINT8, types.TUINT8}: ssaop.OpRsh8Ux8,
2806 {ir.ORSH, types.TINT8, types.TUINT16}: ssaop.OpRsh8x16,
2807 {ir.ORSH, types.TUINT8, types.TUINT16}: ssaop.OpRsh8Ux16,
2808 {ir.ORSH, types.TINT8, types.TUINT32}: ssaop.OpRsh8x32,
2809 {ir.ORSH, types.TUINT8, types.TUINT32}: ssaop.OpRsh8Ux32,
2810 {ir.ORSH, types.TINT8, types.TUINT64}: ssaop.OpRsh8x64,
2811 {ir.ORSH, types.TUINT8, types.TUINT64}: ssaop.OpRsh8Ux64,
2812
2813 {ir.ORSH, types.TINT16, types.TUINT8}: ssaop.OpRsh16x8,
2814 {ir.ORSH, types.TUINT16, types.TUINT8}: ssaop.OpRsh16Ux8,
2815 {ir.ORSH, types.TINT16, types.TUINT16}: ssaop.OpRsh16x16,
2816 {ir.ORSH, types.TUINT16, types.TUINT16}: ssaop.OpRsh16Ux16,
2817 {ir.ORSH, types.TINT16, types.TUINT32}: ssaop.OpRsh16x32,
2818 {ir.ORSH, types.TUINT16, types.TUINT32}: ssaop.OpRsh16Ux32,
2819 {ir.ORSH, types.TINT16, types.TUINT64}: ssaop.OpRsh16x64,
2820 {ir.ORSH, types.TUINT16, types.TUINT64}: ssaop.OpRsh16Ux64,
2821
2822 {ir.ORSH, types.TINT32, types.TUINT8}: ssaop.OpRsh32x8,
2823 {ir.ORSH, types.TUINT32, types.TUINT8}: ssaop.OpRsh32Ux8,
2824 {ir.ORSH, types.TINT32, types.TUINT16}: ssaop.OpRsh32x16,
2825 {ir.ORSH, types.TUINT32, types.TUINT16}: ssaop.OpRsh32Ux16,
2826 {ir.ORSH, types.TINT32, types.TUINT32}: ssaop.OpRsh32x32,
2827 {ir.ORSH, types.TUINT32, types.TUINT32}: ssaop.OpRsh32Ux32,
2828 {ir.ORSH, types.TINT32, types.TUINT64}: ssaop.OpRsh32x64,
2829 {ir.ORSH, types.TUINT32, types.TUINT64}: ssaop.OpRsh32Ux64,
2830
2831 {ir.ORSH, types.TINT64, types.TUINT8}: ssaop.OpRsh64x8,
2832 {ir.ORSH, types.TUINT64, types.TUINT8}: ssaop.OpRsh64Ux8,
2833 {ir.ORSH, types.TINT64, types.TUINT16}: ssaop.OpRsh64x16,
2834 {ir.ORSH, types.TUINT64, types.TUINT16}: ssaop.OpRsh64Ux16,
2835 {ir.ORSH, types.TINT64, types.TUINT32}: ssaop.OpRsh64x32,
2836 {ir.ORSH, types.TUINT64, types.TUINT32}: ssaop.OpRsh64Ux32,
2837 {ir.ORSH, types.TINT64, types.TUINT64}: ssaop.OpRsh64x64,
2838 {ir.ORSH, types.TUINT64, types.TUINT64}: ssaop.OpRsh64Ux64,
2839 }
2840
2841 func (s *state) ssaShiftOp(op ir.Op, t *types.Type, u *types.Type) ssaop.Op {
2842 etype1 := s.concreteEtype(t)
2843 etype2 := s.concreteEtype(u)
2844 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
2845 if !ok {
2846 s.Fatalf("unhandled shift op %v etype=%s/%s", op, etype1, etype2)
2847 }
2848 return x
2849 }
2850
2851 func (s *state) uintptrConstant(v uint64) *ssa.Value {
2852 if s.config.PtrSize == 4 {
2853 return s.newValue0I(ssaop.OpConst32, types.Types[types.TUINTPTR], int64(v))
2854 }
2855 return s.newValue0I(ssaop.OpConst64, types.Types[types.TUINTPTR], int64(v))
2856 }
2857
2858 func (s *state) conv(n ir.Node, v *ssa.Value, ft, tt *types.Type) *ssa.Value {
2859 if ft.IsBoolean() && tt.IsKind(types.TUINT8) {
2860
2861 return s.newValue1(ssaop.OpCvtBoolToUint8, tt, v)
2862 }
2863 if ft.IsInteger() && tt.IsInteger() {
2864 var op ssaop.Op
2865 if tt.Size() == ft.Size() {
2866 op = ssaop.OpCopy
2867 } else if tt.Size() < ft.Size() {
2868
2869 switch 10*ft.Size() + tt.Size() {
2870 case 21:
2871 op = ssaop.OpTrunc16to8
2872 case 41:
2873 op = ssaop.OpTrunc32to8
2874 case 42:
2875 op = ssaop.OpTrunc32to16
2876 case 81:
2877 op = ssaop.OpTrunc64to8
2878 case 82:
2879 op = ssaop.OpTrunc64to16
2880 case 84:
2881 op = ssaop.OpTrunc64to32
2882 default:
2883 s.Fatalf("weird integer truncation %v -> %v", ft, tt)
2884 }
2885 } else if ft.IsSigned() {
2886
2887 switch 10*ft.Size() + tt.Size() {
2888 case 12:
2889 op = ssaop.OpSignExt8to16
2890 case 14:
2891 op = ssaop.OpSignExt8to32
2892 case 18:
2893 op = ssaop.OpSignExt8to64
2894 case 24:
2895 op = ssaop.OpSignExt16to32
2896 case 28:
2897 op = ssaop.OpSignExt16to64
2898 case 48:
2899 op = ssaop.OpSignExt32to64
2900 default:
2901 s.Fatalf("bad integer sign extension %v -> %v", ft, tt)
2902 }
2903 } else {
2904
2905 switch 10*ft.Size() + tt.Size() {
2906 case 12:
2907 op = ssaop.OpZeroExt8to16
2908 case 14:
2909 op = ssaop.OpZeroExt8to32
2910 case 18:
2911 op = ssaop.OpZeroExt8to64
2912 case 24:
2913 op = ssaop.OpZeroExt16to32
2914 case 28:
2915 op = ssaop.OpZeroExt16to64
2916 case 48:
2917 op = ssaop.OpZeroExt32to64
2918 default:
2919 s.Fatalf("weird integer sign extension %v -> %v", ft, tt)
2920 }
2921 }
2922 return s.newValue1(op, tt, v)
2923 }
2924
2925 if ft.IsComplex() && tt.IsComplex() {
2926 var op ssaop.Op
2927 if ft.Size() == tt.Size() {
2928 switch ft.Size() {
2929 case 8:
2930 op = ssaop.OpRound32F
2931 case 16:
2932 op = ssaop.OpRound64F
2933 default:
2934 s.Fatalf("weird complex conversion %v -> %v", ft, tt)
2935 }
2936 } else if ft.Size() == 8 && tt.Size() == 16 {
2937 op = ssaop.OpCvt32Fto64F
2938 } else if ft.Size() == 16 && tt.Size() == 8 {
2939 op = ssaop.OpCvt64Fto32F
2940 } else {
2941 s.Fatalf("weird complex conversion %v -> %v", ft, tt)
2942 }
2943 ftp := types.FloatForComplex(ft)
2944 ttp := types.FloatForComplex(tt)
2945 return s.newValue2(ssaop.OpComplexMake, tt,
2946 s.newValueOrSfCall1(op, ttp, s.newValue1(ssaop.OpComplexReal, ftp, v)),
2947 s.newValueOrSfCall1(op, ttp, s.newValue1(ssaop.OpComplexImag, ftp, v)))
2948 }
2949
2950 if tt.IsComplex() {
2951
2952 et := types.FloatForComplex(tt)
2953 v = s.conv(n, v, ft, et)
2954 return s.newValue2(ssaop.OpComplexMake, tt, v, s.zeroVal(et))
2955 }
2956
2957 if ft.IsFloat() || tt.IsFloat() {
2958 cft, ctt := s.concreteEtype(ft), s.concreteEtype(tt)
2959 conv, ok := fpConvOpToSSA[twoTypes{cft, ctt}]
2960
2961
2962 if ctt == types.TUINT32 && ft.IsFloat() && !base.ConvertHash.MatchPosWithInfo(n.Pos(), "U", nil) {
2963
2964 conv.op1 = ssaop.OpCvt64Fto64
2965 if cft == types.TFLOAT32 {
2966 conv.op1 = ssaop.OpCvt32Fto64
2967 }
2968 conv.op2 = ssaop.OpTrunc64to32
2969
2970 }
2971 if s.config.RegSize == 4 && Arch.LinkArch.Family != sys.MIPS && !s.softFloat {
2972 if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
2973 conv = conv1
2974 }
2975 }
2976 if Arch.LinkArch.Family == sys.ARM64 || Arch.LinkArch.Family == sys.Wasm || Arch.LinkArch.Family == sys.S390X || s.softFloat {
2977 if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
2978 conv = conv1
2979 }
2980 }
2981
2982 if Arch.LinkArch.Family == sys.MIPS && !s.softFloat {
2983 if ft.Size() == 4 && ft.IsInteger() && !ft.IsSigned() {
2984
2985 if tt.Size() == 4 {
2986 return s.uint32Tofloat32(n, v, ft, tt)
2987 }
2988 if tt.Size() == 8 {
2989 return s.uint32Tofloat64(n, v, ft, tt)
2990 }
2991 } else if tt.Size() == 4 && tt.IsInteger() && !tt.IsSigned() {
2992
2993 if ft.Size() == 4 {
2994 return s.float32ToUint32(n, v, ft, tt)
2995 }
2996 if ft.Size() == 8 {
2997 return s.float64ToUint32(n, v, ft, tt)
2998 }
2999 }
3000 }
3001
3002 if !ok {
3003 s.Fatalf("weird float conversion %v -> %v", ft, tt)
3004 }
3005 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
3006
3007 if op1 != ssaop.OpInvalid && op2 != ssaop.OpInvalid {
3008
3009 if op1 == ssaop.OpCopy {
3010 if op2 == ssaop.OpCopy {
3011 return v
3012 }
3013 return s.newValueOrSfCall1(op2, tt, v)
3014 }
3015 if op2 == ssaop.OpCopy {
3016 return s.newValueOrSfCall1(op1, tt, v)
3017 }
3018 return s.newValueOrSfCall1(op2, tt, s.newValueOrSfCall1(op1, types.Types[it], v))
3019 }
3020
3021 if ft.IsInteger() {
3022
3023 if tt.Size() == 4 {
3024 return s.uint64Tofloat32(n, v, ft, tt)
3025 }
3026 if tt.Size() == 8 {
3027 return s.uint64Tofloat64(n, v, ft, tt)
3028 }
3029 s.Fatalf("weird unsigned integer to float conversion %v -> %v", ft, tt)
3030 }
3031
3032 if ft.Size() == 4 {
3033 switch tt.Size() {
3034 case 8:
3035 return s.float32ToUint64(n, v, ft, tt)
3036 case 4, 2, 1:
3037
3038 return s.float32ToUint32(n, v, ft, tt)
3039 }
3040 }
3041 if ft.Size() == 8 {
3042 switch tt.Size() {
3043 case 8:
3044 return s.float64ToUint64(n, v, ft, tt)
3045 case 4, 2, 1:
3046
3047 return s.float64ToUint32(n, v, ft, tt)
3048 }
3049
3050 }
3051 s.Fatalf("weird float to unsigned integer conversion %v -> %v", ft, tt)
3052 return nil
3053 }
3054
3055 s.Fatalf("unhandled OCONV %s -> %s", ft.Kind(), tt.Kind())
3056 return nil
3057 }
3058
3059
3060 func (s *state) expr(n ir.Node) *ssa.Value {
3061 return s.exprCheckPtr(n, true)
3062 }
3063
3064 func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
3065 if ir.HasUniquePos(n) {
3066
3067
3068 s.pushLine(n.Pos())
3069 defer s.popLine()
3070 }
3071
3072 s.stmtList(n.Init())
3073 switch n.Op() {
3074 case ir.OBYTES2STRTMP:
3075 n := n.(*ir.ConvExpr)
3076 slice := s.expr(n.X)
3077 ptr := s.newValue1(ssaop.OpSlicePtr, s.f.Config.Types.BytePtr, slice)
3078 len := s.newValue1(ssaop.OpSliceLen, types.Types[types.TINT], slice)
3079 return s.newValue2(ssaop.OpStringMake, n.Type(), ptr, len)
3080 case ir.OSTR2BYTESTMP:
3081 n := n.(*ir.ConvExpr)
3082 str := s.expr(n.X)
3083 ptr := s.newValue1(ssaop.OpStringPtr, s.f.Config.Types.BytePtr, str)
3084 if !n.NonNil() {
3085
3086
3087
3088 cond := s.newValue2(ssaop.OpNeqPtr, types.Types[types.TBOOL], ptr, s.constNil(ptr.Type))
3089 zerobase := s.newValue1A(ssaop.OpAddr, ptr.Type, ir.Syms.Zerobase, s.sb)
3090 ptr = s.ternary(cond, ptr, zerobase)
3091 }
3092 len := s.newValue1(ssaop.OpStringLen, types.Types[types.TINT], str)
3093 return s.newValue3(ssaop.OpSliceMake, n.Type(), ptr, len, len)
3094 case ir.OCFUNC:
3095 n := n.(*ir.UnaryExpr)
3096 aux := n.X.(*ir.Name).Linksym()
3097
3098
3099 if aux.ABI() != obj.ABIInternal {
3100 s.Fatalf("expected ABIInternal: %v", aux.ABI())
3101 }
3102 return s.entryNewValue1A(ssaop.OpAddr, n.Type(), aux, s.sb)
3103 case ir.ONAME:
3104 n := n.(*ir.Name)
3105 if n.Class == ir.PFUNC {
3106
3107 sym := staticdata.FuncLinksym(n)
3108 return s.entryNewValue1A(ssaop.OpAddr, types.NewPtr(n.Type()), sym, s.sb)
3109 }
3110 if s.canSSA(n) {
3111 return s.variable(n, n.Type())
3112 }
3113 return s.load(n.Type(), s.addr(n))
3114 case ir.OLINKSYMOFFSET:
3115 n := n.(*ir.LinksymOffsetExpr)
3116 return s.load(n.Type(), s.addr(n))
3117 case ir.ONIL:
3118 n := n.(*ir.NilExpr)
3119 t := n.Type()
3120 switch {
3121 case t.IsSlice():
3122 return s.constSlice(t)
3123 case t.IsInterface():
3124 return s.constInterface(t)
3125 default:
3126 return s.constNil(t)
3127 }
3128 case ir.OLITERAL:
3129 switch u := n.Val(); u.Kind() {
3130 case constant.Int:
3131 i := ir.IntVal(n.Type(), u)
3132 switch n.Type().Size() {
3133 case 1:
3134 return s.constInt8(n.Type(), int8(i))
3135 case 2:
3136 return s.constInt16(n.Type(), int16(i))
3137 case 4:
3138 return s.constInt32(n.Type(), int32(i))
3139 case 8:
3140 return s.constInt64(n.Type(), i)
3141 default:
3142 s.Fatalf("bad integer size %d", n.Type().Size())
3143 return nil
3144 }
3145 case constant.String:
3146 i := constant.StringVal(u)
3147 if i == "" {
3148 return s.constEmptyString(n.Type())
3149 }
3150 return s.entryNewValue0A(ssaop.OpConstString, n.Type(), ssa.StringToAux(i))
3151 case constant.Bool:
3152 return s.constBool(constant.BoolVal(u))
3153 case constant.Float:
3154 f, _ := constant.Float64Val(u)
3155 switch n.Type().Size() {
3156 case 4:
3157 return s.constFloat32(n.Type(), f)
3158 case 8:
3159 return s.constFloat64(n.Type(), f)
3160 default:
3161 s.Fatalf("bad float size %d", n.Type().Size())
3162 return nil
3163 }
3164 case constant.Complex:
3165 re, _ := constant.Float64Val(constant.Real(u))
3166 im, _ := constant.Float64Val(constant.Imag(u))
3167 switch n.Type().Size() {
3168 case 8:
3169 pt := types.Types[types.TFLOAT32]
3170 return s.newValue2(ssaop.OpComplexMake, n.Type(),
3171 s.constFloat32(pt, re),
3172 s.constFloat32(pt, im))
3173 case 16:
3174 pt := types.Types[types.TFLOAT64]
3175 return s.newValue2(ssaop.OpComplexMake, n.Type(),
3176 s.constFloat64(pt, re),
3177 s.constFloat64(pt, im))
3178 default:
3179 s.Fatalf("bad complex size %d", n.Type().Size())
3180 return nil
3181 }
3182 default:
3183 s.Fatalf("unhandled OLITERAL %v", u.Kind())
3184 return nil
3185 }
3186 case ir.OCONVNOP:
3187 n := n.(*ir.ConvExpr)
3188 to := n.Type()
3189 from := n.X.Type()
3190
3191
3192
3193 x := s.expr(n.X)
3194 if to == from {
3195 return x
3196 }
3197
3198
3199
3200
3201
3202 if to.IsPtrShaped() != from.IsPtrShaped() {
3203 return s.newValue2(ssaop.OpConvert, to, x, s.mem())
3204 }
3205
3206 v := s.newValue1(ssaop.OpCopy, to, x)
3207
3208
3209 if to.Kind() == types.TFUNC && from.IsPtrShaped() {
3210 return v
3211 }
3212
3213
3214 if from.Kind() == to.Kind() {
3215 return v
3216 }
3217
3218
3219 if to.IsUnsafePtr() && from.IsPtrShaped() || from.IsUnsafePtr() && to.IsPtrShaped() {
3220 if s.checkPtrEnabled && checkPtrOK && to.IsPtr() && from.IsUnsafePtr() {
3221 s.checkPtrAlignment(n, v, nil)
3222 }
3223 return v
3224 }
3225
3226
3227 mt := types.NewPtr(reflectdata.MapType())
3228 if to.Kind() == types.TMAP && from == mt {
3229 return v
3230 }
3231
3232 types.CalcSize(from)
3233 types.CalcSize(to)
3234 if from.Size() != to.Size() {
3235 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Size(), to, to.Size())
3236 return nil
3237 }
3238 if etypesign(from.Kind()) != etypesign(to.Kind()) {
3239 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, from.Kind(), to, to.Kind())
3240 return nil
3241 }
3242
3243 if base.Flag.Cfg.Instrumenting {
3244
3245
3246
3247 return v
3248 }
3249
3250 if etypesign(from.Kind()) == 0 {
3251 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
3252 return nil
3253 }
3254
3255
3256 return v
3257
3258 case ir.OCONV:
3259 n := n.(*ir.ConvExpr)
3260 x := s.expr(n.X)
3261 return s.conv(n, x, n.X.Type(), n.Type())
3262
3263 case ir.ODOTTYPE:
3264 n := n.(*ir.TypeAssertExpr)
3265 res, _ := s.dottype(n, false)
3266 return res
3267
3268 case ir.ODYNAMICDOTTYPE:
3269 n := n.(*ir.DynamicTypeAssertExpr)
3270 res, _ := s.dynamicDottype(n, false)
3271 return res
3272
3273
3274 case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
3275 n := n.(*ir.BinaryExpr)
3276 a := s.expr(n.X)
3277 b := s.expr(n.Y)
3278 if n.X.Type().IsComplex() {
3279 pt := types.FloatForComplex(n.X.Type())
3280 op := s.ssaOp(ir.OEQ, pt)
3281 r := s.newValueOrSfCall2(op, types.Types[types.TBOOL], s.newValue1(ssaop.OpComplexReal, pt, a), s.newValue1(ssaop.OpComplexReal, pt, b))
3282 i := s.newValueOrSfCall2(op, types.Types[types.TBOOL], s.newValue1(ssaop.OpComplexImag, pt, a), s.newValue1(ssaop.OpComplexImag, pt, b))
3283 c := s.newValue2(ssaop.OpAndB, types.Types[types.TBOOL], r, i)
3284 switch n.Op() {
3285 case ir.OEQ:
3286 return c
3287 case ir.ONE:
3288 return s.newValue1(ssaop.OpNot, types.Types[types.TBOOL], c)
3289 default:
3290 s.Fatalf("ordered complex compare %v", n.Op())
3291 }
3292 }
3293
3294
3295 op := n.Op()
3296 switch op {
3297 case ir.OGE:
3298 op, a, b = ir.OLE, b, a
3299 case ir.OGT:
3300 op, a, b = ir.OLT, b, a
3301 }
3302 if n.X.Type().IsFloat() {
3303
3304 return s.newValueOrSfCall2(s.ssaOp(op, n.X.Type()), types.Types[types.TBOOL], a, b)
3305 }
3306
3307 return s.newValue2(s.ssaOp(op, n.X.Type()), types.Types[types.TBOOL], a, b)
3308 case ir.OMUL:
3309 n := n.(*ir.BinaryExpr)
3310 a := s.expr(n.X)
3311 b := s.expr(n.Y)
3312 if n.Type().IsComplex() {
3313 mulop := ssaop.OpMul64F
3314 addop := ssaop.OpAdd64F
3315 subop := ssaop.OpSub64F
3316 pt := types.FloatForComplex(n.Type())
3317 wt := types.Types[types.TFLOAT64]
3318
3319 areal := s.newValue1(ssaop.OpComplexReal, pt, a)
3320 breal := s.newValue1(ssaop.OpComplexReal, pt, b)
3321 aimag := s.newValue1(ssaop.OpComplexImag, pt, a)
3322 bimag := s.newValue1(ssaop.OpComplexImag, pt, b)
3323
3324 if pt != wt {
3325 areal = s.newValueOrSfCall1(ssaop.OpCvt32Fto64F, wt, areal)
3326 breal = s.newValueOrSfCall1(ssaop.OpCvt32Fto64F, wt, breal)
3327 aimag = s.newValueOrSfCall1(ssaop.OpCvt32Fto64F, wt, aimag)
3328 bimag = s.newValueOrSfCall1(ssaop.OpCvt32Fto64F, wt, bimag)
3329 }
3330
3331 xreal := s.newValueOrSfCall2(subop, wt, s.newValueOrSfCall2(mulop, wt, areal, breal), s.newValueOrSfCall2(mulop, wt, aimag, bimag))
3332 ximag := s.newValueOrSfCall2(addop, wt, s.newValueOrSfCall2(mulop, wt, areal, bimag), s.newValueOrSfCall2(mulop, wt, aimag, breal))
3333
3334 if pt != wt {
3335 xreal = s.newValueOrSfCall1(ssaop.OpCvt64Fto32F, pt, xreal)
3336 ximag = s.newValueOrSfCall1(ssaop.OpCvt64Fto32F, pt, ximag)
3337 }
3338
3339 return s.newValue2(ssaop.OpComplexMake, n.Type(), xreal, ximag)
3340 }
3341
3342 if n.Type().IsFloat() {
3343 return s.newValueOrSfCall2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3344 }
3345
3346 return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3347
3348 case ir.ODIV:
3349 n := n.(*ir.BinaryExpr)
3350 a := s.expr(n.X)
3351 b := s.expr(n.Y)
3352 if n.Type().IsComplex() {
3353
3354
3355
3356 mulop := ssaop.OpMul64F
3357 addop := ssaop.OpAdd64F
3358 subop := ssaop.OpSub64F
3359 divop := ssaop.OpDiv64F
3360 pt := types.FloatForComplex(n.Type())
3361 wt := types.Types[types.TFLOAT64]
3362
3363 areal := s.newValue1(ssaop.OpComplexReal, pt, a)
3364 breal := s.newValue1(ssaop.OpComplexReal, pt, b)
3365 aimag := s.newValue1(ssaop.OpComplexImag, pt, a)
3366 bimag := s.newValue1(ssaop.OpComplexImag, pt, b)
3367
3368 if pt != wt {
3369 areal = s.newValueOrSfCall1(ssaop.OpCvt32Fto64F, wt, areal)
3370 breal = s.newValueOrSfCall1(ssaop.OpCvt32Fto64F, wt, breal)
3371 aimag = s.newValueOrSfCall1(ssaop.OpCvt32Fto64F, wt, aimag)
3372 bimag = s.newValueOrSfCall1(ssaop.OpCvt32Fto64F, wt, bimag)
3373 }
3374
3375 denom := s.newValueOrSfCall2(addop, wt, s.newValueOrSfCall2(mulop, wt, breal, breal), s.newValueOrSfCall2(mulop, wt, bimag, bimag))
3376 xreal := s.newValueOrSfCall2(addop, wt, s.newValueOrSfCall2(mulop, wt, areal, breal), s.newValueOrSfCall2(mulop, wt, aimag, bimag))
3377 ximag := s.newValueOrSfCall2(subop, wt, s.newValueOrSfCall2(mulop, wt, aimag, breal), s.newValueOrSfCall2(mulop, wt, areal, bimag))
3378
3379
3380
3381
3382
3383 xreal = s.newValueOrSfCall2(divop, wt, xreal, denom)
3384 ximag = s.newValueOrSfCall2(divop, wt, ximag, denom)
3385
3386 if pt != wt {
3387 xreal = s.newValueOrSfCall1(ssaop.OpCvt64Fto32F, pt, xreal)
3388 ximag = s.newValueOrSfCall1(ssaop.OpCvt64Fto32F, pt, ximag)
3389 }
3390 return s.newValue2(ssaop.OpComplexMake, n.Type(), xreal, ximag)
3391 }
3392 if n.Type().IsFloat() {
3393 return s.newValueOrSfCall2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3394 }
3395 return s.intDivide(n, a, b)
3396 case ir.OMOD:
3397 n := n.(*ir.BinaryExpr)
3398 a := s.expr(n.X)
3399 b := s.expr(n.Y)
3400 return s.intDivide(n, a, b)
3401 case ir.OADD, ir.OSUB:
3402 n := n.(*ir.BinaryExpr)
3403 a := s.expr(n.X)
3404 b := s.expr(n.Y)
3405 if n.Type().IsComplex() {
3406 pt := types.FloatForComplex(n.Type())
3407 op := s.ssaOp(n.Op(), pt)
3408 return s.newValue2(ssaop.OpComplexMake, n.Type(),
3409 s.newValueOrSfCall2(op, pt, s.newValue1(ssaop.OpComplexReal, pt, a), s.newValue1(ssaop.OpComplexReal, pt, b)),
3410 s.newValueOrSfCall2(op, pt, s.newValue1(ssaop.OpComplexImag, pt, a), s.newValue1(ssaop.OpComplexImag, pt, b)))
3411 }
3412 if n.Type().IsFloat() {
3413 return s.newValueOrSfCall2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3414 }
3415 return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3416 case ir.OAND, ir.OOR, ir.OXOR:
3417 n := n.(*ir.BinaryExpr)
3418 a := s.expr(n.X)
3419 b := s.expr(n.Y)
3420 return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
3421 case ir.OANDNOT:
3422 n := n.(*ir.BinaryExpr)
3423 a := s.expr(n.X)
3424 b := s.expr(n.Y)
3425 b = s.newValue1(s.ssaOp(ir.OBITNOT, b.Type), b.Type, b)
3426 return s.newValue2(s.ssaOp(ir.OAND, n.Type()), a.Type, a, b)
3427 case ir.OLSH, ir.ORSH:
3428 n := n.(*ir.BinaryExpr)
3429 a := s.expr(n.X)
3430 b := s.expr(n.Y)
3431 bt := b.Type
3432 if bt.IsSigned() {
3433 cmp := s.newValue2(s.ssaOp(ir.OLE, bt), types.Types[types.TBOOL], s.zeroVal(bt), b)
3434 s.check(cmp, ir.Syms.Panicshift)
3435 bt = bt.ToUnsigned()
3436 }
3437 return s.newValue2(s.ssaShiftOp(n.Op(), n.Type(), bt), a.Type, a, b)
3438 case ir.OANDAND, ir.OOROR:
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452 n := n.(*ir.LogicalExpr)
3453 el := s.expr(n.X)
3454 s.vars[n] = el
3455
3456 b := s.endBlock()
3457 b.Kind = block.BlockIf
3458 b.SetControl(el)
3459
3460
3461
3462
3463
3464 bRight := s.f.NewBlock(block.BlockPlain)
3465 bResult := s.f.NewBlock(block.BlockPlain)
3466 if n.Op() == ir.OANDAND {
3467 b.AddEdgeTo(bRight)
3468 b.AddEdgeTo(bResult)
3469 } else if n.Op() == ir.OOROR {
3470 b.AddEdgeTo(bResult)
3471 b.AddEdgeTo(bRight)
3472 }
3473
3474 s.startBlock(bRight)
3475 er := s.expr(n.Y)
3476 s.vars[n] = er
3477
3478 b = s.endBlock()
3479 b.AddEdgeTo(bResult)
3480
3481 s.startBlock(bResult)
3482 return s.variable(n, types.Types[types.TBOOL])
3483 case ir.OCOMPLEX:
3484 n := n.(*ir.BinaryExpr)
3485 r := s.expr(n.X)
3486 i := s.expr(n.Y)
3487 return s.newValue2(ssaop.OpComplexMake, n.Type(), r, i)
3488
3489
3490 case ir.ONEG:
3491 n := n.(*ir.UnaryExpr)
3492 a := s.expr(n.X)
3493 if n.Type().IsComplex() {
3494 tp := types.FloatForComplex(n.Type())
3495 negop := s.ssaOp(n.Op(), tp)
3496 return s.newValue2(ssaop.OpComplexMake, n.Type(),
3497 s.newValue1(negop, tp, s.newValue1(ssaop.OpComplexReal, tp, a)),
3498 s.newValue1(negop, tp, s.newValue1(ssaop.OpComplexImag, tp, a)))
3499 }
3500 return s.newValue1(s.ssaOp(n.Op(), n.Type()), a.Type, a)
3501 case ir.ONOT, ir.OBITNOT:
3502 n := n.(*ir.UnaryExpr)
3503 a := s.expr(n.X)
3504 return s.newValue1(s.ssaOp(n.Op(), n.Type()), a.Type, a)
3505 case ir.OIMAG, ir.OREAL:
3506 n := n.(*ir.UnaryExpr)
3507 a := s.expr(n.X)
3508 return s.newValue1(s.ssaOp(n.Op(), n.X.Type()), n.Type(), a)
3509 case ir.OPLUS:
3510 n := n.(*ir.UnaryExpr)
3511 return s.expr(n.X)
3512
3513 case ir.OADDR:
3514 n := n.(*ir.AddrExpr)
3515 return s.addr(n.X)
3516
3517 case ir.ORESULT:
3518 n := n.(*ir.ResultExpr)
3519 if s.prevCall == nil || s.prevCall.Op != ssaop.OpStaticLECall && s.prevCall.Op != ssaop.OpInterLECall && s.prevCall.Op != ssaop.OpClosureLECall {
3520 panic("Expected to see a previous call")
3521 }
3522 which := n.Index
3523 if which == -1 {
3524 panic(fmt.Errorf("ORESULT %v does not match call %s", n, s.prevCall))
3525 }
3526 return s.resultOfCall(s.prevCall, which, n.Type())
3527
3528 case ir.ODEREF:
3529 n := n.(*ir.StarExpr)
3530 p := s.exprPtr(n.X, n.Bounded(), n.Pos())
3531 return s.load(n.Type(), p)
3532
3533 case ir.ODOT:
3534 n := n.(*ir.SelectorExpr)
3535 if n.X.Op() == ir.OSTRUCTLIT {
3536
3537
3538
3539 if !ir.IsZero(n.X) {
3540 s.Fatalf("literal with nonzero value in SSA: %v", n.X)
3541 }
3542 return s.zeroVal(n.Type())
3543 }
3544
3545
3546
3547
3548 if ir.IsAddressable(n) && !s.canSSA(n) {
3549 p := s.addr(n)
3550 return s.load(n.Type(), p)
3551 }
3552 v := s.expr(n.X)
3553 return s.newValue1I(ssaop.OpStructSelect, n.Type(), int64(fieldIdx(n)), v)
3554
3555 case ir.ODOTPTR:
3556 n := n.(*ir.SelectorExpr)
3557 p := s.exprPtr(n.X, n.Bounded(), n.Pos())
3558 p = s.newValue1I(ssaop.OpOffPtr, types.NewPtr(n.Type()), n.Offset(), p)
3559 return s.load(n.Type(), p)
3560
3561 case ir.OINDEX:
3562 n := n.(*ir.IndexExpr)
3563 switch {
3564 case n.X.Type().IsString():
3565 if n.Bounded() && ir.IsConst(n.X, constant.String) && ir.IsConst(n.Index, constant.Int) {
3566
3567
3568
3569 return s.newValue0I(ssaop.OpConst8, types.Types[types.TUINT8], int64(int8(ir.StringVal(n.X)[ir.Int64Val(n.Index)])))
3570 }
3571 a := s.expr(n.X)
3572 i := s.expr(n.Index)
3573 len := s.newValue1(ssaop.OpStringLen, types.Types[types.TINT], a)
3574 i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
3575 ptrtyp := s.f.Config.Types.BytePtr
3576 ptr := s.newValue1(ssaop.OpStringPtr, ptrtyp, a)
3577 if ir.IsConst(n.Index, constant.Int) {
3578 ptr = s.newValue1I(ssaop.OpOffPtr, ptrtyp, ir.Int64Val(n.Index), ptr)
3579 } else {
3580 ptr = s.newValue2(ssaop.OpAddPtr, ptrtyp, ptr, i)
3581 }
3582 return s.load(types.Types[types.TUINT8], ptr)
3583 case n.X.Type().IsSlice():
3584 p := s.addr(n)
3585 return s.load(n.X.Type().Elem(), p)
3586 case n.X.Type().IsArray():
3587 if ssa.CanSSA(n.X.Type()) {
3588
3589 bound := n.X.Type().NumElem()
3590 a := s.expr(n.X)
3591 i := s.expr(n.Index)
3592 len := s.constInt(types.Types[types.TINT], bound)
3593 if bound == 0 {
3594
3595 s.boundsCheck(i, len, ssa.BoundsIndex, false)
3596
3597
3598 return s.load(n.Type(), s.constNil(n.Type().PtrTo()))
3599 }
3600 s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
3601 return s.newValue1I(ssaop.OpArraySelect, n.Type(), 0, a)
3602 }
3603 p := s.addr(n)
3604 return s.load(n.X.Type().Elem(), p)
3605 default:
3606 s.Fatalf("bad type for index %v", n.X.Type())
3607 return nil
3608 }
3609
3610 case ir.OLEN, ir.OCAP:
3611 n := n.(*ir.UnaryExpr)
3612
3613
3614 a := s.expr(n.X)
3615 t := n.X.Type()
3616 switch {
3617 case t.IsSlice():
3618 op := ssaop.OpSliceLen
3619 if n.Op() == ir.OCAP {
3620 op = ssaop.OpSliceCap
3621 }
3622 return s.newValue1(op, types.Types[types.TINT], a)
3623 case t.IsString():
3624 return s.newValue1(ssaop.OpStringLen, types.Types[types.TINT], a)
3625 case t.IsMap(), t.IsChan():
3626 return s.referenceTypeBuiltin(n, a)
3627 case t.IsArray():
3628 return s.constInt(types.Types[types.TINT], t.NumElem())
3629 case t.IsPtr() && t.Elem().IsArray():
3630 return s.constInt(types.Types[types.TINT], t.Elem().NumElem())
3631 default:
3632 s.Fatalf("bad type in len/cap: %v", t)
3633 return nil
3634 }
3635
3636 case ir.OSPTR:
3637 n := n.(*ir.UnaryExpr)
3638 a := s.expr(n.X)
3639 if n.X.Type().IsSlice() {
3640 if n.Bounded() {
3641 return s.newValue1(ssaop.OpSlicePtr, n.Type(), a)
3642 }
3643 return s.newValue1(ssaop.OpSlicePtrUnchecked, n.Type(), a)
3644 } else {
3645 return s.newValue1(ssaop.OpStringPtr, n.Type(), a)
3646 }
3647
3648 case ir.OITAB:
3649 n := n.(*ir.UnaryExpr)
3650 a := s.expr(n.X)
3651 return s.newValue1(ssaop.OpITab, n.Type(), a)
3652
3653 case ir.OIDATA:
3654 n := n.(*ir.UnaryExpr)
3655 a := s.expr(n.X)
3656 return s.newValue1(ssaop.OpIData, n.Type(), a)
3657
3658 case ir.OMAKEFACE:
3659 n := n.(*ir.BinaryExpr)
3660 tab := s.expr(n.X)
3661 data := s.expr(n.Y)
3662 return s.newValue2(ssaop.OpIMake, n.Type(), tab, data)
3663
3664 case ir.OSLICEHEADER:
3665 n := n.(*ir.SliceHeaderExpr)
3666 p := s.expr(n.Ptr)
3667 l := s.expr(n.Len)
3668 c := s.expr(n.Cap)
3669 return s.newValue3(ssaop.OpSliceMake, n.Type(), p, l, c)
3670
3671 case ir.OSTRINGHEADER:
3672 n := n.(*ir.StringHeaderExpr)
3673 p := s.expr(n.Ptr)
3674 l := s.expr(n.Len)
3675 return s.newValue2(ssaop.OpStringMake, n.Type(), p, l)
3676
3677 case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
3678 n := n.(*ir.SliceExpr)
3679 check := s.checkPtrEnabled && n.Op() == ir.OSLICE3ARR && n.X.Op() == ir.OCONVNOP && n.X.(*ir.ConvExpr).X.Type().IsUnsafePtr()
3680 v := s.exprCheckPtr(n.X, !check)
3681 var i, j, k *ssa.Value
3682 if n.Low != nil {
3683 i = s.expr(n.Low)
3684 }
3685 if n.High != nil {
3686 j = s.expr(n.High)
3687 }
3688 if n.Max != nil {
3689 k = s.expr(n.Max)
3690 }
3691 p, l, c := s.slice(v, i, j, k, n.Bounded())
3692 if check {
3693
3694 s.checkPtrAlignment(n.X.(*ir.ConvExpr), v, s.conv(n.Max, k, k.Type, types.Types[types.TUINTPTR]))
3695 }
3696 return s.newValue3(ssaop.OpSliceMake, n.Type(), p, l, c)
3697
3698 case ir.OSLICESTR:
3699 n := n.(*ir.SliceExpr)
3700 v := s.expr(n.X)
3701 var i, j *ssa.Value
3702 if n.Low != nil {
3703 i = s.expr(n.Low)
3704 }
3705 if n.High != nil {
3706 j = s.expr(n.High)
3707 }
3708 p, l, _ := s.slice(v, i, j, nil, n.Bounded())
3709 return s.newValue2(ssaop.OpStringMake, n.Type(), p, l)
3710
3711 case ir.OSLICE2ARRPTR:
3712
3713
3714
3715
3716 n := n.(*ir.ConvExpr)
3717 v := s.expr(n.X)
3718 nelem := n.Type().Elem().NumElem()
3719 arrlen := s.constInt(types.Types[types.TINT], nelem)
3720 cap := s.newValue1(ssaop.OpSliceLen, types.Types[types.TINT], v)
3721 s.boundsCheck(arrlen, cap, ssa.BoundsConvert, false)
3722 op := ssaop.OpSlicePtr
3723 if nelem == 0 {
3724 op = ssaop.OpSlicePtrUnchecked
3725 }
3726 return s.newValue1(op, n.Type(), v)
3727
3728 case ir.OCALLFUNC:
3729 n := n.(*ir.CallExpr)
3730 if ir.IsIntrinsicCall(n) {
3731 return s.intrinsicCall(n)
3732 }
3733 fallthrough
3734
3735 case ir.OCALLINTER:
3736 n := n.(*ir.CallExpr)
3737 return s.callResult(n, callNormal)
3738
3739 case ir.OGETG:
3740 n := n.(*ir.CallExpr)
3741 return s.newValue1(ssaop.OpGetG, n.Type(), s.mem())
3742
3743 case ir.OGETCALLERSP:
3744 n := n.(*ir.CallExpr)
3745 return s.newValue1(ssaop.OpGetCallerSP, n.Type(), s.mem())
3746
3747 case ir.OAPPEND:
3748 return s.append(n.(*ir.CallExpr), false)
3749
3750 case ir.OMOVE2HEAP:
3751 return s.move2heap(n.(*ir.MoveToHeapExpr))
3752
3753 case ir.OMIN, ir.OMAX:
3754 return s.minMax(n.(*ir.CallExpr))
3755
3756 case ir.OSTRUCTLIT, ir.OARRAYLIT:
3757
3758
3759
3760 n := n.(*ir.CompLitExpr)
3761 if !ir.IsZero(n) {
3762 s.Fatalf("literal with nonzero value in SSA: %v", n)
3763 }
3764 return s.zeroVal(n.Type())
3765
3766 case ir.ONEW:
3767 n := n.(*ir.UnaryExpr)
3768 if x, ok := n.X.(*ir.DynamicType); ok && x.Op() == ir.ODYNAMICTYPE {
3769 return s.newObjectNonSpecialized(n.Type().Elem(), s.expr(x.RType))
3770 }
3771 return s.newObject(n.Type().Elem())
3772
3773 case ir.OUNSAFEADD:
3774 n := n.(*ir.BinaryExpr)
3775 ptr := s.expr(n.X)
3776 len := s.expr(n.Y)
3777
3778
3779
3780 len = s.conv(n, len, len.Type, types.Types[types.TUINTPTR])
3781
3782 return s.newValue2(ssaop.OpAddPtr, n.Type(), ptr, len)
3783
3784 default:
3785 s.Fatalf("unhandled expr %v", n.Op())
3786 return nil
3787 }
3788 }
3789
3790 func (s *state) resultOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.Value {
3791 aux := c.Aux.(*ssa.AuxCall)
3792 pa := aux.ParamAssignmentForResult(which)
3793
3794
3795 if len(pa.Registers) == 0 && !ssa.CanSSA(t) {
3796 addr := s.newValue1I(ssaop.OpSelectNAddr, types.NewPtr(t), which, c)
3797 return s.rawLoad(t, addr)
3798 }
3799 return s.newValue1I(ssaop.OpSelectN, t, which, c)
3800 }
3801
3802 func (s *state) resultAddrOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.Value {
3803 aux := c.Aux.(*ssa.AuxCall)
3804 pa := aux.ParamAssignmentForResult(which)
3805 if len(pa.Registers) == 0 {
3806 return s.newValue1I(ssaop.OpSelectNAddr, types.NewPtr(t), which, c)
3807 }
3808 _, addr := s.temp(c.Pos, t)
3809 rval := s.newValue1I(ssaop.OpSelectN, t, which, c)
3810 s.vars[memVar] = s.newValue3Apos(ssaop.OpStore, types.TypeMem, t, addr, rval, s.mem(), false)
3811 return addr
3812 }
3813
3814
3815 func (s *state) getBackingStoreInfoForAppend(n *ir.CallExpr) *backingStoreInfo {
3816 if n.Esc() != ir.EscNone {
3817 return nil
3818 }
3819 return s.getBackingStoreInfo(n.Args[0])
3820 }
3821 func (s *state) getBackingStoreInfo(n ir.Node) *backingStoreInfo {
3822 t := n.Type()
3823 et := t.Elem()
3824 maxStackSize := int64(base.Debug.VariableMakeThreshold)
3825 if et.Size() == 0 || et.Size() > maxStackSize {
3826 return nil
3827 }
3828 if base.Flag.N != 0 {
3829 return nil
3830 }
3831 if !base.VariableMakeHash.MatchPos(n.Pos(), nil) {
3832 return nil
3833 }
3834 i := s.backingStores[n]
3835 if i != nil {
3836 return i
3837 }
3838
3839
3840 K := maxStackSize / et.Size()
3841 KT := types.NewArray(et, K)
3842 KT.SetNoalg(true)
3843 types.CalcArraySize(KT)
3844
3845 align := types.NewArray(types.Types[types.TUINTPTR], 0)
3846 types.CalcArraySize(align)
3847 storeTyp := types.NewStruct([]*types.Field{
3848 {Sym: types.BlankSym, Type: align},
3849 {Sym: types.BlankSym, Type: KT},
3850 })
3851 storeTyp.SetNoalg(true)
3852 types.CalcStructSize(storeTyp)
3853
3854
3855 backingStore := typecheck.TempAt(n.Pos(), s.curfn, storeTyp)
3856 backingStore.SetAddrtaken(true)
3857
3858
3859 used := typecheck.TempAt(n.Pos(), s.curfn, types.Types[types.TBOOL])
3860 if s.curBlock == s.f.Entry {
3861 s.vars[used] = s.constBool(false)
3862 } else {
3863
3864 s.defvars[s.f.Entry.ID][used] = s.constBool(false)
3865 }
3866
3867
3868 if s.backingStores == nil {
3869 s.backingStores = map[ir.Node]*backingStoreInfo{}
3870 }
3871 i = &backingStoreInfo{K: K, store: backingStore, used: used, usedStatic: false}
3872 s.backingStores[n] = i
3873 return i
3874 }
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884 func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917 et := n.Type().Elem()
3918 pt := types.NewPtr(et)
3919
3920
3921 sn := n.Args[0]
3922 var slice, addr *ssa.Value
3923 if inplace {
3924 addr = s.addr(sn)
3925 slice = s.load(n.Type(), addr)
3926 } else {
3927 slice = s.expr(sn)
3928 }
3929
3930
3931 grow := s.f.NewBlock(block.BlockPlain)
3932 assign := s.f.NewBlock(block.BlockPlain)
3933
3934
3935 p := s.newValue1(ssaop.OpSlicePtr, pt, slice)
3936 l := s.newValue1(ssaop.OpSliceLen, types.Types[types.TINT], slice)
3937 c := s.newValue1(ssaop.OpSliceCap, types.Types[types.TINT], slice)
3938
3939
3940 nargs := s.constInt(types.Types[types.TINT], int64(len(n.Args)-1))
3941 oldLen := l
3942 l = s.newValue2(s.ssaOp(ir.OADD, types.Types[types.TINT]), types.Types[types.TINT], l, nargs)
3943
3944
3945 cmp := s.newValue2(s.ssaOp(ir.OLT, types.Types[types.TUINT]), types.Types[types.TBOOL], c, l)
3946
3947
3948 s.vars[ptrVar] = p
3949 s.vars[lenVar] = l
3950 if !inplace {
3951 s.vars[capVar] = c
3952 }
3953
3954 b := s.endBlock()
3955 b.Kind = block.BlockIf
3956 b.Likely = ssa.BranchUnlikely
3957 b.SetControl(cmp)
3958 b.AddEdgeTo(grow)
3959 b.AddEdgeTo(assign)
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983 var info *backingStoreInfo
3984 if !inplace {
3985 info = s.getBackingStoreInfoForAppend(n)
3986 }
3987
3988 if !inplace && info != nil && !n.UseBuf && !info.usedStatic {
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012 info.usedStatic = true
4013
4014
4015 usedTestBlock := s.f.NewBlock(block.BlockPlain)
4016 oldLenTestBlock := s.f.NewBlock(block.BlockPlain)
4017 bodyBlock := s.f.NewBlock(block.BlockPlain)
4018 growSlice := s.f.NewBlock(block.BlockPlain)
4019 tInt := types.Types[types.TINT]
4020 tBool := types.Types[types.TBOOL]
4021
4022
4023 s.startBlock(grow)
4024 kTest := s.newValue2(s.ssaOp(ir.OLE, tInt), tBool, l, s.constInt(tInt, info.K))
4025 b := s.endBlock()
4026 b.Kind = block.BlockIf
4027 b.SetControl(kTest)
4028 b.AddEdgeTo(usedTestBlock)
4029 b.AddEdgeTo(growSlice)
4030 b.Likely = ssa.BranchLikely
4031
4032
4033 s.startBlock(usedTestBlock)
4034 usedTest := s.newValue1(ssaop.OpNot, tBool, s.expr(info.used))
4035 b = s.endBlock()
4036 b.Kind = block.BlockIf
4037 b.SetControl(usedTest)
4038 b.AddEdgeTo(oldLenTestBlock)
4039 b.AddEdgeTo(growSlice)
4040 b.Likely = ssa.BranchLikely
4041
4042
4043 s.startBlock(oldLenTestBlock)
4044 oldLenTest := s.newValue2(s.ssaOp(ir.OEQ, tInt), tBool, oldLen, s.constInt(tInt, 0))
4045 b = s.endBlock()
4046 b.Kind = block.BlockIf
4047 b.SetControl(oldLenTest)
4048 b.AddEdgeTo(bodyBlock)
4049 b.AddEdgeTo(growSlice)
4050 b.Likely = ssa.BranchLikely
4051
4052
4053 s.startBlock(bodyBlock)
4054 if et.HasPointers() {
4055 s.vars[memVar] = s.newValue1A(ssaop.OpVarDef, types.TypeMem, info.store, s.mem())
4056 }
4057 addr := s.addr(info.store)
4058 s.zero(info.store.Type(), addr)
4059
4060
4061 s.vars[ptrVar] = addr
4062 s.vars[lenVar] = l
4063 s.vars[capVar] = s.constInt(tInt, info.K)
4064
4065
4066 s.assign(info.used, s.constBool(true), false, 0)
4067 b = s.endBlock()
4068 b.AddEdgeTo(assign)
4069
4070
4071 grow = growSlice
4072 }
4073
4074
4075 s.startBlock(grow)
4076 taddr := s.expr(n.Fun)
4077 var r []*ssa.Value
4078 if info != nil && n.UseBuf {
4079
4080 if et.HasPointers() && !info.usedStatic {
4081
4082
4083
4084 mem := s.defvars[s.f.Entry.ID][memVar]
4085 mem = s.f.Entry.NewValue1A(n.Pos(), ssaop.OpVarDef, types.TypeMem, info.store, mem)
4086 addr := s.f.Entry.NewValue2A(n.Pos(), ssaop.OpLocalAddr, types.NewPtr(info.store.Type()), info.store, s.sp, mem)
4087 mem = s.f.Entry.NewValue2I(n.Pos(), ssaop.OpZero, types.TypeMem, info.store.Type().Size(), addr, mem)
4088 mem.Aux = info.store.Type()
4089 s.defvars[s.f.Entry.ID][memVar] = mem
4090 info.usedStatic = true
4091 }
4092 fn := ir.Syms.GrowsliceBuf
4093 if goexperiment.RuntimeFreegc && n.AppendNoAlias && !et.HasPointers() {
4094
4095
4096
4097
4098 fn = ir.Syms.GrowsliceBufNoAlias
4099 }
4100 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))
4101 } else {
4102 fn := ir.Syms.Growslice
4103 if goexperiment.RuntimeFreegc && n.AppendNoAlias && !et.HasPointers() {
4104
4105
4106
4107
4108 fn = ir.Syms.GrowsliceNoAlias
4109 }
4110 r = s.rtcall(fn, true, []*types.Type{n.Type()}, p, l, c, nargs, taddr)
4111 }
4112
4113
4114 p = s.newValue1(ssaop.OpSlicePtr, pt, r[0])
4115 l = s.newValue1(ssaop.OpSliceLen, types.Types[types.TINT], r[0])
4116 c = s.newValue1(ssaop.OpSliceCap, types.Types[types.TINT], r[0])
4117
4118 s.vars[ptrVar] = p
4119 s.vars[lenVar] = l
4120 s.vars[capVar] = c
4121 if inplace {
4122 if sn.Op() == ir.ONAME {
4123 sn := sn.(*ir.Name)
4124 if sn.Class != ir.PEXTERN {
4125
4126 s.vars[memVar] = s.newValue1A(ssaop.OpVarDef, types.TypeMem, sn, s.mem())
4127 }
4128 }
4129 capaddr := s.newValue1I(ssaop.OpOffPtr, s.f.Config.Types.IntPtr, types.SliceCapOffset, addr)
4130 s.store(types.Types[types.TINT], capaddr, c)
4131 s.store(pt, addr, p)
4132 }
4133
4134 b = s.endBlock()
4135 b.AddEdgeTo(assign)
4136
4137
4138 s.startBlock(assign)
4139 p = s.variable(ptrVar, pt)
4140 l = s.variable(lenVar, types.Types[types.TINT])
4141 if !inplace {
4142 c = s.variable(capVar, types.Types[types.TINT])
4143 }
4144
4145 if inplace {
4146
4147
4148 lenaddr := s.newValue1I(ssaop.OpOffPtr, s.f.Config.Types.IntPtr, types.SliceLenOffset, addr)
4149 s.store(types.Types[types.TINT], lenaddr, l)
4150 }
4151
4152
4153 type argRec struct {
4154
4155
4156 v *ssa.Value
4157 store bool
4158 }
4159 args := make([]argRec, 0, len(n.Args[1:]))
4160 for _, n := range n.Args[1:] {
4161 if ssa.CanSSA(n.Type()) {
4162 args = append(args, argRec{v: s.expr(n), store: true})
4163 } else {
4164 v := s.addr(n)
4165 args = append(args, argRec{v: v})
4166 }
4167 }
4168
4169
4170 oldLen = s.newValue2(s.ssaOp(ir.OSUB, types.Types[types.TINT]), types.Types[types.TINT], l, nargs)
4171 p2 := s.newValue2(ssaop.OpPtrIndex, pt, p, oldLen)
4172 for i, arg := range args {
4173 addr := s.newValue2(ssaop.OpPtrIndex, pt, p2, s.constInt(types.Types[types.TINT], int64(i)))
4174 if arg.store {
4175 s.storeType(et, addr, arg.v, 0, true)
4176 } else {
4177 s.move(et, addr, arg.v)
4178 }
4179 }
4180
4181
4182
4183
4184
4185 delete(s.vars, ptrVar)
4186 delete(s.vars, lenVar)
4187 if !inplace {
4188 delete(s.vars, capVar)
4189 }
4190
4191
4192 if inplace {
4193 return nil
4194 }
4195 return s.newValue3(ssaop.OpSliceMake, n.Type(), p, l, c)
4196 }
4197
4198 func (s *state) move2heap(n *ir.MoveToHeapExpr) *ssa.Value {
4199
4200
4201
4202
4203
4204
4205
4206
4207 slice := s.expr(n.Slice)
4208 et := slice.Type.Elem()
4209 pt := types.NewPtr(et)
4210
4211 info := s.getBackingStoreInfo(n)
4212 if info == nil {
4213
4214
4215 return slice
4216 }
4217
4218
4219 p := s.newValue1(ssaop.OpSlicePtr, pt, slice)
4220 l := s.newValue1(ssaop.OpSliceLen, types.Types[types.TINT], slice)
4221 c := s.newValue1(ssaop.OpSliceCap, types.Types[types.TINT], slice)
4222
4223 moveBlock := s.f.NewBlock(block.BlockPlain)
4224 mergeBlock := s.f.NewBlock(block.BlockPlain)
4225
4226 s.vars[ptrVar] = p
4227 s.vars[lenVar] = l
4228 s.vars[capVar] = c
4229
4230
4231
4232 sub := ssaop.OpSub64
4233 less := ssaop.OpLess64U
4234 if s.config.PtrSize == 4 {
4235 sub = ssaop.OpSub32
4236 less = ssaop.OpLess32U
4237 }
4238 callerSP := s.newValue1(ssaop.OpGetCallerSP, types.Types[types.TUINTPTR], s.mem())
4239 frameSize := s.newValue2(sub, types.Types[types.TUINTPTR], callerSP, s.sp)
4240 pInt := s.newValue2(ssaop.OpConvert, types.Types[types.TUINTPTR], p, s.mem())
4241 off := s.newValue2(sub, types.Types[types.TUINTPTR], pInt, s.sp)
4242 cond := s.newValue2(less, types.Types[types.TBOOL], off, frameSize)
4243
4244 b := s.endBlock()
4245 b.Kind = block.BlockIf
4246 b.Likely = ssa.BranchUnlikely
4247 b.SetControl(cond)
4248 b.AddEdgeTo(moveBlock)
4249 b.AddEdgeTo(mergeBlock)
4250
4251
4252 s.startBlock(moveBlock)
4253 var newSlice *ssa.Value
4254 if et.HasPointers() {
4255 typ := s.expr(n.RType)
4256 if n.PreserveCapacity {
4257 newSlice = s.rtcall(ir.Syms.MoveSlice, true, []*types.Type{slice.Type}, typ, p, l, c)[0]
4258 } else {
4259 newSlice = s.rtcall(ir.Syms.MoveSliceNoCap, true, []*types.Type{slice.Type}, typ, p, l)[0]
4260 }
4261 } else {
4262 elemSize := s.constInt(types.Types[types.TUINTPTR], et.Size())
4263 if n.PreserveCapacity {
4264 newSlice = s.rtcall(ir.Syms.MoveSliceNoScan, true, []*types.Type{slice.Type}, elemSize, p, l, c)[0]
4265 } else {
4266 newSlice = s.rtcall(ir.Syms.MoveSliceNoCapNoScan, true, []*types.Type{slice.Type}, elemSize, p, l)[0]
4267 }
4268 }
4269
4270 s.vars[ptrVar] = s.newValue1(ssaop.OpSlicePtr, pt, newSlice)
4271 s.vars[lenVar] = s.newValue1(ssaop.OpSliceLen, types.Types[types.TINT], newSlice)
4272 s.vars[capVar] = s.newValue1(ssaop.OpSliceCap, types.Types[types.TINT], newSlice)
4273 b = s.endBlock()
4274 b.AddEdgeTo(mergeBlock)
4275
4276
4277 s.startBlock(mergeBlock)
4278 p = s.variable(ptrVar, pt)
4279 l = s.variable(lenVar, types.Types[types.TINT])
4280 c = s.variable(capVar, types.Types[types.TINT])
4281 delete(s.vars, ptrVar)
4282 delete(s.vars, lenVar)
4283 delete(s.vars, capVar)
4284 return s.newValue3(ssaop.OpSliceMake, slice.Type, p, l, c)
4285 }
4286
4287
4288 func (s *state) minMax(n *ir.CallExpr) *ssa.Value {
4289
4290
4291
4292 fold := func(op func(x, a *ssa.Value) *ssa.Value) *ssa.Value {
4293 x := s.expr(n.Args[0])
4294 for _, arg := range n.Args[1:] {
4295 x = op(x, s.expr(arg))
4296 }
4297 return x
4298 }
4299
4300 typ := n.Type()
4301
4302 if typ.IsFloat() || typ.IsString() {
4303
4304
4305
4306
4307
4308
4309
4310
4311 if typ.IsFloat() {
4312 hasIntrinsic := false
4313 switch Arch.LinkArch.Family {
4314 case sys.AMD64, sys.ARM64, sys.Loong64, sys.RISCV64:
4315 hasIntrinsic = true
4316 case sys.PPC64:
4317 hasIntrinsic = buildcfg.GOPPC64 >= 9
4318 case sys.S390X:
4319
4320 }
4321
4322 if hasIntrinsic {
4323 var op ssaop.Op
4324 switch {
4325 case typ.Kind() == types.TFLOAT64 && n.Op() == ir.OMIN:
4326 op = ssaop.OpMin64F
4327 case typ.Kind() == types.TFLOAT64 && n.Op() == ir.OMAX:
4328 op = ssaop.OpMax64F
4329 case typ.Kind() == types.TFLOAT32 && n.Op() == ir.OMIN:
4330 op = ssaop.OpMin32F
4331 case typ.Kind() == types.TFLOAT32 && n.Op() == ir.OMAX:
4332 op = ssaop.OpMax32F
4333 }
4334 return fold(func(x, a *ssa.Value) *ssa.Value {
4335 return s.newValue2(op, typ, x, a)
4336 })
4337 }
4338 }
4339 var name string
4340 switch typ.Kind() {
4341 case types.TFLOAT32:
4342 switch n.Op() {
4343 case ir.OMIN:
4344 name = "fmin32"
4345 case ir.OMAX:
4346 name = "fmax32"
4347 }
4348 case types.TFLOAT64:
4349 switch n.Op() {
4350 case ir.OMIN:
4351 name = "fmin64"
4352 case ir.OMAX:
4353 name = "fmax64"
4354 }
4355 case types.TSTRING:
4356 switch n.Op() {
4357 case ir.OMIN:
4358 name = "strmin"
4359 case ir.OMAX:
4360 name = "strmax"
4361 }
4362 }
4363 fn := typecheck.LookupRuntimeFunc(name)
4364
4365 return fold(func(x, a *ssa.Value) *ssa.Value {
4366 return s.rtcall(fn, true, []*types.Type{typ}, x, a)[0]
4367 })
4368 }
4369
4370 if typ.IsInteger() {
4371 if Arch.LinkArch.Family == sys.RISCV64 && buildcfg.GORISCV64 >= 22 && typ.Size() == 8 {
4372 var op ssaop.Op
4373 switch {
4374 case typ.IsSigned() && n.Op() == ir.OMIN:
4375 op = ssaop.OpMin64
4376 case typ.IsSigned() && n.Op() == ir.OMAX:
4377 op = ssaop.OpMax64
4378 case typ.IsUnsigned() && n.Op() == ir.OMIN:
4379 op = ssaop.OpMin64u
4380 case typ.IsUnsigned() && n.Op() == ir.OMAX:
4381 op = ssaop.OpMax64u
4382 }
4383 return fold(func(x, a *ssa.Value) *ssa.Value {
4384 return s.newValue2(op, typ, x, a)
4385 })
4386 }
4387 }
4388
4389 lt := s.ssaOp(ir.OLT, typ)
4390
4391 return fold(func(x, a *ssa.Value) *ssa.Value {
4392 switch n.Op() {
4393 case ir.OMIN:
4394
4395 return s.ternary(s.newValue2(lt, types.Types[types.TBOOL], a, x), a, x)
4396 case ir.OMAX:
4397
4398 return s.ternary(s.newValue2(lt, types.Types[types.TBOOL], x, a), a, x)
4399 }
4400 panic("unreachable")
4401 })
4402 }
4403
4404
4405 func (s *state) ternary(cond, x, y *ssa.Value) *ssa.Value {
4406
4407
4408 ternaryVar := ssaMarker("ternary")
4409
4410 bThen := s.f.NewBlock(block.BlockPlain)
4411 bElse := s.f.NewBlock(block.BlockPlain)
4412 bEnd := s.f.NewBlock(block.BlockPlain)
4413
4414 b := s.endBlock()
4415 b.Kind = block.BlockIf
4416 b.SetControl(cond)
4417 b.AddEdgeTo(bThen)
4418 b.AddEdgeTo(bElse)
4419
4420 s.startBlock(bThen)
4421 s.vars[ternaryVar] = x
4422 s.endBlock().AddEdgeTo(bEnd)
4423
4424 s.startBlock(bElse)
4425 s.vars[ternaryVar] = y
4426 s.endBlock().AddEdgeTo(bEnd)
4427
4428 s.startBlock(bEnd)
4429 r := s.variable(ternaryVar, x.Type)
4430 delete(s.vars, ternaryVar)
4431 return r
4432 }
4433
4434
4435
4436
4437
4438 func (s *state) condBranch(cond ir.Node, yes, no *ssa.Block, likely int8) {
4439 switch cond.Op() {
4440 case ir.OANDAND:
4441 cond := cond.(*ir.LogicalExpr)
4442 mid := s.f.NewBlock(block.BlockPlain)
4443 s.stmtList(cond.Init())
4444 s.condBranch(cond.X, mid, no, max(likely, 0))
4445 s.startBlock(mid)
4446 s.condBranch(cond.Y, yes, no, likely)
4447 return
4448
4449
4450
4451
4452
4453
4454 case ir.OOROR:
4455 cond := cond.(*ir.LogicalExpr)
4456 mid := s.f.NewBlock(block.BlockPlain)
4457 s.stmtList(cond.Init())
4458 s.condBranch(cond.X, yes, mid, min(likely, 0))
4459 s.startBlock(mid)
4460 s.condBranch(cond.Y, yes, no, likely)
4461 return
4462
4463
4464
4465 case ir.ONOT:
4466 cond := cond.(*ir.UnaryExpr)
4467 s.stmtList(cond.Init())
4468 s.condBranch(cond.X, no, yes, -likely)
4469 return
4470 case ir.OCONVNOP:
4471 cond := cond.(*ir.ConvExpr)
4472 s.stmtList(cond.Init())
4473 s.condBranch(cond.X, yes, no, likely)
4474 return
4475 }
4476 c := s.expr(cond)
4477 b := s.endBlock()
4478 b.Kind = block.BlockIf
4479 b.SetControl(c)
4480 b.Likely = ssa.BranchPrediction(likely)
4481 b.AddEdgeTo(yes)
4482 b.AddEdgeTo(no)
4483 }
4484
4485 type skipMask uint8
4486
4487 const (
4488 skipPtr skipMask = 1 << iota
4489 skipLen
4490 skipCap
4491 )
4492
4493
4494
4495
4496
4497
4498
4499 func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask) {
4500 s.assignWhichMayOverlap(left, right, deref, skip, false)
4501 }
4502 func (s *state) assignWhichMayOverlap(left ir.Node, right *ssa.Value, deref bool, skip skipMask, mayOverlap bool) {
4503 if left.Op() == ir.ONAME && ir.IsBlank(left) {
4504 return
4505 }
4506 t := left.Type()
4507 types.CalcSize(t)
4508 if s.canSSA(left) {
4509 if deref {
4510 s.Fatalf("can SSA LHS %v but not RHS %s", left, right)
4511 }
4512 if left.Op() == ir.ODOT {
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523 left := left.(*ir.SelectorExpr)
4524 t := left.X.Type()
4525 nf := t.NumFields()
4526 idx := fieldIdx(left)
4527
4528
4529 old := s.expr(left.X)
4530
4531 if left.Type().Size() == 0 {
4532
4533 return
4534 }
4535
4536
4537 new := s.newValue0(ssaop.OpStructMake, t)
4538
4539
4540 for i := 0; i < nf; i++ {
4541 if i == idx {
4542 new.AddArg(right)
4543 } else {
4544 new.AddArg(s.newValue1I(ssaop.OpStructSelect, t.FieldType(i), int64(i), old))
4545 }
4546 }
4547
4548
4549 s.assign(left.X, new, false, 0)
4550
4551 return
4552 }
4553 if left.Op() == ir.OINDEX && left.(*ir.IndexExpr).X.Type().IsArray() {
4554 left := left.(*ir.IndexExpr)
4555 s.pushLine(left.Pos())
4556 defer s.popLine()
4557
4558
4559 t := left.X.Type()
4560 n := t.NumElem()
4561
4562 i := s.expr(left.Index)
4563 if n == 0 {
4564 _ = s.expr(left.X)
4565
4566
4567 z := s.constInt(types.Types[types.TINT], 0)
4568 s.boundsCheck(z, z, ssa.BoundsIndex, false)
4569 return
4570 }
4571 if t.Size() == 0 {
4572 _ = s.expr(left.X)
4573
4574
4575 len := s.constInt(types.Types[types.TINT], n)
4576 s.boundsCheck(i, len, ssa.BoundsIndex, false)
4577 return
4578 }
4579 if n != 1 {
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589 _ = s.expr(left.X)
4590 return
4591 }
4592
4593
4594 len := s.constInt(types.Types[types.TINT], 1)
4595 s.boundsCheck(i, len, ssa.BoundsIndex, false)
4596 v := s.newValue1(ssaop.OpArrayMake1, t, right)
4597 s.assign(left.X, v, false, 0)
4598 return
4599 }
4600 left := left.(*ir.Name)
4601
4602 s.vars[left] = right
4603 s.addNamedValue(left, right)
4604 return
4605 }
4606
4607
4608
4609 if base, ok := clobberBase(left).(*ir.Name); ok && base.OnStack() && skip == 0 && (t.HasPointers() || ssa.IsMergeCandidate(base)) {
4610 s.vars[memVar] = s.newValue1Apos(ssaop.OpVarDef, types.TypeMem, base, s.mem(), !ir.IsAutoTmp(base))
4611 }
4612
4613
4614 addr := s.addr(left)
4615 if ir.IsReflectHeaderDataField(left) {
4616
4617
4618
4619
4620
4621 t = types.Types[types.TUNSAFEPTR]
4622 }
4623 if deref {
4624
4625 if right == nil {
4626 s.zero(t, addr)
4627 } else {
4628 s.moveWhichMayOverlap(t, addr, right, mayOverlap)
4629 }
4630 return
4631 }
4632
4633 s.storeType(t, addr, right, skip, !ir.IsAutoTmp(left))
4634 }
4635
4636
4637 func (s *state) zeroVal(t *types.Type) *ssa.Value {
4638 if t.Size() == 0 {
4639 return s.entryNewValue0(ssaop.OpEmpty, t)
4640 }
4641 switch {
4642 case t.IsInteger():
4643 switch t.Size() {
4644 case 1:
4645 return s.constInt8(t, 0)
4646 case 2:
4647 return s.constInt16(t, 0)
4648 case 4:
4649 return s.constInt32(t, 0)
4650 case 8:
4651 return s.constInt64(t, 0)
4652 default:
4653 s.Fatalf("bad sized integer type %v", t)
4654 }
4655 case t.IsFloat():
4656 switch t.Size() {
4657 case 4:
4658 return s.constFloat32(t, 0)
4659 case 8:
4660 return s.constFloat64(t, 0)
4661 default:
4662 s.Fatalf("bad sized float type %v", t)
4663 }
4664 case t.IsComplex():
4665 switch t.Size() {
4666 case 8:
4667 z := s.constFloat32(types.Types[types.TFLOAT32], 0)
4668 return s.entryNewValue2(ssaop.OpComplexMake, t, z, z)
4669 case 16:
4670 z := s.constFloat64(types.Types[types.TFLOAT64], 0)
4671 return s.entryNewValue2(ssaop.OpComplexMake, t, z, z)
4672 default:
4673 s.Fatalf("bad sized complex type %v", t)
4674 }
4675
4676 case t.IsString():
4677 return s.constEmptyString(t)
4678 case t.IsPtrShaped():
4679 return s.constNil(t)
4680 case t.IsBoolean():
4681 return s.constBool(false)
4682 case t.IsInterface():
4683 return s.constInterface(t)
4684 case t.IsSlice():
4685 return s.constSlice(t)
4686 case isStructNotSIMD(t):
4687 n := t.NumFields()
4688 v := s.entryNewValue0(ssaop.OpStructMake, t)
4689 for i := 0; i < n; i++ {
4690 v.AddArg(s.zeroVal(t.FieldType(i)))
4691 }
4692 return v
4693 case t.IsArray() && t.NumElem() == 1:
4694 return s.entryNewValue1(ssaop.OpArrayMake1, t, s.zeroVal(t.Elem()))
4695 case t.IsSIMD():
4696 return s.newValue0(ssaop.OpZeroSIMD, t)
4697 }
4698 s.Fatalf("zero for type %v not implemented", t)
4699 return nil
4700 }
4701
4702 type callKind int8
4703
4704 const (
4705 callNormal callKind = iota
4706 callDefer
4707 callDeferStack
4708 callGo
4709 callTail
4710 )
4711
4712 type sfRtCallDef struct {
4713 rtfn *obj.LSym
4714 rtype types.Kind
4715 }
4716
4717 var softFloatOps map[ssaop.Op]sfRtCallDef
4718
4719 func softfloatInit() {
4720
4721 softFloatOps = map[ssaop.Op]sfRtCallDef{
4722 ssaop.OpAdd32F: {typecheck.LookupRuntimeFunc("fadd32"), types.TFLOAT32},
4723 ssaop.OpAdd64F: {typecheck.LookupRuntimeFunc("fadd64"), types.TFLOAT64},
4724 ssaop.OpSub32F: {typecheck.LookupRuntimeFunc("fadd32"), types.TFLOAT32},
4725 ssaop.OpSub64F: {typecheck.LookupRuntimeFunc("fadd64"), types.TFLOAT64},
4726 ssaop.OpMul32F: {typecheck.LookupRuntimeFunc("fmul32"), types.TFLOAT32},
4727 ssaop.OpMul64F: {typecheck.LookupRuntimeFunc("fmul64"), types.TFLOAT64},
4728 ssaop.OpDiv32F: {typecheck.LookupRuntimeFunc("fdiv32"), types.TFLOAT32},
4729 ssaop.OpDiv64F: {typecheck.LookupRuntimeFunc("fdiv64"), types.TFLOAT64},
4730
4731 ssaop.OpEq64F: {typecheck.LookupRuntimeFunc("feq64"), types.TBOOL},
4732 ssaop.OpEq32F: {typecheck.LookupRuntimeFunc("feq32"), types.TBOOL},
4733 ssaop.OpNeq64F: {typecheck.LookupRuntimeFunc("feq64"), types.TBOOL},
4734 ssaop.OpNeq32F: {typecheck.LookupRuntimeFunc("feq32"), types.TBOOL},
4735 ssaop.OpLess64F: {typecheck.LookupRuntimeFunc("fgt64"), types.TBOOL},
4736 ssaop.OpLess32F: {typecheck.LookupRuntimeFunc("fgt32"), types.TBOOL},
4737 ssaop.OpLeq64F: {typecheck.LookupRuntimeFunc("fge64"), types.TBOOL},
4738 ssaop.OpLeq32F: {typecheck.LookupRuntimeFunc("fge32"), types.TBOOL},
4739
4740 ssaop.OpCvt32to32F: {typecheck.LookupRuntimeFunc("fint32to32"), types.TFLOAT32},
4741 ssaop.OpCvt32Fto32: {typecheck.LookupRuntimeFunc("f32toint32"), types.TINT32},
4742 ssaop.OpCvt64to32F: {typecheck.LookupRuntimeFunc("fint64to32"), types.TFLOAT32},
4743 ssaop.OpCvt32Fto64: {typecheck.LookupRuntimeFunc("f32toint64"), types.TINT64},
4744 ssaop.OpCvt64Uto32F: {typecheck.LookupRuntimeFunc("fuint64to32"), types.TFLOAT32},
4745 ssaop.OpCvt32Fto64U: {typecheck.LookupRuntimeFunc("f32touint64"), types.TUINT64},
4746 ssaop.OpCvt32to64F: {typecheck.LookupRuntimeFunc("fint32to64"), types.TFLOAT64},
4747 ssaop.OpCvt64Fto32: {typecheck.LookupRuntimeFunc("f64toint32"), types.TINT32},
4748 ssaop.OpCvt64to64F: {typecheck.LookupRuntimeFunc("fint64to64"), types.TFLOAT64},
4749 ssaop.OpCvt64Fto64: {typecheck.LookupRuntimeFunc("f64toint64"), types.TINT64},
4750 ssaop.OpCvt64Uto64F: {typecheck.LookupRuntimeFunc("fuint64to64"), types.TFLOAT64},
4751 ssaop.OpCvt64Fto64U: {typecheck.LookupRuntimeFunc("f64touint64"), types.TUINT64},
4752 ssaop.OpCvt32Fto64F: {typecheck.LookupRuntimeFunc("f32to64"), types.TFLOAT64},
4753 ssaop.OpCvt64Fto32F: {typecheck.LookupRuntimeFunc("f64to32"), types.TFLOAT32},
4754 }
4755 }
4756
4757
4758
4759 func (s *state) sfcall(op ssaop.Op, args ...*ssa.Value) (*ssa.Value, bool) {
4760 f2i := func(t *types.Type) *types.Type {
4761 switch t.Kind() {
4762 case types.TFLOAT32:
4763 return types.Types[types.TUINT32]
4764 case types.TFLOAT64:
4765 return types.Types[types.TUINT64]
4766 }
4767 return t
4768 }
4769
4770 if callDef, ok := softFloatOps[op]; ok {
4771 switch op {
4772 case ssaop.OpLess32F,
4773 ssaop.OpLess64F,
4774 ssaop.OpLeq32F,
4775 ssaop.OpLeq64F:
4776 args[0], args[1] = args[1], args[0]
4777 case ssaop.OpSub32F,
4778 ssaop.OpSub64F:
4779 args[1] = s.newValue1(s.ssaOp(ir.ONEG, types.Types[callDef.rtype]), args[1].Type, args[1])
4780 }
4781
4782
4783
4784 for i, a := range args {
4785 if a.Type.IsFloat() {
4786 args[i] = s.newValue1(ssaop.OpCopy, f2i(a.Type), a)
4787 }
4788 }
4789
4790 rt := types.Types[callDef.rtype]
4791 result := s.rtcall(callDef.rtfn, true, []*types.Type{f2i(rt)}, args...)[0]
4792 if rt.IsFloat() {
4793 result = s.newValue1(ssaop.OpCopy, rt, result)
4794 }
4795 if op == ssaop.OpNeq32F || op == ssaop.OpNeq64F {
4796 result = s.newValue1(ssaop.OpNot, result.Type, result)
4797 }
4798 return result, true
4799 }
4800 return nil, false
4801 }
4802
4803
4804 func (s *state) split(v *ssa.Value) (*ssa.Value, *ssa.Value) {
4805 p0 := s.newValue1(ssaop.OpSelect0, v.Type.FieldType(0), v)
4806 p1 := s.newValue1(ssaop.OpSelect1, v.Type.FieldType(1), v)
4807 return p0, p1
4808 }
4809
4810
4811 func (s *state) intrinsicCall(n *ir.CallExpr) *ssa.Value {
4812 v := findIntrinsic(n.Fun.Sym())(s, n, s.intrinsicArgs(n))
4813 if ssaconfig.IntrinsicsDebug > 0 {
4814 x := v
4815 if x == nil {
4816 x = s.mem()
4817 }
4818 if x.Op == ssaop.OpSelect0 || x.Op == ssaop.OpSelect1 {
4819 x = x.Args[0]
4820 }
4821 base.WarnfAt(n.Pos(), "intrinsic substitution for %v with %s", n.Fun.Sym().Name, x.LongString())
4822 }
4823 return v
4824 }
4825
4826
4827 func (s *state) intrinsicArgs(n *ir.CallExpr) []*ssa.Value {
4828 args := make([]*ssa.Value, len(n.Args))
4829 for i, n := range n.Args {
4830 args[i] = s.expr(n)
4831 }
4832 return args
4833 }
4834
4835
4836
4837
4838
4839
4840
4841 func (s *state) openDeferRecord(n *ir.CallExpr) {
4842 if len(n.Args) != 0 || n.Op() != ir.OCALLFUNC || n.Fun.Type().NumResults() != 0 {
4843 s.Fatalf("defer call with arguments or results: %v", n)
4844 }
4845
4846 opendefer := &openDeferInfo{
4847 n: n,
4848 }
4849 fn := n.Fun
4850
4851
4852
4853 closureVal := s.expr(fn)
4854 closure := s.openDeferSave(fn.Type(), closureVal)
4855 opendefer.closureNode = closure.Aux.(*ir.Name)
4856 if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC) {
4857 opendefer.closure = closure
4858 }
4859 index := len(s.openDefers)
4860 s.openDefers = append(s.openDefers, opendefer)
4861
4862
4863
4864 bitvalue := s.constInt8(types.Types[types.TUINT8], 1<<uint(index))
4865 newDeferBits := s.newValue2(ssaop.OpOr8, types.Types[types.TUINT8], s.variable(deferBitsVar, types.Types[types.TUINT8]), bitvalue)
4866 s.vars[deferBitsVar] = newDeferBits
4867 s.store(types.Types[types.TUINT8], s.deferBitsAddr, newDeferBits)
4868 }
4869
4870
4871
4872
4873
4874
4875 func (s *state) openDeferSave(t *types.Type, val *ssa.Value) *ssa.Value {
4876 if !ssa.CanSSA(t) {
4877 s.Fatalf("openDeferSave of non-SSA-able type %v val=%v", t, val)
4878 }
4879 if !t.HasPointers() {
4880 s.Fatalf("openDeferSave of pointerless type %v val=%v", t, val)
4881 }
4882 pos := val.Pos
4883 temp := typecheck.TempAt(pos.WithNotStmt(), s.curfn, t)
4884 temp.SetOpenDeferSlot(true)
4885 temp.SetFrameOffset(int64(len(s.openDefers)))
4886 var addrTemp *ssa.Value
4887
4888
4889 if s.curBlock.ID != s.f.Entry.ID {
4890
4891
4892
4893 if t.HasPointers() {
4894 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])
4895 }
4896 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])
4897 addrTemp = s.f.Entry.NewValue2A(src.NoXPos, ssaop.OpLocalAddr, types.NewPtr(temp.Type()), temp, s.sp, s.defvars[s.f.Entry.ID][memVar])
4898 } else {
4899
4900
4901
4902 if t.HasPointers() {
4903 s.vars[memVar] = s.newValue1Apos(ssaop.OpVarDef, types.TypeMem, temp, s.mem(), false)
4904 }
4905 s.vars[memVar] = s.newValue1Apos(ssaop.OpVarLive, types.TypeMem, temp, s.mem(), false)
4906 addrTemp = s.newValue2Apos(ssaop.OpLocalAddr, types.NewPtr(temp.Type()), temp, s.sp, s.mem(), false)
4907 }
4908
4909
4910
4911
4912
4913 temp.SetNeedzero(true)
4914
4915
4916 s.store(t, addrTemp, val)
4917 return addrTemp
4918 }
4919
4920
4921
4922
4923
4924 func (s *state) openDeferExit() {
4925 deferExit := s.f.NewBlock(block.BlockPlain)
4926 s.endBlock().AddEdgeTo(deferExit)
4927 s.startBlock(deferExit)
4928 s.lastDeferExit = deferExit
4929 s.lastDeferCount = len(s.openDefers)
4930 zeroval := s.constInt8(types.Types[types.TUINT8], 0)
4931
4932 for i := len(s.openDefers) - 1; i >= 0; i-- {
4933 r := s.openDefers[i]
4934 bCond := s.f.NewBlock(block.BlockPlain)
4935 bEnd := s.f.NewBlock(block.BlockPlain)
4936
4937 deferBits := s.variable(deferBitsVar, types.Types[types.TUINT8])
4938
4939
4940 bitval := s.constInt8(types.Types[types.TUINT8], 1<<uint(i))
4941 andval := s.newValue2(ssaop.OpAnd8, types.Types[types.TUINT8], deferBits, bitval)
4942 eqVal := s.newValue2(ssaop.OpEq8, types.Types[types.TBOOL], andval, zeroval)
4943 b := s.endBlock()
4944 b.Kind = block.BlockIf
4945 b.SetControl(eqVal)
4946 b.AddEdgeTo(bEnd)
4947 b.AddEdgeTo(bCond)
4948 bCond.AddEdgeTo(bEnd)
4949 s.startBlock(bCond)
4950
4951
4952
4953 nbitval := s.newValue1(ssaop.OpCom8, types.Types[types.TUINT8], bitval)
4954 maskedval := s.newValue2(ssaop.OpAnd8, types.Types[types.TUINT8], deferBits, nbitval)
4955 s.store(types.Types[types.TUINT8], s.deferBitsAddr, maskedval)
4956
4957
4958 s.vars[deferBitsVar] = maskedval
4959
4960
4961
4962
4963 fn := r.n.Fun
4964 stksize := fn.Type().ArgWidth()
4965 var callArgs []*ssa.Value
4966 var call *ssa.Value
4967 if r.closure != nil {
4968 v := s.load(r.closure.Type.Elem(), r.closure)
4969 s.maybeNilCheckClosure(v, callDefer)
4970 codeptr := s.rawLoad(types.Types[types.TUINTPTR], v)
4971 aux := ssa.ClosureAuxCall(s.f.ABIDefault.ABIAnalyzeTypes(nil, nil))
4972 call = s.newValue2A(ssaop.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v)
4973 } else {
4974 aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), s.f.ABIDefault.ABIAnalyzeTypes(nil, nil))
4975 call = s.newValue0A(ssaop.OpStaticLECall, aux.LateExpansionResultType(), aux)
4976 }
4977 callArgs = append(callArgs, s.mem())
4978 call.AddArgs(callArgs...)
4979 call.AuxInt = stksize
4980 s.vars[memVar] = s.newValue1I(ssaop.OpSelectN, types.TypeMem, 0, call)
4981
4982
4983
4984
4985 if r.closureNode != nil {
4986 s.vars[memVar] = s.newValue1Apos(ssaop.OpVarLive, types.TypeMem, r.closureNode, s.mem(), false)
4987 }
4988
4989 s.endBlock()
4990 s.startBlock(bEnd)
4991 }
4992 }
4993
4994 func (s *state) callResult(n *ir.CallExpr, k callKind) *ssa.Value {
4995 return s.call(n, k, false, nil)
4996 }
4997
4998 func (s *state) callAddr(n *ir.CallExpr, k callKind) *ssa.Value {
4999 return s.call(n, k, true, nil)
5000 }
5001
5002
5003
5004 func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool, deferExtra ir.Expr) *ssa.Value {
5005 s.prevCall = nil
5006 var calleeLSym *obj.LSym
5007 var closure *ssa.Value
5008 var codeptr *ssa.Value
5009 var dextra *ssa.Value
5010 var rcvr *ssa.Value
5011 fn := n.Fun
5012 var ACArgs []*types.Type
5013 var ACResults []*types.Type
5014 var callArgs []*ssa.Value
5015
5016 callABI := s.f.ABIDefault
5017
5018 if k != callNormal && k != callTail && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.Fun.Type().NumResults() != 0) {
5019 s.Fatalf("go/defer call with arguments: %v", n)
5020 }
5021
5022 isCallDeferRangeFunc := false
5023
5024 switch n.Op() {
5025 case ir.OCALLFUNC:
5026 if (k == callNormal || k == callTail) && fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC {
5027 fn := fn.(*ir.Name)
5028 calleeLSym = callTargetLSym(fn)
5029 if buildcfg.Experiment.RegabiArgs {
5030
5031
5032
5033
5034
5035 if fn.Func != nil {
5036 callABI = abiForFunc(fn.Func, s.f.ABI0, s.f.ABI1)
5037 }
5038 } else {
5039
5040 inRegistersImported := fn.Pragma()&ir.RegisterParams != 0
5041 inRegistersSamePackage := fn.Func != nil && fn.Func.Pragma&ir.RegisterParams != 0
5042 if inRegistersImported || inRegistersSamePackage {
5043 callABI = s.f.ABI1
5044 }
5045 }
5046 if fn := n.Fun.Sym().Name; n.Fun.Sym().Pkg == ir.Pkgs.Runtime && fn == "deferrangefunc" {
5047 isCallDeferRangeFunc = true
5048 }
5049 break
5050 }
5051 closure = s.expr(fn)
5052 if k != callDefer && k != callDeferStack {
5053
5054
5055 s.maybeNilCheckClosure(closure, k)
5056 }
5057 case ir.OCALLINTER:
5058 if fn.Op() != ir.ODOTINTER {
5059 s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
5060 }
5061 fn := fn.(*ir.SelectorExpr)
5062 var iclosure *ssa.Value
5063 iclosure, rcvr = s.getClosureAndRcvr(fn)
5064 if k == callNormal || k == callTail {
5065 codeptr = s.load(types.Types[types.TUINTPTR], iclosure)
5066 } else {
5067 closure = iclosure
5068 }
5069 }
5070 if deferExtra != nil {
5071 dextra = s.expr(deferExtra)
5072 }
5073
5074 params := callABI.ABIAnalyze(n.Fun.Type(), false )
5075 types.CalcSize(fn.Type())
5076 stksize := params.ArgWidth()
5077
5078 res := n.Fun.Type().Results()
5079 if k == callNormal || k == callTail {
5080 for _, p := range params.OutParams() {
5081 ACResults = append(ACResults, p.Type)
5082 }
5083 }
5084
5085 var call *ssa.Value
5086 if k == callDeferStack {
5087 if stksize != 0 {
5088 s.Fatalf("deferprocStack with non-zero stack size %d: %v", stksize, n)
5089 }
5090
5091 t := deferstruct()
5092 n, addr := s.temp(n.Pos(), t)
5093 n.SetNonMergeable(true)
5094 s.store(closure.Type,
5095 s.newValue1I(ssaop.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(deferStructFnField), addr),
5096 closure)
5097
5098
5099 ACArgs = append(ACArgs, types.Types[types.TUINTPTR])
5100 aux := ssa.StaticAuxCall(ir.Syms.DeferprocStack, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5101 callArgs = append(callArgs, addr, s.mem())
5102 call = s.newValue0A(ssaop.OpStaticLECall, aux.LateExpansionResultType(), aux)
5103 call.AddArgs(callArgs...)
5104 call.AuxInt = int64(types.PtrSize)
5105 } else {
5106
5107
5108 argStart := base.Ctxt.Arch.FixedFrameSize
5109
5110 if k != callNormal && k != callTail {
5111
5112 ACArgs = append(ACArgs, types.Types[types.TUINTPTR])
5113 callArgs = append(callArgs, closure)
5114 stksize += int64(types.PtrSize)
5115 argStart += int64(types.PtrSize)
5116 if dextra != nil {
5117
5118 ACArgs = append(ACArgs, types.Types[types.TINTER])
5119 callArgs = append(callArgs, dextra)
5120 stksize += 2 * int64(types.PtrSize)
5121 argStart += 2 * int64(types.PtrSize)
5122 }
5123 }
5124
5125
5126 if rcvr != nil {
5127 callArgs = append(callArgs, rcvr)
5128 }
5129
5130
5131 t := n.Fun.Type()
5132 args := n.Args
5133
5134 for _, p := range params.InParams() {
5135 ACArgs = append(ACArgs, p.Type)
5136 }
5137
5138
5139
5140
5141 if s.curBlock.ID == s.f.Entry.ID && s.hasOpenDefers {
5142 b := s.endBlock()
5143 b.Kind = block.BlockPlain
5144 curb := s.f.NewBlock(block.BlockPlain)
5145 b.AddEdgeTo(curb)
5146 s.startBlock(curb)
5147 }
5148
5149 for i, n := range args {
5150 callArgs = append(callArgs, s.putArg(n, t.Param(i).Type))
5151 }
5152
5153
5154
5155
5156
5157
5158
5159 if k == callTail && s.instrumentEnterExit {
5160 s.rtcall(ir.Syms.Racefuncexit, true, nil)
5161 }
5162
5163 callArgs = append(callArgs, s.mem())
5164
5165
5166 switch {
5167 case k == callDefer:
5168 sym := ir.Syms.Deferproc
5169 if dextra != nil {
5170 sym = ir.Syms.Deferprocat
5171 }
5172 aux := ssa.StaticAuxCall(sym, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5173 call = s.newValue0A(ssaop.OpStaticLECall, aux.LateExpansionResultType(), aux)
5174 case k == callGo:
5175 aux := ssa.StaticAuxCall(ir.Syms.Newproc, s.f.ABIDefault.ABIAnalyzeTypes(ACArgs, ACResults))
5176 call = s.newValue0A(ssaop.OpStaticLECall, aux.LateExpansionResultType(), aux)
5177 case closure != nil:
5178
5179
5180
5181
5182
5183 codeptr = s.rawLoad(types.Types[types.TUINTPTR], closure)
5184 aux := ssa.ClosureAuxCall(callABI.ABIAnalyzeTypes(ACArgs, ACResults))
5185 call = s.newValue2A(ssaop.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure)
5186 case codeptr != nil:
5187
5188 aux := ssa.InterfaceAuxCall(params)
5189 call = s.newValue1A(ssaop.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr)
5190 if k == callTail {
5191 call.Op = ssaop.OpTailLECallInter
5192 stksize = 0
5193 }
5194 case calleeLSym != nil:
5195 aux := ssa.StaticAuxCall(calleeLSym, params)
5196 call = s.newValue0A(ssaop.OpStaticLECall, aux.LateExpansionResultType(), aux)
5197 if k == callTail {
5198 call.Op = ssaop.OpTailLECall
5199 stksize = 0
5200 }
5201 default:
5202 s.Fatalf("bad call type %v %v", n.Op(), n)
5203 }
5204 call.AddArgs(callArgs...)
5205 call.AuxInt = stksize
5206 }
5207 s.prevCall = call
5208 s.vars[memVar] = s.newValue1I(ssaop.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
5209
5210 for _, v := range n.KeepAlive {
5211 if !v.Addrtaken() {
5212 s.Fatalf("KeepAlive variable %v must have Addrtaken set", v)
5213 }
5214 switch v.Class {
5215 case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
5216 default:
5217 s.Fatalf("KeepAlive variable %v must be Auto or Arg", v)
5218 }
5219 s.vars[memVar] = s.newValue1A(ssaop.OpVarLive, types.TypeMem, v, s.mem())
5220 }
5221
5222
5223 var result *ssa.Value
5224 if len(res) == 0 || k != callNormal {
5225 result = nil
5226 } else {
5227 fp := res[0]
5228 if returnResultAddr {
5229 result = s.resultAddrOfCall(call, 0, fp.Type)
5230 } else {
5231 result = s.newValue1I(ssaop.OpSelectN, fp.Type, 0, call)
5232 }
5233 if n.Reshape {
5234 result = s.newValue1(ssaop.OpCopy, n.Type(), result)
5235 }
5236 }
5237
5238
5239 if k == callDefer || k == callDeferStack || isCallDeferRangeFunc {
5240 b := s.endBlock()
5241 b.Kind = block.BlockDefer
5242 b.SetControl(call)
5243 bNext := s.f.NewBlock(block.BlockPlain)
5244 b.AddEdgeTo(bNext)
5245 r := s.f.DeferReturn
5246 if r == nil {
5247 r = s.f.NewBlock(block.BlockPlain)
5248 s.startBlock(r)
5249 s.exit()
5250 s.f.DeferReturn = r
5251 }
5252 b.AddEdgeTo(r)
5253 b.Likely = ssa.BranchLikely
5254 s.startBlock(bNext)
5255 }
5256
5257 return result
5258 }
5259
5260
5261
5262 func (s *state) maybeNilCheckClosure(closure *ssa.Value, k callKind) {
5263 if Arch.LinkArch.Family == sys.Wasm || buildcfg.GOOS == "aix" && k != callGo {
5264
5265
5266 s.nilCheck(closure)
5267 }
5268 }
5269
5270
5271
5272 func (s *state) getClosureAndRcvr(fn *ir.SelectorExpr) (*ssa.Value, *ssa.Value) {
5273 i := s.expr(fn.X)
5274 itab := s.newValue1(ssaop.OpITab, types.Types[types.TUINTPTR], i)
5275 s.nilCheck(itab)
5276 itabidx := fn.Offset() + rttype.ITab.OffsetOf("Fun")
5277 closure := s.newValue1I(ssaop.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
5278 rcvr := s.newValue1(ssaop.OpIData, s.f.Config.Types.BytePtr, i)
5279 return closure, rcvr
5280 }
5281
5282
5283
5284 func etypesign(e types.Kind) int8 {
5285 switch e {
5286 case types.TINT8, types.TINT16, types.TINT32, types.TINT64, types.TINT:
5287 return -1
5288 case types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINT, types.TUINTPTR, types.TUNSAFEPTR:
5289 return +1
5290 }
5291 return 0
5292 }
5293
5294
5295
5296 func (s *state) addr(n ir.Node) *ssa.Value {
5297 if n.Op() != ir.ONAME {
5298 s.pushLine(n.Pos())
5299 defer s.popLine()
5300 }
5301
5302 if s.canSSA(n) {
5303
5304
5305
5306
5307
5308
5309
5310
5311 s.boundsCheckArrayIndex(n)
5312 return s.newValue1A(ssaop.OpAddr, n.Type().PtrTo(), ir.Syms.Zerobase, s.sb)
5313 }
5314
5315 t := types.NewPtr(n.Type())
5316 linksymOffset := func(lsym *obj.LSym, offset int64) *ssa.Value {
5317 v := s.entryNewValue1A(ssaop.OpAddr, t, lsym, s.sb)
5318
5319 if offset != 0 {
5320 v = s.entryNewValue1I(ssaop.OpOffPtr, v.Type, offset, v)
5321 }
5322 return v
5323 }
5324 switch n.Op() {
5325 case ir.OLINKSYMOFFSET:
5326 no := n.(*ir.LinksymOffsetExpr)
5327 return linksymOffset(no.Linksym, no.Offset_)
5328 case ir.ONAME:
5329 n := n.(*ir.Name)
5330 if n.Heapaddr != nil {
5331 return s.expr(n.Heapaddr)
5332 }
5333 switch n.Class {
5334 case ir.PEXTERN:
5335
5336 return linksymOffset(n.Linksym(), 0)
5337 case ir.PPARAM:
5338
5339 v := s.decladdrs[n]
5340 if v != nil {
5341 return v
5342 }
5343 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
5344 return nil
5345 case ir.PAUTO:
5346 return s.newValue2Apos(ssaop.OpLocalAddr, t, n, s.sp, s.mem(), !ir.IsAutoTmp(n))
5347
5348 case ir.PPARAMOUT:
5349
5350
5351 return s.newValue2Apos(ssaop.OpLocalAddr, t, n, s.sp, s.mem(), true)
5352 default:
5353 s.Fatalf("variable address class %v not implemented", n.Class)
5354 return nil
5355 }
5356 case ir.ORESULT:
5357
5358 n := n.(*ir.ResultExpr)
5359 return s.resultAddrOfCall(s.prevCall, n.Index, n.Type())
5360 case ir.OINDEX:
5361 n := n.(*ir.IndexExpr)
5362 if n.X.Type().IsSlice() {
5363 a := s.expr(n.X)
5364 i := s.expr(n.Index)
5365 len := s.newValue1(ssaop.OpSliceLen, types.Types[types.TINT], a)
5366 i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
5367 p := s.newValue1(ssaop.OpSlicePtr, t, a)
5368 return s.newValue2(ssaop.OpPtrIndex, t, p, i)
5369 } else {
5370 a := s.addr(n.X)
5371 i := s.expr(n.Index)
5372 len := s.constInt(types.Types[types.TINT], n.X.Type().NumElem())
5373 i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
5374 return s.newValue2(ssaop.OpPtrIndex, types.NewPtr(n.X.Type().Elem()), a, i)
5375 }
5376 case ir.ODEREF:
5377 n := n.(*ir.StarExpr)
5378 return s.exprPtr(n.X, n.Bounded(), n.Pos())
5379 case ir.ODOT:
5380 n := n.(*ir.SelectorExpr)
5381 p := s.addr(n.X)
5382 return s.newValue1I(ssaop.OpOffPtr, t, n.Offset(), p)
5383 case ir.ODOTPTR:
5384 n := n.(*ir.SelectorExpr)
5385 p := s.exprPtr(n.X, n.Bounded(), n.Pos())
5386 return s.newValue1I(ssaop.OpOffPtr, t, n.Offset(), p)
5387 case ir.OCONVNOP:
5388 n := n.(*ir.ConvExpr)
5389 if n.Type() == n.X.Type() {
5390 return s.addr(n.X)
5391 }
5392 addr := s.addr(n.X)
5393 return s.newValue1(ssaop.OpCopy, t, addr)
5394 case ir.OCALLFUNC, ir.OCALLINTER:
5395 n := n.(*ir.CallExpr)
5396 return s.callAddr(n, callNormal)
5397 case ir.ODOTTYPE, ir.ODYNAMICDOTTYPE:
5398 var v *ssa.Value
5399 if n.Op() == ir.ODOTTYPE {
5400 v, _ = s.dottype(n.(*ir.TypeAssertExpr), false)
5401 } else {
5402 v, _ = s.dynamicDottype(n.(*ir.DynamicTypeAssertExpr), false)
5403 }
5404 if v.Op != ssaop.OpLoad {
5405 s.Fatalf("dottype of non-load")
5406 }
5407 if v.Args[1] != s.mem() {
5408 s.Fatalf("memory no longer live from dottype load")
5409 }
5410 return v.Args[0]
5411 default:
5412 s.Fatalf("unhandled addr %v", n.Op())
5413 return nil
5414 }
5415 }
5416
5417
5418
5419 func (s *state) canSSA(n ir.Node) bool {
5420 if base.Flag.N != 0 {
5421 return false
5422 }
5423 for {
5424 nn := n
5425 if nn.Op() == ir.ODOT {
5426 nn := nn.(*ir.SelectorExpr)
5427 n = nn.X
5428 continue
5429 }
5430 if nn.Op() == ir.OINDEX {
5431 nn := nn.(*ir.IndexExpr)
5432 if nn.X.Type().IsArray() {
5433 n = nn.X
5434 continue
5435 }
5436 }
5437 break
5438 }
5439 if n.Op() != ir.ONAME {
5440 return false
5441 }
5442 return s.canSSAName(n.(*ir.Name)) && ssa.CanSSA(n.Type())
5443 }
5444
5445 func (s *state) canSSAName(name *ir.Name) bool {
5446 if name.Addrtaken() || !name.OnStack() {
5447 return false
5448 }
5449 switch name.Class {
5450 case ir.PPARAMOUT:
5451 if s.hasdefer {
5452
5453
5454
5455
5456
5457 return false
5458 }
5459 if s.cgoUnsafeArgs {
5460
5461
5462 return false
5463 }
5464 }
5465 return true
5466
5467 }
5468
5469
5470 func (s *state) exprPtr(n ir.Node, bounded bool, lineno src.XPos) *ssa.Value {
5471 p := s.expr(n)
5472 if bounded || n.NonNil() {
5473 if s.f.Frontend().Debug_checknil() && lineno.Line() > 1 {
5474 s.f.Warnl(lineno, "removed nil check")
5475 }
5476 return p
5477 }
5478 p = s.nilCheck(p)
5479 return p
5480 }
5481
5482
5483
5484
5485
5486
5487 func (s *state) nilCheck(ptr *ssa.Value) *ssa.Value {
5488 if base.Debug.DisableNil != 0 || s.curfn.NilCheckDisabled() {
5489 return ptr
5490 }
5491 return s.newValue2(ssaop.OpNilCheck, ptr.Type, ptr, s.mem())
5492 }
5493
5494
5495 func (s *state) boundsCheckArrayIndex(n ir.Node) {
5496 if n.Op() != ir.OINDEX {
5497 return
5498 }
5499 nn := n.(*ir.IndexExpr)
5500 typ := nn.X.Type()
5501 if typ.IsArray() {
5502 _ = s.expr(nn.X)
5503 idx := s.expr(nn.Index)
5504 len := s.constInt(types.Types[types.TINT], typ.NumElem())
5505 s.boundsCheck(idx, len, ssa.BoundsIndex, nn.Bounded())
5506 }
5507 }
5508
5509
5510
5511
5512
5513
5514
5515 func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
5516 idx = s.extendIndex(idx, len, kind, bounded)
5517
5518 if bounded || base.Flag.B != 0 {
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539 return idx
5540 }
5541
5542 bNext := s.f.NewBlock(block.BlockPlain)
5543 bPanic := s.f.NewBlock(block.BlockExit)
5544
5545 if !idx.Type.IsSigned() {
5546 switch kind {
5547 case ssa.BoundsIndex:
5548 kind = ssa.BoundsIndexU
5549 case ssa.BoundsSliceAlen:
5550 kind = ssa.BoundsSliceAlenU
5551 case ssa.BoundsSliceAcap:
5552 kind = ssa.BoundsSliceAcapU
5553 case ssa.BoundsSliceB:
5554 kind = ssa.BoundsSliceBU
5555 case ssa.BoundsSlice3Alen:
5556 kind = ssa.BoundsSlice3AlenU
5557 case ssa.BoundsSlice3Acap:
5558 kind = ssa.BoundsSlice3AcapU
5559 case ssa.BoundsSlice3B:
5560 kind = ssa.BoundsSlice3BU
5561 case ssa.BoundsSlice3C:
5562 kind = ssa.BoundsSlice3CU
5563 }
5564 }
5565
5566 var cmp *ssa.Value
5567 if kind == ssa.BoundsIndex || kind == ssa.BoundsIndexU {
5568 cmp = s.newValue2(ssaop.OpIsInBounds, types.Types[types.TBOOL], idx, len)
5569 } else {
5570 cmp = s.newValue2(ssaop.OpIsSliceInBounds, types.Types[types.TBOOL], idx, len)
5571 }
5572 b := s.endBlock()
5573 b.Kind = block.BlockIf
5574 b.SetControl(cmp)
5575 b.Likely = ssa.BranchLikely
5576 b.AddEdgeTo(bNext)
5577 b.AddEdgeTo(bPanic)
5578
5579 s.startBlock(bPanic)
5580 if Arch.LinkArch.Family == sys.Wasm {
5581
5582
5583 s.rtcall(BoundsCheckFunc[kind], false, nil, idx, len)
5584 } else {
5585 mem := s.newValue3I(ssaop.OpPanicBounds, types.TypeMem, int64(kind), idx, len, s.mem())
5586 s.endBlock().SetControl(mem)
5587 }
5588 s.startBlock(bNext)
5589
5590
5591 if base.Flag.Cfg.SpectreIndex {
5592 op := ssaop.OpSpectreIndex
5593 if kind != ssa.BoundsIndex && kind != ssa.BoundsIndexU {
5594 op = ssaop.OpSpectreSliceIndex
5595 }
5596 idx = s.newValue2(op, types.Types[types.TINT], idx, len)
5597 }
5598
5599 return idx
5600 }
5601
5602
5603 func (s *state) check(cmp *ssa.Value, fn *obj.LSym) {
5604 b := s.endBlock()
5605 b.Kind = block.BlockIf
5606 b.SetControl(cmp)
5607 b.Likely = ssa.BranchLikely
5608 bNext := s.f.NewBlock(block.BlockPlain)
5609 line := s.peekPos()
5610 pos := base.Ctxt.PosTable.Pos(line)
5611 fl := funcLine{f: fn, base: pos.Base(), line: pos.Line()}
5612 bPanic := s.panics[fl]
5613 if bPanic == nil {
5614 bPanic = s.f.NewBlock(block.BlockPlain)
5615 s.panics[fl] = bPanic
5616 s.startBlock(bPanic)
5617
5618
5619 s.rtcall(fn, false, nil)
5620 }
5621 b.AddEdgeTo(bNext)
5622 b.AddEdgeTo(bPanic)
5623 s.startBlock(bNext)
5624 }
5625
5626 func (s *state) intDivide(n ir.Node, a, b *ssa.Value) *ssa.Value {
5627 needcheck := true
5628 switch b.Op {
5629 case ssaop.OpConst8, ssaop.OpConst16, ssaop.OpConst32, ssaop.OpConst64:
5630 if b.AuxInt != 0 {
5631 needcheck = false
5632 }
5633 }
5634 if needcheck {
5635
5636 cmp := s.newValue2(s.ssaOp(ir.ONE, n.Type()), types.Types[types.TBOOL], b, s.zeroVal(n.Type()))
5637 s.check(cmp, ir.Syms.Panicdivide)
5638 }
5639 return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
5640 }
5641
5642
5643
5644
5645
5646 func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args ...*ssa.Value) []*ssa.Value {
5647 s.prevCall = nil
5648
5649 off := base.Ctxt.Arch.FixedFrameSize
5650 var callArgs []*ssa.Value
5651 var callArgTypes []*types.Type
5652
5653 for _, arg := range args {
5654 t := arg.Type
5655 off = types.RoundUp(off, t.Alignment())
5656 size := t.Size()
5657 callArgs = append(callArgs, arg)
5658 callArgTypes = append(callArgTypes, t)
5659 off += size
5660 }
5661 off = types.RoundUp(off, int64(types.RegSize))
5662
5663
5664 var call *ssa.Value
5665 aux := ssa.StaticAuxCall(fn, s.f.ABIDefault.ABIAnalyzeTypes(callArgTypes, results))
5666 callArgs = append(callArgs, s.mem())
5667 call = s.newValue0A(ssaop.OpStaticLECall, aux.LateExpansionResultType(), aux)
5668 call.AddArgs(callArgs...)
5669 s.vars[memVar] = s.newValue1I(ssaop.OpSelectN, types.TypeMem, int64(len(results)), call)
5670
5671 if !returns {
5672
5673 b := s.endBlock()
5674 b.Kind = block.BlockExit
5675 b.SetControl(call)
5676 call.AuxInt = off - base.Ctxt.Arch.FixedFrameSize
5677 if len(results) > 0 {
5678 s.Fatalf("panic call can't have results")
5679 }
5680 return nil
5681 }
5682
5683
5684 res := make([]*ssa.Value, len(results))
5685 for i, t := range results {
5686 off = types.RoundUp(off, t.Alignment())
5687 res[i] = s.resultOfCall(call, int64(i), t)
5688 off += t.Size()
5689 }
5690 off = types.RoundUp(off, int64(types.PtrSize))
5691
5692
5693 call.AuxInt = off
5694
5695 return res
5696 }
5697
5698
5699 func (s *state) storeType(t *types.Type, left, right *ssa.Value, skip skipMask, leftIsStmt bool) {
5700 s.instrument(t, left, instrumentWrite)
5701
5702 if skip == 0 && (!t.HasPointers() || ssa.IsStackAddr(left)) {
5703
5704 s.vars[memVar] = s.newValue3Apos(ssaop.OpStore, types.TypeMem, t, left, right, s.mem(), leftIsStmt)
5705 return
5706 }
5707
5708
5709
5710
5711
5712
5713 s.storeTypeScalars(t, left, right, skip)
5714 if skip&skipPtr == 0 && t.HasPointers() {
5715 s.storeTypePtrs(t, left, right)
5716 }
5717 }
5718
5719
5720 func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip skipMask) {
5721 switch {
5722 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex() || t.IsSIMD():
5723 s.store(t, left, right)
5724 case t.IsPtrShaped():
5725 if t.IsPtr() && t.Elem().NotInHeap() {
5726 s.store(t, left, right)
5727 }
5728
5729 case t.IsString():
5730 if skip&skipLen != 0 {
5731 return
5732 }
5733 len := s.newValue1(ssaop.OpStringLen, types.Types[types.TINT], right)
5734 lenAddr := s.newValue1I(ssaop.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
5735 s.store(types.Types[types.TINT], lenAddr, len)
5736 case t.IsSlice():
5737 if skip&skipLen == 0 {
5738 len := s.newValue1(ssaop.OpSliceLen, types.Types[types.TINT], right)
5739 lenAddr := s.newValue1I(ssaop.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
5740 s.store(types.Types[types.TINT], lenAddr, len)
5741 }
5742 if skip&skipCap == 0 {
5743 cap := s.newValue1(ssaop.OpSliceCap, types.Types[types.TINT], right)
5744 capAddr := s.newValue1I(ssaop.OpOffPtr, s.f.Config.Types.IntPtr, 2*s.config.PtrSize, left)
5745 s.store(types.Types[types.TINT], capAddr, cap)
5746 }
5747 case t.IsInterface():
5748
5749 itab := s.newValue1(ssaop.OpITab, s.f.Config.Types.BytePtr, right)
5750 s.store(types.Types[types.TUINTPTR], left, itab)
5751 case isStructNotSIMD(t):
5752 n := t.NumFields()
5753 for i := 0; i < n; i++ {
5754 ft := t.FieldType(i)
5755 addr := s.newValue1I(ssaop.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
5756 val := s.newValue1I(ssaop.OpStructSelect, ft, int64(i), right)
5757 s.storeTypeScalars(ft, addr, val, 0)
5758 }
5759 case t.IsArray() && t.Size() == 0:
5760
5761 case t.IsArray() && t.NumElem() == 1:
5762 s.storeTypeScalars(t.Elem(), left, s.newValue1I(ssaop.OpArraySelect, t.Elem(), 0, right), 0)
5763 default:
5764 s.Fatalf("bad write barrier type %v", t)
5765 }
5766 }
5767
5768
5769 func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
5770 switch {
5771 case t.IsPtrShaped():
5772 if t.IsPtr() && t.Elem().NotInHeap() {
5773 break
5774 }
5775 s.store(t, left, right)
5776 case t.IsString():
5777 ptr := s.newValue1(ssaop.OpStringPtr, s.f.Config.Types.BytePtr, right)
5778 s.store(s.f.Config.Types.BytePtr, left, ptr)
5779 case t.IsSlice():
5780 elType := types.NewPtr(t.Elem())
5781 ptr := s.newValue1(ssaop.OpSlicePtr, elType, right)
5782 s.store(elType, left, ptr)
5783 case t.IsInterface():
5784
5785 idata := s.newValue1(ssaop.OpIData, s.f.Config.Types.BytePtr, right)
5786 idataAddr := s.newValue1I(ssaop.OpOffPtr, s.f.Config.Types.BytePtrPtr, s.config.PtrSize, left)
5787 s.store(s.f.Config.Types.BytePtr, idataAddr, idata)
5788 case isStructNotSIMD(t):
5789 n := t.NumFields()
5790 for i := 0; i < n; i++ {
5791 ft := t.FieldType(i)
5792 if !ft.HasPointers() {
5793 continue
5794 }
5795 addr := s.newValue1I(ssaop.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
5796 val := s.newValue1I(ssaop.OpStructSelect, ft, int64(i), right)
5797 s.storeTypePtrs(ft, addr, val)
5798 }
5799 case t.IsArray() && t.Size() == 0:
5800
5801 case t.IsArray() && t.NumElem() == 1:
5802 s.storeTypePtrs(t.Elem(), left, s.newValue1I(ssaop.OpArraySelect, t.Elem(), 0, right))
5803 default:
5804 s.Fatalf("bad write barrier type %v", t)
5805 }
5806 }
5807
5808
5809 func (s *state) putArg(n ir.Node, t *types.Type) *ssa.Value {
5810 var a *ssa.Value
5811 if !ssa.CanSSA(t) {
5812 a = s.newValue2(ssaop.OpDereference, t, s.addr(n), s.mem())
5813 } else {
5814 a = s.expr(n)
5815 }
5816 return a
5817 }
5818
5819
5820
5821
5822 func (s *state) slice(v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value) {
5823 t := v.Type
5824 var ptr, len, cap *ssa.Value
5825 switch {
5826 case t.IsSlice():
5827 ptr = s.newValue1(ssaop.OpSlicePtr, types.NewPtr(t.Elem()), v)
5828 len = s.newValue1(ssaop.OpSliceLen, types.Types[types.TINT], v)
5829 cap = s.newValue1(ssaop.OpSliceCap, types.Types[types.TINT], v)
5830 case t.IsString():
5831 ptr = s.newValue1(ssaop.OpStringPtr, types.NewPtr(types.Types[types.TUINT8]), v)
5832 len = s.newValue1(ssaop.OpStringLen, types.Types[types.TINT], v)
5833 cap = len
5834 case t.IsPtr():
5835 if !t.Elem().IsArray() {
5836 s.Fatalf("bad ptr to array in slice %v\n", t)
5837 }
5838 nv := s.nilCheck(v)
5839 ptr = s.newValue1(ssaop.OpCopy, types.NewPtr(t.Elem().Elem()), nv)
5840 len = s.constInt(types.Types[types.TINT], t.Elem().NumElem())
5841 cap = len
5842 default:
5843 s.Fatalf("bad type in slice %v\n", t)
5844 }
5845
5846
5847 if i == nil {
5848 i = s.constInt(types.Types[types.TINT], 0)
5849 }
5850 if j == nil {
5851 j = len
5852 }
5853 three := true
5854 if k == nil {
5855 three = false
5856 k = cap
5857 }
5858
5859
5860
5861
5862 if three {
5863 if k != cap {
5864 kind := ssa.BoundsSlice3Alen
5865 if t.IsSlice() {
5866 kind = ssa.BoundsSlice3Acap
5867 }
5868 k = s.boundsCheck(k, cap, kind, bounded)
5869 }
5870 if j != k {
5871 j = s.boundsCheck(j, k, ssa.BoundsSlice3B, bounded)
5872 }
5873 i = s.boundsCheck(i, j, ssa.BoundsSlice3C, bounded)
5874 } else {
5875 if j != k {
5876 kind := ssa.BoundsSliceAlen
5877 if t.IsSlice() {
5878 kind = ssa.BoundsSliceAcap
5879 }
5880 j = s.boundsCheck(j, k, kind, bounded)
5881 }
5882 i = s.boundsCheck(i, j, ssa.BoundsSliceB, bounded)
5883 }
5884
5885
5886 subOp := s.ssaOp(ir.OSUB, types.Types[types.TINT])
5887 mulOp := s.ssaOp(ir.OMUL, types.Types[types.TINT])
5888 andOp := s.ssaOp(ir.OAND, types.Types[types.TINT])
5889
5890
5891
5892
5893
5894 rlen := s.newValue2(subOp, types.Types[types.TINT], j, i)
5895 rcap := rlen
5896 if j != k && !t.IsString() {
5897 rcap = s.newValue2(subOp, types.Types[types.TINT], k, i)
5898 }
5899
5900 if (i.Op == ssaop.OpConst64 || i.Op == ssaop.OpConst32) && i.AuxInt == 0 {
5901
5902 return ptr, rlen, rcap
5903 }
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919 stride := s.constInt(types.Types[types.TINT], ptr.Type.Elem().Size())
5920
5921
5922 delta := s.newValue2(mulOp, types.Types[types.TINT], i, stride)
5923
5924
5925
5926 mask := s.newValue1(ssaop.OpSlicemask, types.Types[types.TINT], rcap)
5927 delta = s.newValue2(andOp, types.Types[types.TINT], delta, mask)
5928
5929
5930 rptr := s.newValue2(ssaop.OpAddPtr, ptr.Type, ptr, delta)
5931
5932 return rptr, rlen, rcap
5933 }
5934
5935 type u642fcvtTab struct {
5936 leq, cvt2F, and, rsh, or, add ssaop.Op
5937 one func(*state, *types.Type, int64) *ssa.Value
5938 }
5939
5940 var u64_f64 = u642fcvtTab{
5941 leq: ssaop.OpLeq64,
5942 cvt2F: ssaop.OpCvt64to64F,
5943 and: ssaop.OpAnd64,
5944 rsh: ssaop.OpRsh64Ux64,
5945 or: ssaop.OpOr64,
5946 add: ssaop.OpAdd64F,
5947 one: (*state).constInt64,
5948 }
5949
5950 var u64_f32 = u642fcvtTab{
5951 leq: ssaop.OpLeq64,
5952 cvt2F: ssaop.OpCvt64to32F,
5953 and: ssaop.OpAnd64,
5954 rsh: ssaop.OpRsh64Ux64,
5955 or: ssaop.OpOr64,
5956 add: ssaop.OpAdd32F,
5957 one: (*state).constInt64,
5958 }
5959
5960 func (s *state) uint64Tofloat64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5961 return s.uint64Tofloat(&u64_f64, n, x, ft, tt)
5962 }
5963
5964 func (s *state) uint64Tofloat32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5965 return s.uint64Tofloat(&u64_f32, n, x, ft, tt)
5966 }
5967
5968 func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994 cmp := s.newValue2(cvttab.leq, types.Types[types.TBOOL], s.zeroVal(ft), x)
5995
5996 b := s.endBlock()
5997 b.Kind = block.BlockIf
5998 b.SetControl(cmp)
5999 b.Likely = ssa.BranchLikely
6000
6001 bThen := s.f.NewBlock(block.BlockPlain)
6002 bElse := s.f.NewBlock(block.BlockPlain)
6003 bAfter := s.f.NewBlock(block.BlockPlain)
6004
6005 b.AddEdgeTo(bThen)
6006 s.startBlock(bThen)
6007 a0 := s.newValue1(cvttab.cvt2F, tt, x)
6008 s.vars[n] = a0
6009 s.endBlock()
6010 bThen.AddEdgeTo(bAfter)
6011
6012 b.AddEdgeTo(bElse)
6013 s.startBlock(bElse)
6014 one := cvttab.one(s, ft, 1)
6015 y := s.newValue2(cvttab.and, ft, x, one)
6016 z := s.newValue2(cvttab.rsh, ft, x, one)
6017 z = s.newValue2(cvttab.or, ft, z, y)
6018 a := s.newValue1(cvttab.cvt2F, tt, z)
6019 a1 := s.newValue2(cvttab.add, tt, a, a)
6020 s.vars[n] = a1
6021 s.endBlock()
6022 bElse.AddEdgeTo(bAfter)
6023
6024 s.startBlock(bAfter)
6025 return s.variable(n, n.Type())
6026 }
6027
6028 type u322fcvtTab struct {
6029 cvtI2F, cvtF2F ssaop.Op
6030 }
6031
6032 var u32_f64 = u322fcvtTab{
6033 cvtI2F: ssaop.OpCvt32to64F,
6034 cvtF2F: ssaop.OpCopy,
6035 }
6036
6037 var u32_f32 = u322fcvtTab{
6038 cvtI2F: ssaop.OpCvt32to32F,
6039 cvtF2F: ssaop.OpCvt64Fto32F,
6040 }
6041
6042 func (s *state) uint32Tofloat64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6043 return s.uint32Tofloat(&u32_f64, n, x, ft, tt)
6044 }
6045
6046 func (s *state) uint32Tofloat32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6047 return s.uint32Tofloat(&u32_f32, n, x, ft, tt)
6048 }
6049
6050 func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6051
6052
6053
6054
6055
6056 cmp := s.newValue2(ssaop.OpLeq32, types.Types[types.TBOOL], s.zeroVal(ft), x)
6057 b := s.endBlock()
6058 b.Kind = block.BlockIf
6059 b.SetControl(cmp)
6060 b.Likely = ssa.BranchLikely
6061
6062 bThen := s.f.NewBlock(block.BlockPlain)
6063 bElse := s.f.NewBlock(block.BlockPlain)
6064 bAfter := s.f.NewBlock(block.BlockPlain)
6065
6066 b.AddEdgeTo(bThen)
6067 s.startBlock(bThen)
6068 a0 := s.newValue1(cvttab.cvtI2F, tt, x)
6069 s.vars[n] = a0
6070 s.endBlock()
6071 bThen.AddEdgeTo(bAfter)
6072
6073 b.AddEdgeTo(bElse)
6074 s.startBlock(bElse)
6075 a1 := s.newValue1(ssaop.OpCvt32to64F, types.Types[types.TFLOAT64], x)
6076 twoToThe32 := s.constFloat64(types.Types[types.TFLOAT64], float64(1<<32))
6077 a2 := s.newValue2(ssaop.OpAdd64F, types.Types[types.TFLOAT64], a1, twoToThe32)
6078 a3 := s.newValue1(cvttab.cvtF2F, tt, a2)
6079
6080 s.vars[n] = a3
6081 s.endBlock()
6082 bElse.AddEdgeTo(bAfter)
6083
6084 s.startBlock(bAfter)
6085 return s.variable(n, n.Type())
6086 }
6087
6088
6089 func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
6090 if !n.X.Type().IsMap() && !n.X.Type().IsChan() {
6091 s.Fatalf("node must be a map or a channel")
6092 }
6093 if n.X.Type().IsChan() && n.Op() == ir.OLEN {
6094 s.Fatalf("cannot inline len(chan)")
6095 }
6096 if n.X.Type().IsChan() && n.Op() == ir.OCAP {
6097 s.Fatalf("cannot inline cap(chan)")
6098 }
6099 if n.X.Type().IsMap() && n.Op() == ir.OCAP {
6100 s.Fatalf("cannot inline cap(map)")
6101 }
6102
6103
6104
6105
6106
6107
6108
6109
6110 lenType := n.Type()
6111 nilValue := s.constNil(types.Types[types.TUINTPTR])
6112 cmp := s.newValue2(ssaop.OpEqPtr, types.Types[types.TBOOL], x, nilValue)
6113 b := s.endBlock()
6114 b.Kind = block.BlockIf
6115 b.SetControl(cmp)
6116 b.Likely = ssa.BranchUnlikely
6117
6118 bThen := s.f.NewBlock(block.BlockPlain)
6119 bElse := s.f.NewBlock(block.BlockPlain)
6120 bAfter := s.f.NewBlock(block.BlockPlain)
6121
6122
6123 b.AddEdgeTo(bThen)
6124 s.startBlock(bThen)
6125 s.vars[n] = s.zeroVal(lenType)
6126 s.endBlock()
6127 bThen.AddEdgeTo(bAfter)
6128
6129 b.AddEdgeTo(bElse)
6130 s.startBlock(bElse)
6131 switch n.Op() {
6132 case ir.OLEN:
6133 if n.X.Type().IsMap() {
6134
6135 loadType := reflectdata.MapType().Field(0).Type
6136 load := s.load(loadType, x)
6137 s.vars[n] = s.conv(nil, load, loadType, lenType)
6138 } else {
6139
6140 s.vars[n] = s.load(lenType, x)
6141 }
6142 case ir.OCAP:
6143
6144 sw := s.newValue1I(ssaop.OpOffPtr, lenType.PtrTo(), lenType.Size(), x)
6145 s.vars[n] = s.load(lenType, sw)
6146 default:
6147 s.Fatalf("op must be OLEN or OCAP")
6148 }
6149 s.endBlock()
6150 bElse.AddEdgeTo(bAfter)
6151
6152 s.startBlock(bAfter)
6153 return s.variable(n, lenType)
6154 }
6155
6156 type f2uCvtTab struct {
6157 ltf, cvt2U, subf, or ssaop.Op
6158 floatValue func(*state, *types.Type, float64) *ssa.Value
6159 intValue func(*state, *types.Type, int64) *ssa.Value
6160 cutoff uint64
6161 }
6162
6163 var f32_u64 = f2uCvtTab{
6164 ltf: ssaop.OpLess32F,
6165 cvt2U: ssaop.OpCvt32Fto64,
6166 subf: ssaop.OpSub32F,
6167 or: ssaop.OpOr64,
6168 floatValue: (*state).constFloat32,
6169 intValue: (*state).constInt64,
6170 cutoff: 1 << 63,
6171 }
6172
6173 var f64_u64 = f2uCvtTab{
6174 ltf: ssaop.OpLess64F,
6175 cvt2U: ssaop.OpCvt64Fto64,
6176 subf: ssaop.OpSub64F,
6177 or: ssaop.OpOr64,
6178 floatValue: (*state).constFloat64,
6179 intValue: (*state).constInt64,
6180 cutoff: 1 << 63,
6181 }
6182
6183 var f32_u32 = f2uCvtTab{
6184 ltf: ssaop.OpLess32F,
6185 cvt2U: ssaop.OpCvt32Fto32,
6186 subf: ssaop.OpSub32F,
6187 or: ssaop.OpOr32,
6188 floatValue: (*state).constFloat32,
6189 intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
6190 cutoff: 1 << 31,
6191 }
6192
6193 var f64_u32 = f2uCvtTab{
6194 ltf: ssaop.OpLess64F,
6195 cvt2U: ssaop.OpCvt64Fto32,
6196 subf: ssaop.OpSub64F,
6197 or: ssaop.OpOr32,
6198 floatValue: (*state).constFloat64,
6199 intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
6200 cutoff: 1 << 31,
6201 }
6202
6203 func (s *state) float32ToUint64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6204 return s.floatToUint(&f32_u64, n, x, ft, tt)
6205 }
6206 func (s *state) float64ToUint64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6207 return s.floatToUint(&f64_u64, n, x, ft, tt)
6208 }
6209
6210 func (s *state) float32ToUint32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6211 return s.floatToUint(&f32_u32, n, x, ft, tt)
6212 }
6213
6214 func (s *state) float64ToUint32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6215 return s.floatToUint(&f64_u32, n, x, ft, tt)
6216 }
6217
6218 func (s *state) floatToUint(cvttab *f2uCvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232 cutoff := cvttab.floatValue(s, ft, float64(cvttab.cutoff))
6233 cmp := s.newValueOrSfCall2(cvttab.ltf, types.Types[types.TBOOL], x, cutoff)
6234 b := s.endBlock()
6235 b.Kind = block.BlockIf
6236 b.SetControl(cmp)
6237 b.Likely = ssa.BranchLikely
6238
6239 var bThen, bZero *ssa.Block
6240
6241 newConversion := base.ConvertHash.MatchPosWithInfo(n.Pos(), "U", nil)
6242 if newConversion {
6243 bZero = s.f.NewBlock(block.BlockPlain)
6244 bThen = s.f.NewBlock(block.BlockIf)
6245 } else {
6246 bThen = s.f.NewBlock(block.BlockPlain)
6247 }
6248
6249 bElse := s.f.NewBlock(block.BlockPlain)
6250 bAfter := s.f.NewBlock(block.BlockPlain)
6251
6252 b.AddEdgeTo(bThen)
6253 s.startBlock(bThen)
6254 a0 := s.newValueOrSfCall1(cvttab.cvt2U, tt, x)
6255 s.vars[n] = a0
6256
6257 if newConversion {
6258 cmpz := s.newValueOrSfCall2(cvttab.ltf, types.Types[types.TBOOL], x, cvttab.floatValue(s, ft, 0.0))
6259 s.endBlock()
6260 bThen.SetControl(cmpz)
6261 bThen.AddEdgeTo(bZero)
6262 bThen.Likely = ssa.BranchUnlikely
6263 bThen.AddEdgeTo(bAfter)
6264
6265 s.startBlock(bZero)
6266 s.vars[n] = cvttab.intValue(s, tt, 0)
6267 s.endBlock()
6268 bZero.AddEdgeTo(bAfter)
6269 } else {
6270 s.endBlock()
6271 bThen.AddEdgeTo(bAfter)
6272 }
6273
6274 b.AddEdgeTo(bElse)
6275 s.startBlock(bElse)
6276 y := s.newValueOrSfCall2(cvttab.subf, ft, x, cutoff)
6277 y = s.newValueOrSfCall1(cvttab.cvt2U, tt, y)
6278 z := cvttab.intValue(s, tt, int64(-cvttab.cutoff))
6279 a1 := s.newValue2(cvttab.or, tt, y, z)
6280 s.vars[n] = a1
6281 s.endBlock()
6282 bElse.AddEdgeTo(bAfter)
6283
6284 s.startBlock(bAfter)
6285 return s.variable(n, n.Type())
6286 }
6287
6288
6289
6290
6291 func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
6292 iface := s.expr(n.X)
6293 target := s.reflectType(n.Type())
6294 var targetItab *ssa.Value
6295 if n.ITab != nil {
6296 targetItab = s.expr(n.ITab)
6297 }
6298
6299 if n.UseNilPanic {
6300 if commaok {
6301 base.Fatalf("unexpected *ir.TypeAssertExpr with UseNilPanic == true && commaok == true")
6302 }
6303 if n.Type().IsInterface() {
6304
6305
6306 base.Fatalf("unexpected *ir.TypeAssertExpr with UseNilPanic == true && Type().IsInterface() == true")
6307 }
6308 typs := s.f.Config.Types
6309 iface = s.newValue2(
6310 ssaop.OpIMake,
6311 iface.Type,
6312 s.nilCheck(s.newValue1(ssaop.OpITab, typs.BytePtr, iface)),
6313 s.newValue1(ssaop.OpIData, typs.BytePtr, iface),
6314 )
6315 }
6316
6317 return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, nil, target, targetItab, commaok, n.Descriptor)
6318 }
6319
6320 func (s *state) dynamicDottype(n *ir.DynamicTypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
6321 iface := s.expr(n.X)
6322 var source, target, targetItab *ssa.Value
6323 if n.SrcRType != nil {
6324 source = s.expr(n.SrcRType)
6325 }
6326 if !n.X.Type().IsEmptyInterface() && !n.Type().IsInterface() {
6327 byteptr := s.f.Config.Types.BytePtr
6328 targetItab = s.expr(n.ITab)
6329
6330
6331 target = s.load(byteptr, s.newValue1I(ssaop.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), targetItab))
6332 } else {
6333 target = s.expr(n.RType)
6334 }
6335 return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, source, target, targetItab, commaok, nil)
6336 }
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346 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) {
6347 typs := s.f.Config.Types
6348 byteptr := typs.BytePtr
6349 if dst.IsInterface() {
6350 if dst.IsEmptyInterface() {
6351
6352
6353 if base.Debug.TypeAssert > 0 {
6354 base.WarnfAt(pos, "type assertion inlined")
6355 }
6356
6357
6358 itab := s.newValue1(ssaop.OpITab, byteptr, iface)
6359
6360 cond := s.newValue2(ssaop.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6361
6362 if src.IsEmptyInterface() && commaok {
6363
6364 return iface, cond
6365 }
6366
6367
6368 b := s.endBlock()
6369 b.Kind = block.BlockIf
6370 b.SetControl(cond)
6371 b.Likely = ssa.BranchLikely
6372 bOk := s.f.NewBlock(block.BlockPlain)
6373 bFail := s.f.NewBlock(block.BlockPlain)
6374 b.AddEdgeTo(bOk)
6375 b.AddEdgeTo(bFail)
6376
6377 if !commaok {
6378
6379 s.startBlock(bFail)
6380 s.rtcall(ir.Syms.Panicnildottype, false, nil, target)
6381
6382
6383 s.startBlock(bOk)
6384 if src.IsEmptyInterface() {
6385 res = iface
6386 return
6387 }
6388
6389 off := s.newValue1I(ssaop.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab)
6390 typ := s.load(byteptr, off)
6391 idata := s.newValue1(ssaop.OpIData, byteptr, iface)
6392 res = s.newValue2(ssaop.OpIMake, dst, typ, idata)
6393 return
6394 }
6395
6396 s.startBlock(bOk)
6397
6398
6399 off := s.newValue1I(ssaop.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab)
6400 s.vars[typVar] = s.load(byteptr, off)
6401 s.endBlock()
6402
6403
6404 s.startBlock(bFail)
6405 s.vars[typVar] = itab
6406 s.endBlock()
6407
6408
6409 bEnd := s.f.NewBlock(block.BlockPlain)
6410 bOk.AddEdgeTo(bEnd)
6411 bFail.AddEdgeTo(bEnd)
6412 s.startBlock(bEnd)
6413 idata := s.newValue1(ssaop.OpIData, byteptr, iface)
6414 res = s.newValue2(ssaop.OpIMake, dst, s.variable(typVar, byteptr), idata)
6415 resok = cond
6416 delete(s.vars, typVar)
6417 return
6418 }
6419
6420 if base.Debug.TypeAssert > 0 {
6421 base.WarnfAt(pos, "type assertion not inlined")
6422 }
6423
6424 itab := s.newValue1(ssaop.OpITab, byteptr, iface)
6425 data := s.newValue1(ssaop.OpIData, types.Types[types.TUNSAFEPTR], iface)
6426
6427
6428 bNil := s.f.NewBlock(block.BlockPlain)
6429 bNonNil := s.f.NewBlock(block.BlockPlain)
6430 bMerge := s.f.NewBlock(block.BlockPlain)
6431 cond := s.newValue2(ssaop.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6432 b := s.endBlock()
6433 b.Kind = block.BlockIf
6434 b.SetControl(cond)
6435 b.Likely = ssa.BranchLikely
6436 b.AddEdgeTo(bNonNil)
6437 b.AddEdgeTo(bNil)
6438
6439 s.startBlock(bNil)
6440 if commaok {
6441 s.vars[typVar] = itab
6442 b := s.endBlock()
6443 b.AddEdgeTo(bMerge)
6444 } else {
6445
6446 s.rtcall(ir.Syms.Panicnildottype, false, nil, target)
6447 }
6448
6449
6450 s.startBlock(bNonNil)
6451 typ := itab
6452 if !src.IsEmptyInterface() {
6453 typ = s.load(byteptr, s.newValue1I(ssaop.OpOffPtr, byteptr, rttype.ITab.OffsetOf("Type"), itab))
6454 }
6455
6456
6457 var d *ssa.Value
6458 if descriptor != nil {
6459 d = s.newValue1A(ssaop.OpAddr, byteptr, descriptor, s.sb)
6460 if base.Flag.N == 0 && rtabi.UseInterfaceSwitchCache(Arch.LinkArch.Family) {
6461
6462
6463 if intrinsics.lookup(Arch.LinkArch.Arch, "internal/runtime/atomic", "Loadp") == nil {
6464 s.Fatalf("atomic load not available")
6465 }
6466
6467 var mul, and, add, zext ssaop.Op
6468 if s.config.PtrSize == 4 {
6469 mul = ssaop.OpMul32
6470 and = ssaop.OpAnd32
6471 add = ssaop.OpAdd32
6472 zext = ssaop.OpCopy
6473 } else {
6474 mul = ssaop.OpMul64
6475 and = ssaop.OpAnd64
6476 add = ssaop.OpAdd64
6477 zext = ssaop.OpZeroExt32to64
6478 }
6479
6480 loopHead := s.f.NewBlock(block.BlockPlain)
6481 loopBody := s.f.NewBlock(block.BlockPlain)
6482 cacheHit := s.f.NewBlock(block.BlockPlain)
6483 cacheMiss := s.f.NewBlock(block.BlockPlain)
6484
6485
6486
6487 atomicLoad := s.newValue2(ssaop.OpAtomicLoadPtr, types.NewTuple(typs.BytePtr, types.TypeMem), d, s.mem())
6488 cache := s.newValue1(ssaop.OpSelect0, typs.BytePtr, atomicLoad)
6489 s.vars[memVar] = s.newValue1(ssaop.OpSelect1, types.TypeMem, atomicLoad)
6490
6491
6492 var hash *ssa.Value
6493 if src.IsEmptyInterface() {
6494 hash = s.newValue2(ssaop.OpLoad, typs.UInt32, s.newValue1I(ssaop.OpOffPtr, typs.UInt32Ptr, rttype.Type.OffsetOf("Hash"), typ), s.mem())
6495 } else {
6496 hash = s.newValue2(ssaop.OpLoad, typs.UInt32, s.newValue1I(ssaop.OpOffPtr, typs.UInt32Ptr, rttype.ITab.OffsetOf("Hash"), itab), s.mem())
6497 }
6498 hash = s.newValue1(zext, typs.Uintptr, hash)
6499 s.vars[hashVar] = hash
6500
6501 mask := s.newValue2(ssaop.OpLoad, typs.Uintptr, cache, s.mem())
6502
6503 b := s.endBlock()
6504 b.AddEdgeTo(loopHead)
6505
6506
6507
6508 s.startBlock(loopHead)
6509 idx := s.newValue2(and, typs.Uintptr, s.variable(hashVar, typs.Uintptr), mask)
6510 idx = s.newValue2(mul, typs.Uintptr, idx, s.uintptrConstant(uint64(2*s.config.PtrSize)))
6511 idx = s.newValue2(add, typs.Uintptr, idx, s.uintptrConstant(uint64(s.config.PtrSize)))
6512 e := s.newValue2(ssaop.OpAddPtr, typs.UintptrPtr, cache, idx)
6513
6514 s.vars[hashVar] = s.newValue2(add, typs.Uintptr, s.variable(hashVar, typs.Uintptr), s.uintptrConstant(1))
6515
6516
6517
6518 eTyp := s.newValue2(ssaop.OpLoad, typs.Uintptr, e, s.mem())
6519 cmp1 := s.newValue2(ssaop.OpEqPtr, typs.Bool, typ, eTyp)
6520 b = s.endBlock()
6521 b.Kind = block.BlockIf
6522 b.SetControl(cmp1)
6523 b.AddEdgeTo(cacheHit)
6524 b.AddEdgeTo(loopBody)
6525
6526
6527
6528 s.startBlock(loopBody)
6529 cmp2 := s.newValue2(ssaop.OpEqPtr, typs.Bool, eTyp, s.constNil(typs.BytePtr))
6530 b = s.endBlock()
6531 b.Kind = block.BlockIf
6532 b.SetControl(cmp2)
6533 b.AddEdgeTo(cacheMiss)
6534 b.AddEdgeTo(loopHead)
6535
6536
6537
6538 s.startBlock(cacheHit)
6539 eItab := s.newValue2(ssaop.OpLoad, typs.BytePtr, s.newValue1I(ssaop.OpOffPtr, typs.BytePtrPtr, s.config.PtrSize, e), s.mem())
6540 s.vars[typVar] = eItab
6541 b = s.endBlock()
6542 b.AddEdgeTo(bMerge)
6543
6544
6545 s.startBlock(cacheMiss)
6546 }
6547 }
6548
6549
6550 if descriptor != nil {
6551 itab = s.rtcall(ir.Syms.TypeAssert, true, []*types.Type{byteptr}, d, typ)[0]
6552 } else {
6553 var fn *obj.LSym
6554 if commaok {
6555 fn = ir.Syms.AssertE2I2
6556 } else {
6557 fn = ir.Syms.AssertE2I
6558 }
6559 itab = s.rtcall(fn, true, []*types.Type{byteptr}, target, typ)[0]
6560 }
6561 s.vars[typVar] = itab
6562 b = s.endBlock()
6563 b.AddEdgeTo(bMerge)
6564
6565
6566 s.startBlock(bMerge)
6567 itab = s.variable(typVar, byteptr)
6568 var ok *ssa.Value
6569 if commaok {
6570 ok = s.newValue2(ssaop.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
6571 }
6572 return s.newValue2(ssaop.OpIMake, dst, itab, data), ok
6573 }
6574
6575 if base.Debug.TypeAssert > 0 {
6576 base.WarnfAt(pos, "type assertion inlined")
6577 }
6578
6579
6580 direct := types.IsDirectIface(dst)
6581 itab := s.newValue1(ssaop.OpITab, byteptr, iface)
6582 if base.Debug.TypeAssert > 0 {
6583 base.WarnfAt(pos, "type assertion inlined")
6584 }
6585 var wantedFirstWord *ssa.Value
6586 if src.IsEmptyInterface() {
6587
6588 wantedFirstWord = target
6589 } else {
6590
6591 wantedFirstWord = targetItab
6592 }
6593
6594 var tmp ir.Node
6595 var addr *ssa.Value
6596 if commaok && !ssa.CanSSA(dst) {
6597
6598
6599 tmp, addr = s.temp(pos, dst)
6600 }
6601
6602 cond := s.newValue2(ssaop.OpEqPtr, types.Types[types.TBOOL], itab, wantedFirstWord)
6603 b := s.endBlock()
6604 b.Kind = block.BlockIf
6605 b.SetControl(cond)
6606 b.Likely = ssa.BranchLikely
6607
6608 bOk := s.f.NewBlock(block.BlockPlain)
6609 bFail := s.f.NewBlock(block.BlockPlain)
6610 b.AddEdgeTo(bOk)
6611 b.AddEdgeTo(bFail)
6612
6613 if !commaok {
6614
6615 s.startBlock(bFail)
6616 taddr := source
6617 if taddr == nil {
6618 taddr = s.reflectType(src)
6619 }
6620 if src.IsEmptyInterface() {
6621 s.rtcall(ir.Syms.PanicdottypeE, false, nil, itab, target, taddr)
6622 } else {
6623 s.rtcall(ir.Syms.PanicdottypeI, false, nil, itab, target, taddr)
6624 }
6625
6626
6627 s.startBlock(bOk)
6628 if direct {
6629 return s.newValue1(ssaop.OpIData, dst, iface), nil
6630 }
6631 p := s.newValue1(ssaop.OpIData, types.NewPtr(dst), iface)
6632 return s.load(dst, p), nil
6633 }
6634
6635
6636
6637 bEnd := s.f.NewBlock(block.BlockPlain)
6638
6639
6640 valVar := ssaMarker("val")
6641
6642
6643 s.startBlock(bOk)
6644 if tmp == nil {
6645 if direct {
6646 s.vars[valVar] = s.newValue1(ssaop.OpIData, dst, iface)
6647 } else {
6648 p := s.newValue1(ssaop.OpIData, types.NewPtr(dst), iface)
6649 s.vars[valVar] = s.load(dst, p)
6650 }
6651 } else {
6652 p := s.newValue1(ssaop.OpIData, types.NewPtr(dst), iface)
6653 s.move(dst, addr, p)
6654 }
6655 s.vars[okVar] = s.constBool(true)
6656 s.endBlock()
6657 bOk.AddEdgeTo(bEnd)
6658
6659
6660 s.startBlock(bFail)
6661 if tmp == nil {
6662 s.vars[valVar] = s.zeroVal(dst)
6663 } else {
6664 s.zero(dst, addr)
6665 }
6666 s.vars[okVar] = s.constBool(false)
6667 s.endBlock()
6668 bFail.AddEdgeTo(bEnd)
6669
6670
6671 s.startBlock(bEnd)
6672 if tmp == nil {
6673 res = s.variable(valVar, dst)
6674 delete(s.vars, valVar)
6675 } else {
6676 res = s.load(dst, addr)
6677 }
6678 resok = s.variable(okVar, types.Types[types.TBOOL])
6679 delete(s.vars, okVar)
6680 return res, resok
6681 }
6682
6683
6684 func (s *state) temp(pos src.XPos, t *types.Type) (*ir.Name, *ssa.Value) {
6685 tmp := typecheck.TempAt(pos, s.curfn, t)
6686 if ssa.CanSSA(t) {
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698 tmp.SetAddrtaken(true)
6699 }
6700 if t.HasPointers() || (ssa.IsMergeCandidate(tmp) && t != deferstruct()) {
6701 s.vars[memVar] = s.newValue1A(ssaop.OpVarDef, types.TypeMem, tmp, s.mem())
6702 }
6703 addr := s.addr(tmp)
6704 return tmp, addr
6705 }
6706
6707
6708 func (s *state) variable(n ir.Node, t *types.Type) *ssa.Value {
6709 v := s.vars[n]
6710 if v != nil {
6711 return v
6712 }
6713 v = s.fwdVars[n]
6714 if v != nil {
6715 return v
6716 }
6717
6718 if s.curBlock == s.f.Entry {
6719
6720 s.f.Fatalf("value %v (%v) incorrectly live at entry", n, v)
6721 }
6722
6723
6724 v = s.newValue0A(ssaop.OpFwdRef, t, fwdRefAux{N: n})
6725 s.fwdVars[n] = v
6726 if n.Op() == ir.ONAME {
6727 s.addNamedValue(n.(*ir.Name), v)
6728 }
6729 return v
6730 }
6731
6732 func (s *state) mem() *ssa.Value {
6733 return s.variable(memVar, types.TypeMem)
6734 }
6735
6736 func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) {
6737 if n.Class == ir.Pxxx {
6738
6739 return
6740 }
6741 if ir.IsAutoTmp(n) {
6742
6743 return
6744 }
6745 if n.Class == ir.PPARAMOUT {
6746
6747
6748 return
6749 }
6750 loc := ssa.LocalSlot{N: n, Type: n.Type(), Off: 0}
6751 values, ok := s.f.NamedValues[loc]
6752 if !ok {
6753 s.f.Names = append(s.f.Names, loc)
6754 }
6755 s.f.NamedValues[loc] = append(values, v)
6756 }
6757
6758
6759 type Branch struct {
6760 P *obj.Prog
6761 B *ssa.Block
6762 }
6763
6764
6765 type State struct {
6766 ABI obj.ABI
6767
6768 pp *objw.Progs
6769
6770
6771
6772 Branches []Branch
6773
6774
6775 JumpTables []*ssa.Block
6776
6777
6778 bstart []*obj.Prog
6779
6780 maxarg int64
6781
6782
6783
6784 livenessMap liveness.Map
6785
6786
6787
6788 partLiveArgs map[*ir.Name]bool
6789
6790
6791
6792
6793 lineRunStart *obj.Prog
6794
6795
6796 OnWasmStackSkipped int
6797 }
6798
6799 func (s *State) FuncInfo() *obj.FuncInfo {
6800 return s.pp.CurFunc.LSym.Func()
6801 }
6802
6803
6804 func (s *State) Prog(as obj.As) *obj.Prog {
6805 p := s.pp.Prog(as)
6806 if objw.LosesStmtMark(as) {
6807 return p
6808 }
6809
6810
6811 if s.lineRunStart == nil || s.lineRunStart.Pos.Line() != p.Pos.Line() {
6812 s.lineRunStart = p
6813 } else if p.Pos.IsStmt() == src.PosIsStmt {
6814 s.lineRunStart.Pos = s.lineRunStart.Pos.WithIsStmt()
6815 p.Pos = p.Pos.WithNotStmt()
6816 }
6817 return p
6818 }
6819
6820
6821 func (s *State) Pc() *obj.Prog {
6822 return s.pp.Next
6823 }
6824
6825
6826 func (s *State) SetPos(pos src.XPos) {
6827 s.pp.Pos = pos
6828 }
6829
6830
6831
6832
6833 func (s *State) Br(op obj.As, target *ssa.Block) *obj.Prog {
6834 p := s.Prog(op)
6835 p.To.Type = obj.TYPE_BRANCH
6836 s.Branches = append(s.Branches, Branch{P: p, B: target})
6837 return p
6838 }
6839
6840
6841
6842
6843
6844
6845 func (s *State) DebugFriendlySetPosFrom(v *ssa.Value) {
6846 switch v.Op {
6847 case ssaop.OpPhi, ssaop.OpCopy, ssaop.OpLoadReg, ssaop.OpStoreReg:
6848
6849 s.SetPos(v.Pos.WithNotStmt())
6850 default:
6851 p := v.Pos
6852 if p != src.NoXPos {
6853
6854
6855
6856
6857 if p.IsStmt() != src.PosIsStmt {
6858 if s.pp.Pos.IsStmt() == src.PosIsStmt && s.pp.Pos.SameFileAndLine(p) {
6859
6860
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872 return
6873 }
6874 p = p.WithNotStmt()
6875
6876 }
6877 s.SetPos(p)
6878 } else {
6879 s.SetPos(s.pp.Pos.WithNotStmt())
6880 }
6881 }
6882 }
6883
6884
6885 func emitArgInfo(e *ssafn, f *ssa.Func, pp *objw.Progs) {
6886 ft := e.curfn.Type()
6887 if ft.NumRecvs() == 0 && ft.NumParams() == 0 {
6888 return
6889 }
6890
6891 x := EmitArgInfo(e.curfn, f.OwnAux.ABIInfo())
6892 x.Set(obj.AttrContentAddressable, true)
6893 e.curfn.LSym.Func().ArgInfo = x
6894
6895
6896 p := pp.Prog(obj.AFUNCDATA)
6897 p.From.SetConst(rtabi.FUNCDATA_ArgInfo)
6898 p.To.Type = obj.TYPE_MEM
6899 p.To.Name = obj.NAME_EXTERN
6900 p.To.Sym = x
6901 }
6902
6903
6904 func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
6905 x := base.Ctxt.Lookup(fmt.Sprintf("%s.arginfo%d", f.LSym.Name, f.ABI))
6906 x.Align = 1
6907
6908
6909
6910
6911 PtrSize := int64(types.PtrSize)
6912 uintptrTyp := types.Types[types.TUINTPTR]
6913
6914 isAggregate := func(t *types.Type) bool {
6915 return isStructNotSIMD(t) || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice()
6916 }
6917
6918 wOff := 0
6919 n := 0
6920 writebyte := func(o uint8) { wOff = objw.Uint8(x, wOff, o) }
6921
6922
6923 write1 := func(sz, offset int64) {
6924 if offset >= rtabi.TraceArgsSpecial {
6925 writebyte(rtabi.TraceArgsOffsetTooLarge)
6926 } else {
6927 writebyte(uint8(offset))
6928 writebyte(uint8(sz))
6929 }
6930 n++
6931 }
6932
6933
6934
6935 var visitType func(baseOffset int64, t *types.Type, depth int) bool
6936 visitType = func(baseOffset int64, t *types.Type, depth int) bool {
6937 if n >= rtabi.TraceArgsLimit {
6938 writebyte(rtabi.TraceArgsDotdotdot)
6939 return false
6940 }
6941 if !isAggregate(t) {
6942 write1(t.Size(), baseOffset)
6943 return true
6944 }
6945 writebyte(rtabi.TraceArgsStartAgg)
6946 depth++
6947 if depth >= rtabi.TraceArgsMaxDepth {
6948 writebyte(rtabi.TraceArgsDotdotdot)
6949 writebyte(rtabi.TraceArgsEndAgg)
6950 n++
6951 return true
6952 }
6953 switch {
6954 case t.IsInterface(), t.IsString():
6955 _ = visitType(baseOffset, uintptrTyp, depth) &&
6956 visitType(baseOffset+PtrSize, uintptrTyp, depth)
6957 case t.IsSlice():
6958 _ = visitType(baseOffset, uintptrTyp, depth) &&
6959 visitType(baseOffset+PtrSize, uintptrTyp, depth) &&
6960 visitType(baseOffset+PtrSize*2, uintptrTyp, depth)
6961 case t.IsComplex():
6962 _ = visitType(baseOffset, types.FloatForComplex(t), depth) &&
6963 visitType(baseOffset+t.Size()/2, types.FloatForComplex(t), depth)
6964 case t.IsArray():
6965 if t.NumElem() == 0 {
6966 n++
6967 break
6968 }
6969 for i := int64(0); i < t.NumElem(); i++ {
6970 if !visitType(baseOffset, t.Elem(), depth) {
6971 break
6972 }
6973 baseOffset += t.Elem().Size()
6974 }
6975 case isStructNotSIMD(t):
6976 if t.NumFields() == 0 {
6977 n++
6978 break
6979 }
6980 for _, field := range t.Fields() {
6981 if !visitType(baseOffset+field.Offset, field.Type, depth) {
6982 break
6983 }
6984 }
6985 }
6986 writebyte(rtabi.TraceArgsEndAgg)
6987 return true
6988 }
6989
6990 start := 0
6991 if strings.Contains(f.LSym.Name, "[") {
6992
6993 start = 1
6994 }
6995
6996 for _, a := range abiInfo.InParams()[start:] {
6997 if !visitType(a.FrameOffset(abiInfo), a.Type, 0) {
6998 break
6999 }
7000 }
7001 writebyte(rtabi.TraceArgsEndSeq)
7002 if wOff > rtabi.TraceArgsMaxLen {
7003 base.Fatalf("ArgInfo too large")
7004 }
7005
7006 return x
7007 }
7008
7009
7010 func emitWrappedFuncInfo(e *ssafn, pp *objw.Progs) {
7011 if base.Ctxt.Flag_linkshared {
7012
7013
7014 return
7015 }
7016
7017 wfn := e.curfn.WrappedFunc
7018 if wfn == nil {
7019 return
7020 }
7021
7022 wsym := wfn.Linksym()
7023 x := base.Ctxt.LookupInit(fmt.Sprintf("%s.wrapinfo", wsym.Name), func(x *obj.LSym) {
7024 objw.SymPtrOff(x, 0, wsym)
7025 x.Set(obj.AttrContentAddressable, true)
7026 x.Align = 4
7027 })
7028 e.curfn.LSym.Func().WrapInfo = x
7029
7030
7031 p := pp.Prog(obj.AFUNCDATA)
7032 p.From.SetConst(rtabi.FUNCDATA_WrapInfo)
7033 p.To.Type = obj.TYPE_MEM
7034 p.To.Name = obj.NAME_EXTERN
7035 p.To.Sym = x
7036 }
7037
7038
7039 func genssa(htmlWriter ssa.HTMLWriter, f *ssa.Func, pp *objw.Progs) {
7040 var s State
7041 s.ABI = f.OwnAux.Fn.ABI()
7042
7043 e := f.Frontend().(*ssafn)
7044
7045 gatherPrintInfo := f.PrintOrHtmlSSA || ssaconfig.GenssaDump[f.Name]
7046
7047 var lv *liveness.Liveness
7048 s.livenessMap, s.partLiveArgs, lv = liveness.Compute(e.curfn, f, e.stkptrsize, pp, gatherPrintInfo)
7049 emitArgInfo(e, f, pp)
7050 argLiveBlockMap, argLiveValueMap := liveness.ArgLiveness(e.curfn, f, pp)
7051
7052 openDeferInfo := e.curfn.LSym.Func().OpenCodedDeferInfo
7053 if openDeferInfo != nil {
7054
7055
7056 p := pp.Prog(obj.AFUNCDATA)
7057 p.From.SetConst(rtabi.FUNCDATA_OpenCodedDeferInfo)
7058 p.To.Type = obj.TYPE_MEM
7059 p.To.Name = obj.NAME_EXTERN
7060 p.To.Sym = openDeferInfo
7061 }
7062
7063 emitWrappedFuncInfo(e, pp)
7064
7065
7066 s.bstart = make([]*obj.Prog, f.NumBlocks())
7067 s.pp = pp
7068 var progToValue map[*obj.Prog]*ssa.Value
7069 var progToBlock map[*obj.Prog]*ssa.Block
7070 var valueToProgAfter []*obj.Prog
7071 if gatherPrintInfo {
7072 progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
7073 progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
7074 f.Logf("genssa %s\n", f.Name)
7075 progToBlock[s.pp.Next] = f.Blocks[0]
7076 }
7077
7078 if base.Ctxt.Flag_locationlists {
7079 if cap(f.Cache.ValueToProgAfter) < f.NumValues() {
7080 f.Cache.ValueToProgAfter = make([]*obj.Prog, f.NumValues())
7081 }
7082 valueToProgAfter = f.Cache.ValueToProgAfter[:f.NumValues()]
7083 clear(valueToProgAfter)
7084 }
7085
7086
7087
7088 firstPos := src.NoXPos
7089 for _, v := range f.Entry.Values {
7090 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 {
7091 firstPos = v.Pos
7092 v.Pos = firstPos.WithDefaultStmt()
7093 break
7094 }
7095 }
7096
7097
7098
7099
7100 var inlMarks map[*obj.Prog]int32
7101 var inlMarkList []*obj.Prog
7102
7103
7104
7105 var inlMarksByPos map[src.XPos][]*obj.Prog
7106
7107 var argLiveIdx int = -1
7108
7109
7110
7111
7112
7113 var hotAlign, hotRequire int64
7114
7115 if base.Debug.AlignHot > 0 {
7116 switch base.Ctxt.Arch.Name {
7117
7118
7119
7120
7121
7122 case "amd64", "386":
7123
7124
7125
7126 hotAlign = 64
7127 hotRequire = 31
7128 }
7129 }
7130
7131
7132 for i, b := range f.Blocks {
7133
7134 s.lineRunStart = nil
7135 s.SetPos(s.pp.Pos.WithNotStmt())
7136
7137 if hotAlign > 0 && b.Hotness&ssa.HotPgoInitial == ssa.HotPgoInitial {
7138
7139
7140
7141
7142
7143 p := s.pp.Prog(obj.APCALIGNMAX)
7144 p.From.SetConst(hotAlign)
7145 p.To.SetConst(hotRequire)
7146 }
7147
7148 s.bstart[b.ID] = s.pp.Next
7149
7150 if idx, ok := argLiveBlockMap[b.ID]; ok && idx != argLiveIdx {
7151 argLiveIdx = idx
7152 p := s.pp.Prog(obj.APCDATA)
7153 p.From.SetConst(rtabi.PCDATA_ArgLiveIndex)
7154 p.To.SetConst(int64(idx))
7155 }
7156
7157
7158 Arch.SSAMarkMoves(&s, b)
7159 for _, v := range b.Values {
7160 x := s.pp.Next
7161 s.DebugFriendlySetPosFrom(v)
7162
7163 if v.Op.ResultInArg0() && v.ResultReg() != v.Args[0].Reg() {
7164 v.Fatalf("input[0] and output not in same register %s", v.LongString())
7165 }
7166
7167 switch v.Op {
7168 case ssaop.OpInitMem:
7169
7170 case ssaop.OpArg:
7171
7172 case ssaop.OpSP, ssaop.OpSB:
7173
7174 case ssaop.OpSelect0, ssaop.OpSelect1, ssaop.OpSelectN, ssaop.OpMakeResult:
7175
7176 case ssaop.OpGetG:
7177
7178
7179 case ssaop.OpVarDef, ssaop.OpVarLive, ssaop.OpKeepAlive, ssaop.OpWBend:
7180
7181 case ssaop.OpPhi:
7182 CheckLoweredPhi(v)
7183 case ssaop.OpConvert:
7184
7185 if v.Args[0].Reg() != v.Reg() {
7186 v.Fatalf("OpConvert should be a no-op: %s; %s", v.Args[0].LongString(), v.LongString())
7187 }
7188 case ssaop.OpInlMark:
7189 p := Arch.Ginsnop(s.pp)
7190 if inlMarks == nil {
7191 inlMarks = map[*obj.Prog]int32{}
7192 inlMarksByPos = map[src.XPos][]*obj.Prog{}
7193 }
7194 inlMarks[p] = v.AuxInt32()
7195 inlMarkList = append(inlMarkList, p)
7196 pos := v.Pos.AtColumn1()
7197 inlMarksByPos[pos] = append(inlMarksByPos[pos], p)
7198 firstPos = src.NoXPos
7199
7200 default:
7201
7202 if firstPos != src.NoXPos && v.Op != ssaop.OpArgIntReg && v.Op != ssaop.OpArgFloatReg && v.Op != ssaop.OpLoadReg && v.Op != ssaop.OpStoreReg {
7203 s.SetPos(firstPos)
7204 firstPos = src.NoXPos
7205 }
7206
7207
7208 s.pp.NextLive = s.livenessMap.Get(v)
7209 s.pp.NextUnsafe = s.livenessMap.GetUnsafe(v)
7210
7211
7212 Arch.SSAGenValue(&s, v)
7213 }
7214
7215 if idx, ok := argLiveValueMap[v.ID]; ok && idx != argLiveIdx {
7216 argLiveIdx = idx
7217 p := s.pp.Prog(obj.APCDATA)
7218 p.From.SetConst(rtabi.PCDATA_ArgLiveIndex)
7219 p.To.SetConst(int64(idx))
7220 }
7221
7222 if base.Ctxt.Flag_locationlists {
7223 valueToProgAfter[v.ID] = s.pp.Next
7224 }
7225
7226 if gatherPrintInfo {
7227 for ; x != s.pp.Next; x = x.Link {
7228 progToValue[x] = v
7229 }
7230 }
7231 }
7232
7233 if s.bstart[b.ID] == s.pp.Next && len(b.Succs) == 1 && b.Succs[0].Block() == b {
7234 p := Arch.Ginsnop(s.pp)
7235 p.Pos = p.Pos.WithIsStmt()
7236 if b.Pos == src.NoXPos {
7237 b.Pos = p.Pos
7238 if b.Pos == src.NoXPos {
7239 b.Pos = s.pp.Text.Pos
7240 }
7241 }
7242 b.Pos = b.Pos.WithBogusLine()
7243 }
7244
7245
7246
7247
7248
7249 s.pp.NextUnsafe = s.livenessMap.GetUnsafeBlock(b)
7250
7251
7252 var next *ssa.Block
7253 if i < len(f.Blocks)-1 && base.Flag.N == 0 {
7254
7255
7256
7257
7258 next = f.Blocks[i+1]
7259 }
7260 x := s.pp.Next
7261 s.SetPos(b.Pos)
7262 Arch.SSAGenBlock(&s, b, next)
7263 if gatherPrintInfo {
7264 for ; x != s.pp.Next; x = x.Link {
7265 progToBlock[x] = b
7266 }
7267 }
7268 }
7269 if f.Blocks[len(f.Blocks)-1].Kind == block.BlockExit {
7270
7271
7272
7273
7274 Arch.Ginsnop(s.pp)
7275 }
7276 if openDeferInfo != nil {
7277
7278
7279
7280
7281
7282
7283
7284
7285 s.pp.NextLive = s.livenessMap.DeferReturn
7286 p := s.pp.Prog(obj.ACALL)
7287 p.To.Type = obj.TYPE_MEM
7288 p.To.Name = obj.NAME_EXTERN
7289 p.To.Sym = ir.Syms.Deferreturn
7290
7291
7292
7293
7294
7295 for _, o := range f.OwnAux.ABIInfo().OutParams() {
7296 n := o.Name
7297 rts, offs := o.RegisterTypesAndOffsets()
7298 for i := range o.Registers {
7299 Arch.LoadRegResult(&s, f, rts[i], ssa.ObjRegForAbiReg(o.Registers[i], f.Config), n, offs[i])
7300 }
7301 }
7302
7303 s.pp.Prog(obj.ARET)
7304 }
7305
7306 if inlMarks != nil {
7307 hasCall := false
7308
7309
7310
7311
7312 for p := s.pp.Text; p != nil; p = p.Link {
7313 if p.As == obj.ANOP || p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT ||
7314 p.As == obj.APCALIGN || p.As == obj.APCALIGNMAX || Arch.LinkArch.Family == sys.Wasm {
7315
7316
7317
7318
7319
7320 continue
7321 }
7322 if _, ok := inlMarks[p]; ok {
7323
7324
7325 continue
7326 }
7327 if p.As == obj.ACALL || p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
7328 hasCall = true
7329 }
7330 pos := p.Pos.AtColumn1()
7331 marks := inlMarksByPos[pos]
7332 if len(marks) == 0 {
7333 continue
7334 }
7335 for _, m := range marks {
7336
7337
7338
7339 p.Pos = p.Pos.WithIsStmt()
7340 s.pp.CurFunc.LSym.Func().AddInlMark(p, inlMarks[m])
7341
7342 m.As = obj.ANOP
7343 m.Pos = src.NoXPos
7344 m.From = obj.Addr{}
7345 m.To = obj.Addr{}
7346 }
7347 delete(inlMarksByPos, pos)
7348 }
7349
7350 for _, p := range inlMarkList {
7351 if p.As != obj.ANOP {
7352 s.pp.CurFunc.LSym.Func().AddInlMark(p, inlMarks[p])
7353 }
7354 }
7355
7356 if e.stksize == 0 && !hasCall {
7357
7358
7359
7360
7361
7362
7363 for p := s.pp.Text; p != nil; p = p.Link {
7364 if p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT || p.As == obj.ANOP {
7365 continue
7366 }
7367 if base.Ctxt.PosTable.Pos(p.Pos).Base().InliningIndex() >= 0 {
7368
7369 nop := Arch.Ginsnop(s.pp)
7370 nop.Pos = e.curfn.Pos().WithIsStmt()
7371
7372
7373
7374
7375
7376 for x := s.pp.Text; x != nil; x = x.Link {
7377 if x.Link == nop {
7378 x.Link = nop.Link
7379 break
7380 }
7381 }
7382
7383 for x := s.pp.Text; x != nil; x = x.Link {
7384 if x.Link == p {
7385 nop.Link = p
7386 x.Link = nop
7387 break
7388 }
7389 }
7390 }
7391 break
7392 }
7393 }
7394 }
7395
7396 if base.Ctxt.Flag_locationlists {
7397 var debugInfo *ssadebug.FuncDebug
7398 debugInfo = e.curfn.DebugInfo.(*ssadebug.FuncDebug)
7399
7400
7401 debugInfo.EntryID = f.Entry.ID
7402 if e.curfn.ABI == obj.ABIInternal && base.Flag.N != 0 {
7403 ssadebug.BuildFuncDebugNoOptimized(base.Ctxt, f, base.Debug.LocationLists > 1, StackOffset, debugInfo)
7404 } else {
7405 ssadebug.BuildFuncDebug(base.Ctxt, f, base.Debug.LocationLists, StackOffset, debugInfo)
7406 }
7407 bstart := s.bstart
7408 idToIdx := make([]int, f.NumBlocks())
7409 for i, b := range f.Blocks {
7410 idToIdx[b.ID] = i
7411 }
7412
7413
7414
7415 debugInfo.GetPC = func(b, v ssa.ID) int64 {
7416 switch v {
7417 case ssa.BlockStart.ID:
7418 if b == f.Entry.ID {
7419 return 0
7420
7421 }
7422 return bstart[b].Pc
7423 case ssa.BlockEnd.ID:
7424 blk := f.Blocks[idToIdx[b]]
7425 nv := len(blk.Values)
7426 return valueToProgAfter[blk.Values[nv-1].ID].Pc
7427 case ssa.FuncEnd.ID:
7428 return e.curfn.LSym.Size
7429 default:
7430 return valueToProgAfter[v].Pc
7431 }
7432 }
7433 }
7434
7435
7436 for _, br := range s.Branches {
7437 br.P.To.SetTarget(s.bstart[br.B.ID])
7438 if br.P.Pos.IsStmt() != src.PosIsStmt {
7439 br.P.Pos = br.P.Pos.WithNotStmt()
7440 } else if v0 := br.B.FirstPossibleStmtValue(); v0 != nil && v0.Pos.Line() == br.P.Pos.Line() && v0.Pos.IsStmt() == src.PosIsStmt {
7441 br.P.Pos = br.P.Pos.WithNotStmt()
7442 }
7443
7444 }
7445
7446
7447 for _, jt := range s.JumpTables {
7448
7449 targets := make([]*obj.Prog, len(jt.Succs))
7450 for i, e := range jt.Succs {
7451 targets[i] = s.bstart[e.Block().ID]
7452 }
7453
7454
7455
7456 fi := s.pp.CurFunc.LSym.Func()
7457 fi.JumpTables = append(fi.JumpTables, obj.JumpTable{Sym: jt.Aux.(*obj.LSym), Targets: targets})
7458 }
7459
7460
7461
7462
7463
7464
7465
7466
7467 defframe(&s, e, f)
7468 if Arch.SSAGenFinish != nil {
7469 Arch.SSAGenFinish(s.pp)
7470 }
7471
7472 if e.log {
7473 filename := ""
7474 for p := s.pp.Text; p != nil; p = p.Link {
7475 if p.Pos.IsKnown() && p.InnermostFilename() != filename {
7476 filename = p.InnermostFilename()
7477 f.Logf("# %s\n", filename)
7478 }
7479
7480 var s string
7481 if v, ok := progToValue[p]; ok {
7482 s = v.String()
7483 } else if b, ok := progToBlock[p]; ok {
7484 s = b.String()
7485 } else {
7486 s = " "
7487 }
7488 f.Logf(" %-6s\t%.5d (%s)\t%s\n", s, p.Pc, p.InnermostLineNumber(), p.InstructionString())
7489 }
7490 }
7491 if htmlWriter.Enabled() {
7492 var buf strings.Builder
7493 buf.WriteString("<code>")
7494 buf.WriteString("<dl class=\"ssa-gen\">")
7495 filename := ""
7496
7497 liveness := lv.Format(nil)
7498 if liveness != "" {
7499 buf.WriteString("<dt class=\"ssa-prog-src\"></dt><dd class=\"ssa-prog\">")
7500 buf.WriteString(html.EscapeString("# " + liveness))
7501 buf.WriteString("</dd>")
7502 }
7503
7504 for p := s.pp.Text; p != nil; p = p.Link {
7505
7506
7507 if p.Pos.IsKnown() && p.InnermostFilename() != filename {
7508 filename = p.InnermostFilename()
7509 buf.WriteString("<dt class=\"ssa-prog-src\"></dt><dd class=\"ssa-prog\">")
7510 buf.WriteString(html.EscapeString("# " + filename))
7511 buf.WriteString("</dd>")
7512 }
7513
7514 buf.WriteString("<dt class=\"ssa-prog-src\">")
7515 if v, ok := progToValue[p]; ok {
7516
7517
7518 if p.As != obj.APCDATA {
7519 if liveness := lv.Format(v); liveness != "" {
7520
7521 buf.WriteString("</dt><dd class=\"ssa-prog\">")
7522 buf.WriteString(html.EscapeString("# " + liveness))
7523 buf.WriteString("</dd>")
7524
7525 buf.WriteString("<dt class=\"ssa-prog-src\">")
7526 }
7527 }
7528
7529 buf.WriteString(v.HTML())
7530 } else if b, ok := progToBlock[p]; ok {
7531 buf.WriteString("<b>" + b.HTML() + "</b>")
7532 }
7533 buf.WriteString("</dt>")
7534 buf.WriteString("<dd class=\"ssa-prog\">")
7535 fmt.Fprintf(&buf, "%.5d <span class=\"l%v line-number\">(%s)</span> %s", p.Pc, p.InnermostLineNumber(), p.InnermostLineNumberHTML(), html.EscapeString(p.InstructionString()))
7536 buf.WriteString("</dd>")
7537 }
7538 buf.WriteString("</dl>")
7539 buf.WriteString("</code>")
7540 htmlWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String())
7541 }
7542 if ssaconfig.GenssaDump[f.Name] {
7543 fi := f.DumpFileForPhase("genssa")
7544 if fi != nil {
7545
7546
7547 inliningDiffers := func(a, b []src.Pos) bool {
7548 if len(a) != len(b) {
7549 return true
7550 }
7551 for i := range a {
7552 if a[i].Filename() != b[i].Filename() {
7553 return true
7554 }
7555 if i != len(a)-1 && a[i].Line() != b[i].Line() {
7556 return true
7557 }
7558 }
7559 return false
7560 }
7561
7562 var allPosOld []src.Pos
7563 var allPos []src.Pos
7564
7565 for p := s.pp.Text; p != nil; p = p.Link {
7566 if p.Pos.IsKnown() {
7567 allPos = allPos[:0]
7568 p.Ctxt.AllPos(p.Pos, func(pos src.Pos) { allPos = append(allPos, pos) })
7569 if inliningDiffers(allPos, allPosOld) {
7570 for _, pos := range allPos {
7571 fmt.Fprintf(fi, "# %s:%d\n", pos.Filename(), pos.Line())
7572 }
7573 allPos, allPosOld = allPosOld, allPos
7574 }
7575 }
7576
7577 var s string
7578 if v, ok := progToValue[p]; ok {
7579 s = v.String()
7580 } else if b, ok := progToBlock[p]; ok {
7581 s = b.String()
7582 } else {
7583 s = " "
7584 }
7585 fmt.Fprintf(fi, " %-6s\t%.5d %s\t%s\n", s, p.Pc, ssa.StmtString(p.Pos), p.InstructionString())
7586 }
7587 fi.Close()
7588 }
7589 }
7590
7591 htmlWriter.Close()
7592 htmlWriter = nil
7593 }
7594
7595 func defframe(s *State, e *ssafn, f *ssa.Func) {
7596 pp := s.pp
7597
7598 s.maxarg = types.RoundUp(s.maxarg, e.stkalign)
7599 frame := s.maxarg + e.stksize
7600 if Arch.PadFrame != nil {
7601 frame = Arch.PadFrame(frame)
7602 }
7603
7604
7605 pp.Text.To.Type = obj.TYPE_TEXTSIZE
7606 pp.Text.To.Val = int32(types.RoundUp(f.OwnAux.ArgWidth(), int64(types.RegSize)))
7607 pp.Text.To.Offset = frame
7608
7609 p := pp.Text
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620 if f.OwnAux.ABIInfo().InRegistersUsed() != 0 && base.Flag.N == 0 {
7621
7622
7623 type nameOff struct {
7624 n *ir.Name
7625 off int64
7626 }
7627 partLiveArgsSpilled := make(map[nameOff]bool)
7628 for _, v := range f.Entry.Values {
7629 if v.Op.IsCall() {
7630 break
7631 }
7632 if v.Op != ssaop.OpStoreReg || v.Args[0].Op != ssaop.OpArgIntReg {
7633 continue
7634 }
7635 n, off := ssa.AutoVar(v)
7636 if n.Class != ir.PPARAM || n.Addrtaken() || !ssa.CanSSA(n.Type()) || !s.partLiveArgs[n] {
7637 continue
7638 }
7639 partLiveArgsSpilled[nameOff{n, off}] = true
7640 }
7641
7642
7643 for _, a := range f.OwnAux.ABIInfo().InParams() {
7644 n := a.Name
7645 if n == nil || n.Addrtaken() || !ssa.CanSSA(n.Type()) || !s.partLiveArgs[n] || len(a.Registers) <= 1 {
7646 continue
7647 }
7648 rts, offs := a.RegisterTypesAndOffsets()
7649 for i := range a.Registers {
7650 if !rts[i].HasPointers() {
7651 continue
7652 }
7653 if partLiveArgsSpilled[nameOff{n, offs[i]}] {
7654 continue
7655 }
7656 reg := ssa.ObjRegForAbiReg(a.Registers[i], f.Config)
7657 p = Arch.SpillArgReg(pp, p, f, rts[i], reg, n, offs[i])
7658 }
7659 }
7660 }
7661
7662
7663
7664
7665 var lo, hi int64
7666
7667
7668
7669 var state uint32
7670
7671
7672
7673 for _, n := range e.curfn.Dcl {
7674 if !n.Needzero() {
7675 continue
7676 }
7677 if n.Class != ir.PAUTO {
7678 e.Fatalf(n.Pos(), "needzero class %d", n.Class)
7679 }
7680 if n.Type().Size()%int64(types.PtrSize) != 0 || n.FrameOffset()%int64(types.PtrSize) != 0 || n.Type().Size() == 0 {
7681 e.Fatalf(n.Pos(), "var %L has size %d offset %d", n, n.Type().Size(), n.Offset_)
7682 }
7683
7684 if lo != hi && n.FrameOffset()+n.Type().Size() >= lo-int64(2*types.RegSize) {
7685
7686 lo = n.FrameOffset()
7687 continue
7688 }
7689
7690
7691 p = Arch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
7692
7693
7694 lo = n.FrameOffset()
7695 hi = lo + n.Type().Size()
7696 }
7697
7698
7699 Arch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
7700 }
7701
7702
7703 type IndexJump struct {
7704 Jump obj.As
7705 Index int
7706 }
7707
7708 func (s *State) oneJump(b *ssa.Block, jump *IndexJump) {
7709 p := s.Br(jump.Jump, b.Succs[jump.Index].Block())
7710 p.Pos = b.Pos
7711 }
7712
7713
7714
7715 func (s *State) CombJump(b, next *ssa.Block, jumps *[2][2]IndexJump) {
7716 switch next {
7717 case b.Succs[0].Block():
7718 s.oneJump(b, &jumps[0][0])
7719 s.oneJump(b, &jumps[0][1])
7720 case b.Succs[1].Block():
7721 s.oneJump(b, &jumps[1][0])
7722 s.oneJump(b, &jumps[1][1])
7723 default:
7724 var q *obj.Prog
7725 if b.Likely != ssa.BranchUnlikely {
7726 s.oneJump(b, &jumps[1][0])
7727 s.oneJump(b, &jumps[1][1])
7728 q = s.Br(obj.AJMP, b.Succs[1].Block())
7729 } else {
7730 s.oneJump(b, &jumps[0][0])
7731 s.oneJump(b, &jumps[0][1])
7732 q = s.Br(obj.AJMP, b.Succs[0].Block())
7733 }
7734 q.Pos = b.Pos
7735 }
7736 }
7737
7738
7739 func AddAux(a *obj.Addr, v *ssa.Value) {
7740 AddAux2(a, v, v.AuxInt)
7741 }
7742 func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
7743 if a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR {
7744 v.Fatalf("bad AddAux addr %v", a)
7745 }
7746
7747 a.Offset += offset
7748
7749
7750 if v.Aux == nil {
7751 return
7752 }
7753
7754 switch n := v.Aux.(type) {
7755 case *ssa.AuxCall:
7756 a.Name = obj.NAME_EXTERN
7757 a.Sym = n.Fn
7758 case *obj.LSym:
7759 a.Name = obj.NAME_EXTERN
7760 a.Sym = n
7761 case *ir.Name:
7762 if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
7763 a.Name = obj.NAME_PARAM
7764 } else {
7765 a.Name = obj.NAME_AUTO
7766 }
7767 a.Sym = n.Linksym()
7768 a.Offset += n.FrameOffset()
7769 default:
7770 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
7771 }
7772 }
7773
7774
7775
7776 func (s *state) extendIndex(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
7777 size := idx.Type.Size()
7778 if size == s.config.PtrSize {
7779 return idx
7780 }
7781 if size > s.config.PtrSize {
7782
7783
7784 var lo *ssa.Value
7785 if idx.Type.IsSigned() {
7786 lo = s.newValue1(ssaop.OpInt64Lo, types.Types[types.TINT], idx)
7787 } else {
7788 lo = s.newValue1(ssaop.OpInt64Lo, types.Types[types.TUINT], idx)
7789 }
7790 if bounded || base.Flag.B != 0 {
7791 return lo
7792 }
7793 bNext := s.f.NewBlock(block.BlockPlain)
7794 bPanic := s.f.NewBlock(block.BlockExit)
7795 hi := s.newValue1(ssaop.OpInt64Hi, types.Types[types.TUINT32], idx)
7796 cmp := s.newValue2(ssaop.OpEq32, types.Types[types.TBOOL], hi, s.constInt32(types.Types[types.TUINT32], 0))
7797 if !idx.Type.IsSigned() {
7798 switch kind {
7799 case ssa.BoundsIndex:
7800 kind = ssa.BoundsIndexU
7801 case ssa.BoundsSliceAlen:
7802 kind = ssa.BoundsSliceAlenU
7803 case ssa.BoundsSliceAcap:
7804 kind = ssa.BoundsSliceAcapU
7805 case ssa.BoundsSliceB:
7806 kind = ssa.BoundsSliceBU
7807 case ssa.BoundsSlice3Alen:
7808 kind = ssa.BoundsSlice3AlenU
7809 case ssa.BoundsSlice3Acap:
7810 kind = ssa.BoundsSlice3AcapU
7811 case ssa.BoundsSlice3B:
7812 kind = ssa.BoundsSlice3BU
7813 case ssa.BoundsSlice3C:
7814 kind = ssa.BoundsSlice3CU
7815 }
7816 }
7817 b := s.endBlock()
7818 b.Kind = block.BlockIf
7819 b.SetControl(cmp)
7820 b.Likely = ssa.BranchLikely
7821 b.AddEdgeTo(bNext)
7822 b.AddEdgeTo(bPanic)
7823
7824 s.startBlock(bPanic)
7825 mem := s.newValue4I(ssaop.OpPanicExtend, types.TypeMem, int64(kind), hi, lo, len, s.mem())
7826 s.endBlock().SetControl(mem)
7827 s.startBlock(bNext)
7828
7829 return lo
7830 }
7831
7832
7833 var op ssaop.Op
7834 if idx.Type.IsSigned() {
7835 switch 10*size + s.config.PtrSize {
7836 case 14:
7837 op = ssaop.OpSignExt8to32
7838 case 18:
7839 op = ssaop.OpSignExt8to64
7840 case 24:
7841 op = ssaop.OpSignExt16to32
7842 case 28:
7843 op = ssaop.OpSignExt16to64
7844 case 48:
7845 op = ssaop.OpSignExt32to64
7846 default:
7847 s.Fatalf("bad signed index extension %s", idx.Type)
7848 }
7849 } else {
7850 switch 10*size + s.config.PtrSize {
7851 case 14:
7852 op = ssaop.OpZeroExt8to32
7853 case 18:
7854 op = ssaop.OpZeroExt8to64
7855 case 24:
7856 op = ssaop.OpZeroExt16to32
7857 case 28:
7858 op = ssaop.OpZeroExt16to64
7859 case 48:
7860 op = ssaop.OpZeroExt32to64
7861 default:
7862 s.Fatalf("bad unsigned index extension %s", idx.Type)
7863 }
7864 }
7865 return s.newValue1(op, types.Types[types.TINT], idx)
7866 }
7867
7868
7869
7870 func CheckLoweredPhi(v *ssa.Value) {
7871 if v.Op != ssaop.OpPhi {
7872 v.Fatalf("CheckLoweredPhi called with non-phi value: %v", v.LongString())
7873 }
7874 if v.Type.IsMemory() {
7875 return
7876 }
7877 f := v.Block.Func
7878 loc := f.RegAlloc[v.ID]
7879 for _, a := range v.Args {
7880 if aloc := f.RegAlloc[a.ID]; aloc != loc {
7881 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)
7882 }
7883 }
7884 }
7885
7886
7887
7888
7889
7890 func CheckLoweredGetClosurePtr(v *ssa.Value) {
7891 entry := v.Block.Func.Entry
7892 if entry != v.Block {
7893 base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
7894 }
7895 for _, w := range entry.Values {
7896 if w == v {
7897 break
7898 }
7899 switch w.Op {
7900 case ssaop.OpArgIntReg, ssaop.OpArgFloatReg:
7901
7902 default:
7903 base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
7904 }
7905 }
7906 }
7907
7908
7909 func CheckArgReg(v *ssa.Value) {
7910 entry := v.Block.Func.Entry
7911 if entry != v.Block {
7912 base.Fatalf("in %s, badly placed ArgIReg or ArgFReg: %v %v", v.Block.Func.Name, v.Block, v)
7913 }
7914 }
7915
7916 func AddrAuto(a *obj.Addr, v *ssa.Value) {
7917 n, off := ssa.AutoVar(v)
7918 a.Type = obj.TYPE_MEM
7919 a.Sym = n.Linksym()
7920 a.Reg = int16(Arch.REGSP)
7921 a.Offset = n.FrameOffset() + off
7922 if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
7923 a.Name = obj.NAME_PARAM
7924 } else {
7925 a.Name = obj.NAME_AUTO
7926 }
7927 }
7928
7929
7930
7931 func (s *State) Call(v *ssa.Value) *obj.Prog {
7932 pPosIsStmt := s.pp.Pos.IsStmt()
7933 s.PrepareCall(v)
7934
7935 p := s.Prog(obj.ACALL)
7936 if pPosIsStmt == src.PosIsStmt {
7937 p.Pos = v.Pos.WithIsStmt()
7938 } else {
7939 p.Pos = v.Pos.WithNotStmt()
7940 }
7941 if sym, ok := v.Aux.(*ssa.AuxCall); ok && sym.Fn != nil {
7942 p.To.Type = obj.TYPE_MEM
7943 p.To.Name = obj.NAME_EXTERN
7944 p.To.Sym = sym.Fn
7945 } else {
7946
7947 switch Arch.LinkArch.Family {
7948 case sys.AMD64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X, sys.Wasm:
7949 p.To.Type = obj.TYPE_REG
7950 case sys.ARM, sys.ARM64, sys.Loong64, sys.MIPS, sys.MIPS64:
7951 p.To.Type = obj.TYPE_MEM
7952 default:
7953 base.Fatalf("unknown indirect call family")
7954 }
7955 p.To.Reg = v.Args[0].Reg()
7956 }
7957 return p
7958 }
7959
7960
7961
7962 func (s *State) TailCall(v *ssa.Value) *obj.Prog {
7963 p := s.Call(v)
7964 p.As = obj.ARET
7965 return p
7966 }
7967
7968
7969
7970
7971 func (s *State) PrepareCall(v *ssa.Value) {
7972 idx := s.livenessMap.Get(v)
7973 if !idx.StackMapValid() {
7974
7975 if sym, ok := v.Aux.(*ssa.AuxCall); !ok || !(sym.Fn == ir.Syms.WBZero || sym.Fn == ir.Syms.WBMove) {
7976 base.Fatalf("missing stack map index for %v", v.LongString())
7977 }
7978 }
7979
7980 call, ok := v.Aux.(*ssa.AuxCall)
7981
7982 if ok {
7983
7984
7985 if nowritebarrierrecCheck != nil {
7986 nowritebarrierrecCheck.recordCall(s.pp.CurFunc, call.Fn, v.Pos)
7987 }
7988 }
7989
7990 if s.maxarg < v.AuxInt {
7991 s.maxarg = v.AuxInt
7992 }
7993 }
7994
7995
7996
7997 func (s *State) UseArgs(n int64) {
7998 if s.maxarg < n {
7999 s.maxarg = n
8000 }
8001 }
8002
8003
8004 func fieldIdx(n *ir.SelectorExpr) int {
8005 t := n.X.Type()
8006 if !isStructNotSIMD(t) {
8007 panic("ODOT's LHS is not a struct")
8008 }
8009
8010 for i, f := range t.Fields() {
8011 if f.Sym == n.Sel {
8012 if f.Offset != n.Offset() {
8013 panic("field offset doesn't match")
8014 }
8015 return i
8016 }
8017 }
8018 panic(fmt.Sprintf("can't find field in expr %v\n", n))
8019
8020
8021
8022 }
8023
8024
8025
8026 type ssafn struct {
8027 curfn *ir.Func
8028 strings map[string]*obj.LSym
8029 stksize int64
8030 stkptrsize int64
8031
8032
8033
8034
8035
8036 stkalign int64
8037
8038 log bool
8039 }
8040
8041
8042
8043 func (e *ssafn) StringData(s string) *obj.LSym {
8044 if aux, ok := e.strings[s]; ok {
8045 return aux
8046 }
8047 if e.strings == nil {
8048 e.strings = make(map[string]*obj.LSym)
8049 }
8050 data := staticdata.StringSym(e.curfn.Pos(), s)
8051 e.strings[s] = data
8052 return data
8053 }
8054
8055
8056 func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
8057 node := parent.N
8058
8059 if node.Class != ir.PAUTO || node.Addrtaken() {
8060
8061 return ssa.LocalSlot{N: node, Type: t, Off: parent.Off + offset}
8062 }
8063
8064 sym := &types.Sym{Name: node.Sym().Name + suffix, Pkg: types.LocalPkg}
8065 n := e.curfn.NewLocal(parent.N.Pos(), sym, t)
8066 n.SetUsed(true)
8067 n.SetEsc(ir.EscNever)
8068 types.CalcSize(t)
8069 return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset}
8070 }
8071
8072
8073 func (e *ssafn) Logf(msg string, args ...any) {
8074 if e.log {
8075 fmt.Printf(msg, args...)
8076 }
8077 }
8078
8079 func (e *ssafn) Log() bool {
8080 return e.log
8081 }
8082
8083
8084 func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...any) {
8085 base.Pos = pos
8086 nargs := append([]any{ir.FuncName(e.curfn)}, args...)
8087 base.Fatalf("'%s': "+msg, nargs...)
8088 }
8089
8090
8091
8092 func (e *ssafn) Warnl(pos src.XPos, fmt_ string, args ...any) {
8093 base.WarnfAt(pos, fmt_, args...)
8094 }
8095
8096 func (e *ssafn) Debug_checknil() bool {
8097 return base.Debug.Nil != 0
8098 }
8099
8100 func (e *ssafn) UseWriteBarrier() bool {
8101 return base.Flag.WB
8102 }
8103
8104 func (e *ssafn) Syslook(name string) *obj.LSym {
8105 switch name {
8106 case "goschedguarded":
8107 return ir.Syms.Goschedguarded
8108 case "writeBarrier":
8109 return ir.Syms.WriteBarrier
8110 case "wbZero":
8111 return ir.Syms.WBZero
8112 case "wbMove":
8113 return ir.Syms.WBMove
8114 case "cgoCheckMemmove":
8115 return ir.Syms.CgoCheckMemmove
8116 case "cgoCheckPtrWrite":
8117 return ir.Syms.CgoCheckPtrWrite
8118 }
8119 e.Fatalf(src.NoXPos, "unknown Syslook func %v", name)
8120 return nil
8121 }
8122
8123 func (e *ssafn) Func() *ir.Func {
8124 return e.curfn
8125 }
8126
8127 func clobberBase(n ir.Node) ir.Node {
8128 if n.Op() == ir.ODOT {
8129 n := n.(*ir.SelectorExpr)
8130 if n.X.Type().NumFields() == 1 {
8131 return clobberBase(n.X)
8132 }
8133 }
8134 if n.Op() == ir.OINDEX {
8135 n := n.(*ir.IndexExpr)
8136 if n.X.Type().IsArray() && n.X.Type().NumElem() == 1 {
8137 return clobberBase(n.X)
8138 }
8139 }
8140 return n
8141 }
8142
8143
8144 func callTargetLSym(callee *ir.Name) *obj.LSym {
8145 if callee.Func == nil {
8146
8147
8148
8149 return callee.Linksym()
8150 }
8151
8152 return callee.LinksymABI(callee.Func.ABI)
8153 }
8154
8155
8156 const deferStructFnField = 4
8157
8158 var deferType *types.Type
8159
8160
8161
8162 func deferstruct() *types.Type {
8163 if deferType != nil {
8164 return deferType
8165 }
8166
8167 makefield := func(name string, t *types.Type) *types.Field {
8168 sym := (*types.Pkg)(nil).Lookup(name)
8169 return types.NewField(src.NoXPos, sym, t)
8170 }
8171
8172 fields := []*types.Field{
8173 makefield("heap", types.Types[types.TBOOL]),
8174 makefield("rangefunc", types.Types[types.TBOOL]),
8175 makefield("sp", types.Types[types.TUINTPTR]),
8176 makefield("pc", types.Types[types.TUINTPTR]),
8177
8178
8179
8180 makefield("fn", types.Types[types.TUINTPTR]),
8181 makefield("link", types.Types[types.TUINTPTR]),
8182 makefield("head", types.Types[types.TUINTPTR]),
8183 }
8184 if name := fields[deferStructFnField].Sym.Name; name != "fn" {
8185 base.Fatalf("deferStructFnField is %q, not fn", name)
8186 }
8187
8188 n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.Pkgs.Runtime.Lookup("_defer"))
8189 typ := types.NewNamed(n)
8190 n.SetType(typ)
8191 n.SetTypecheck(1)
8192
8193
8194 typ.SetUnderlying(types.NewStruct(fields))
8195 types.CalcStructSize(typ)
8196
8197 deferType = typ
8198 return typ
8199 }
8200
8201
8202
8203
8204
8205 func SpillSlotAddr(spill ssa.Spill, baseReg int16, extraOffset int64) obj.Addr {
8206 return obj.Addr{
8207 Name: obj.NAME_NONE,
8208 Type: obj.TYPE_MEM,
8209 Reg: baseReg,
8210 Offset: spill.Offset + extraOffset,
8211 }
8212 }
8213
8214 func isStructNotSIMD(t *types.Type) bool {
8215 return t.IsStruct() && !t.IsSIMD()
8216 }
8217
8218 var BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
8219
View as plain text