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