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