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