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