github.com/bir3/gocompiler@v0.9.2202/src/cmd/compile/internal/ssa/op.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 ssa 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/compile/internal/abi" 9 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 10 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 11 "github.com/bir3/gocompiler/src/cmd/internal/obj" 12 "fmt" 13 "strings" 14 ) 15 16 // An Op encodes the specific operation that a Value performs. 17 // Opcodes' semantics can be modified by the type and aux fields of the Value. 18 // For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type. 19 // Semantics of each op are described in the opcode files in _gen/*Ops.go. 20 // There is one file for generic (architecture-independent) ops and one file 21 // for each architecture. 22 type Op int32 23 24 type opInfo struct { 25 name string 26 reg regInfo 27 auxType auxType 28 argLen int32 // the number of arguments, -1 if variable length 29 asm obj.As 30 generic bool // this is a generic (arch-independent) opcode 31 rematerializeable bool // this op is rematerializeable 32 commutative bool // this operation is commutative (e.g. addition) 33 resultInArg0 bool // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register 34 resultNotInArgs bool // outputs must not be allocated to the same registers as inputs 35 clobberFlags bool // this op clobbers flags register 36 needIntTemp bool // need a temporary free integer register 37 call bool // is a function call 38 tailCall bool // is a tail call 39 nilCheck bool // this op is a nil check on arg0 40 faultOnNilArg0 bool // this op will fault if arg0 is nil (and aux encodes a small offset) 41 faultOnNilArg1 bool // this op will fault if arg1 is nil (and aux encodes a small offset) 42 usesScratch bool // this op requires scratch memory space 43 hasSideEffects bool // for "reasons", not to be eliminated. E.g., atomic store, #19182. 44 zeroWidth bool // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width. 45 unsafePoint bool // this op is an unsafe point, i.e. not safe for async preemption 46 symEffect SymEffect // effect this op has on symbol in aux 47 scale uint8 // amd64/386 indexed load scale 48 } 49 50 type inputInfo struct { 51 idx int // index in Args array 52 regs regMask // allowed input registers 53 } 54 55 type outputInfo struct { 56 idx int // index in output tuple 57 regs regMask // allowed output registers 58 } 59 60 type regInfo struct { 61 // inputs encodes the register restrictions for an instruction's inputs. 62 // Each entry specifies an allowed register set for a particular input. 63 // They are listed in the order in which regalloc should pick a register 64 // from the register set (most constrained first). 65 // Inputs which do not need registers are not listed. 66 inputs []inputInfo 67 // clobbers encodes the set of registers that are overwritten by 68 // the instruction (other than the output registers). 69 clobbers regMask 70 // outputs is the same as inputs, but for the outputs of the instruction. 71 outputs []outputInfo 72 } 73 74 func (r *regInfo) String() string { 75 s := "" 76 s += "INS:\n" 77 for _, i := range r.inputs { 78 mask := fmt.Sprintf("%64b", i.regs) 79 mask = strings.Replace(mask, "0", ".", -1) 80 s += fmt.Sprintf("%2d |%s|\n", i.idx, mask) 81 } 82 s += "OUTS:\n" 83 for _, i := range r.outputs { 84 mask := fmt.Sprintf("%64b", i.regs) 85 mask = strings.Replace(mask, "0", ".", -1) 86 s += fmt.Sprintf("%2d |%s|\n", i.idx, mask) 87 } 88 s += "CLOBBERS:\n" 89 mask := fmt.Sprintf("%64b", r.clobbers) 90 mask = strings.Replace(mask, "0", ".", -1) 91 s += fmt.Sprintf(" |%s|\n", mask) 92 return s 93 } 94 95 type auxType int8 96 97 type AuxNameOffset struct { 98 Name *ir.Name 99 Offset int64 100 } 101 102 func (a *AuxNameOffset) CanBeAnSSAAux() {} 103 func (a *AuxNameOffset) String() string { 104 return fmt.Sprintf("%s+%d", a.Name.Sym().Name, a.Offset) 105 } 106 107 func (a *AuxNameOffset) FrameOffset() int64 { 108 return a.Name.FrameOffset() + a.Offset 109 } 110 111 type AuxCall struct { 112 Fn *obj.LSym 113 reg *regInfo // regInfo for this call 114 abiInfo *abi.ABIParamResultInfo 115 } 116 117 // Reg returns the regInfo for a given call, combining the derived in/out register masks 118 // with the machine-specific register information in the input i. (The machine-specific 119 // regInfo is much handier at the call site than it is when the AuxCall is being constructed, 120 // therefore do this lazily). 121 // 122 // TODO: there is a Clever Hack that allows pre-generation of a small-ish number of the slices 123 // of inputInfo and outputInfo used here, provided that we are willing to reorder the inputs 124 // and outputs from calls, so that all integer registers come first, then all floating registers. 125 // At this point (active development of register ABI) that is very premature, 126 // but if this turns out to be a cost, we could do it. 127 func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo { 128 if a.reg.clobbers != 0 { 129 // Already updated 130 return a.reg 131 } 132 if a.abiInfo.InRegistersUsed()+a.abiInfo.OutRegistersUsed() == 0 { 133 // Shortcut for zero case, also handles old ABI. 134 a.reg = i 135 return a.reg 136 } 137 138 k := len(i.inputs) 139 for _, p := range a.abiInfo.InParams() { 140 for _, r := range p.Registers { 141 m := archRegForAbiReg(r, c) 142 a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)}) 143 k++ 144 } 145 } 146 a.reg.inputs = append(a.reg.inputs, i.inputs...) // These are less constrained, thus should come last 147 k = len(i.outputs) 148 for _, p := range a.abiInfo.OutParams() { 149 for _, r := range p.Registers { 150 m := archRegForAbiReg(r, c) 151 a.reg.outputs = append(a.reg.outputs, outputInfo{idx: k, regs: (1 << m)}) 152 k++ 153 } 154 } 155 a.reg.outputs = append(a.reg.outputs, i.outputs...) 156 a.reg.clobbers = i.clobbers 157 return a.reg 158 } 159 func (a *AuxCall) ABI() *abi.ABIConfig { 160 return a.abiInfo.Config() 161 } 162 func (a *AuxCall) ABIInfo() *abi.ABIParamResultInfo { 163 return a.abiInfo 164 } 165 func (a *AuxCall) ResultReg(c *Config) *regInfo { 166 if a.abiInfo.OutRegistersUsed() == 0 { 167 return a.reg 168 } 169 if len(a.reg.inputs) > 0 { 170 return a.reg 171 } 172 k := 0 173 for _, p := range a.abiInfo.OutParams() { 174 for _, r := range p.Registers { 175 m := archRegForAbiReg(r, c) 176 a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)}) 177 k++ 178 } 179 } 180 return a.reg 181 } 182 183 // For ABI register index r, returns the (dense) register number used in 184 // SSA backend. 185 func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 { 186 var m int8 187 if int(r) < len(c.intParamRegs) { 188 m = c.intParamRegs[r] 189 } else { 190 m = c.floatParamRegs[int(r)-len(c.intParamRegs)] 191 } 192 return uint8(m) 193 } 194 195 // For ABI register index r, returns the register number used in the obj 196 // package (assembler). 197 func ObjRegForAbiReg(r abi.RegIndex, c *Config) int16 { 198 m := archRegForAbiReg(r, c) 199 return c.registers[m].objNum 200 } 201 202 // ArgWidth returns the amount of stack needed for all the inputs 203 // and outputs of a function or method, including ABI-defined parameter 204 // slots and ABI-defined spill slots for register-resident parameters. 205 // 206 // The name is taken from the types package's ArgWidth(<function type>), 207 // which predated changes to the ABI; this version handles those changes. 208 func (a *AuxCall) ArgWidth() int64 { 209 return a.abiInfo.ArgWidth() 210 } 211 212 // ParamAssignmentForResult returns the ABI Parameter assignment for result which (indexed 0, 1, etc). 213 func (a *AuxCall) ParamAssignmentForResult(which int64) *abi.ABIParamAssignment { 214 return a.abiInfo.OutParam(int(which)) 215 } 216 217 // OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc). 218 func (a *AuxCall) OffsetOfResult(which int64) int64 { 219 n := int64(a.abiInfo.OutParam(int(which)).Offset()) 220 return n 221 } 222 223 // OffsetOfArg returns the SP offset of argument which (indexed 0, 1, etc). 224 // If the call is to a method, the receiver is the first argument (i.e., index 0) 225 func (a *AuxCall) OffsetOfArg(which int64) int64 { 226 n := int64(a.abiInfo.InParam(int(which)).Offset()) 227 return n 228 } 229 230 // RegsOfResult returns the register(s) used for result which (indexed 0, 1, etc). 231 func (a *AuxCall) RegsOfResult(which int64) []abi.RegIndex { 232 return a.abiInfo.OutParam(int(which)).Registers 233 } 234 235 // RegsOfArg returns the register(s) used for argument which (indexed 0, 1, etc). 236 // If the call is to a method, the receiver is the first argument (i.e., index 0) 237 func (a *AuxCall) RegsOfArg(which int64) []abi.RegIndex { 238 return a.abiInfo.InParam(int(which)).Registers 239 } 240 241 // NameOfResult returns the ir.Name of result which (indexed 0, 1, etc). 242 func (a *AuxCall) NameOfResult(which int64) *ir.Name { 243 return a.abiInfo.OutParam(int(which)).Name 244 } 245 246 // TypeOfResult returns the type of result which (indexed 0, 1, etc). 247 func (a *AuxCall) TypeOfResult(which int64) *types.Type { 248 return a.abiInfo.OutParam(int(which)).Type 249 } 250 251 // TypeOfArg returns the type of argument which (indexed 0, 1, etc). 252 // If the call is to a method, the receiver is the first argument (i.e., index 0) 253 func (a *AuxCall) TypeOfArg(which int64) *types.Type { 254 return a.abiInfo.InParam(int(which)).Type 255 } 256 257 // SizeOfResult returns the size of result which (indexed 0, 1, etc). 258 func (a *AuxCall) SizeOfResult(which int64) int64 { 259 return a.TypeOfResult(which).Size() 260 } 261 262 // SizeOfArg returns the size of argument which (indexed 0, 1, etc). 263 // If the call is to a method, the receiver is the first argument (i.e., index 0) 264 func (a *AuxCall) SizeOfArg(which int64) int64 { 265 return a.TypeOfArg(which).Size() 266 } 267 268 // NResults returns the number of results. 269 func (a *AuxCall) NResults() int64 { 270 return int64(len(a.abiInfo.OutParams())) 271 } 272 273 // LateExpansionResultType returns the result type (including trailing mem) 274 // for a call that will be expanded later in the SSA phase. 275 func (a *AuxCall) LateExpansionResultType() *types.Type { 276 var tys []*types.Type 277 for i := int64(0); i < a.NResults(); i++ { 278 tys = append(tys, a.TypeOfResult(i)) 279 } 280 tys = append(tys, types.TypeMem) 281 return types.NewResults(tys) 282 } 283 284 // NArgs returns the number of arguments (including receiver, if there is one). 285 func (a *AuxCall) NArgs() int64 { 286 return int64(len(a.abiInfo.InParams())) 287 } 288 289 // String returns "AuxCall{<fn>}" 290 func (a *AuxCall) String() string { 291 var fn string 292 if a.Fn == nil { 293 fn = "AuxCall{nil" // could be interface/closure etc. 294 } else { 295 fn = fmt.Sprintf("AuxCall{%v", a.Fn) 296 } 297 // TODO how much of the ABI should be printed? 298 299 return fn + "}" 300 } 301 302 // StaticAuxCall returns an AuxCall for a static call. 303 func StaticAuxCall(sym *obj.LSym, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { 304 if paramResultInfo == nil { 305 panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym)) 306 } 307 var reg *regInfo 308 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { 309 reg = ®Info{} 310 } 311 return &AuxCall{Fn: sym, abiInfo: paramResultInfo, reg: reg} 312 } 313 314 // InterfaceAuxCall returns an AuxCall for an interface call. 315 func InterfaceAuxCall(paramResultInfo *abi.ABIParamResultInfo) *AuxCall { 316 var reg *regInfo 317 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { 318 reg = ®Info{} 319 } 320 return &AuxCall{Fn: nil, abiInfo: paramResultInfo, reg: reg} 321 } 322 323 // ClosureAuxCall returns an AuxCall for a closure call. 324 func ClosureAuxCall(paramResultInfo *abi.ABIParamResultInfo) *AuxCall { 325 var reg *regInfo 326 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { 327 reg = ®Info{} 328 } 329 return &AuxCall{Fn: nil, abiInfo: paramResultInfo, reg: reg} 330 } 331 332 func (*AuxCall) CanBeAnSSAAux() {} 333 334 // OwnAuxCall returns a function's own AuxCall. 335 func OwnAuxCall(fn *obj.LSym, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { 336 // TODO if this remains identical to ClosureAuxCall above after new ABI is done, should deduplicate. 337 var reg *regInfo 338 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { 339 reg = ®Info{} 340 } 341 return &AuxCall{Fn: fn, abiInfo: paramResultInfo, reg: reg} 342 } 343 344 const ( 345 auxNone auxType = iota 346 auxBool // auxInt is 0/1 for false/true 347 auxInt8 // auxInt is an 8-bit integer 348 auxInt16 // auxInt is a 16-bit integer 349 auxInt32 // auxInt is a 32-bit integer 350 auxInt64 // auxInt is a 64-bit integer 351 auxInt128 // auxInt represents a 128-bit integer. Always 0. 352 auxUInt8 // auxInt is an 8-bit unsigned integer 353 auxFloat32 // auxInt is a float32 (encoded with math.Float64bits) 354 auxFloat64 // auxInt is a float64 (encoded with math.Float64bits) 355 auxFlagConstant // auxInt is a flagConstant 356 auxNameOffsetInt8 // aux is a &struct{Name ir.Name, Offset int64}; auxInt is index in parameter registers array 357 auxString // aux is a string 358 auxSym // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none) 359 auxSymOff // aux is a symbol, auxInt is an offset 360 auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff 361 auxTyp // aux is a type 362 auxTypSize // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt 363 auxCCop // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan) 364 auxCall // aux is a *ssa.AuxCall 365 auxCallOff // aux is a *ssa.AuxCall, AuxInt is int64 param (in+out) size 366 367 // architecture specific aux types 368 auxARM64BitField // aux is an arm64 bitfield lsb and width packed into auxInt 369 auxS390XRotateParams // aux is a s390x rotate parameters object encoding start bit, end bit and rotate amount 370 auxS390XCCMask // aux is a s390x 4-bit condition code mask 371 auxS390XCCMaskInt8 // aux is a s390x 4-bit condition code mask, auxInt is an int8 immediate 372 auxS390XCCMaskUint8 // aux is a s390x 4-bit condition code mask, auxInt is a uint8 immediate 373 ) 374 375 // A SymEffect describes the effect that an SSA Value has on the variable 376 // identified by the symbol in its Aux field. 377 type SymEffect int8 378 379 const ( 380 SymRead SymEffect = 1 << iota 381 SymWrite 382 SymAddr 383 384 SymRdWr = SymRead | SymWrite 385 386 SymNone SymEffect = 0 387 ) 388 389 // A Sym represents a symbolic offset from a base register. 390 // Currently a Sym can be one of 3 things: 391 // - a *gc.Node, for an offset from SP (the stack pointer) 392 // - a *obj.LSym, for an offset from SB (the global pointer) 393 // - nil, for no offset 394 type Sym interface { 395 CanBeAnSSASym() 396 CanBeAnSSAAux() 397 } 398 399 // A ValAndOff is used by the several opcodes. It holds 400 // both a value and a pointer offset. 401 // A ValAndOff is intended to be encoded into an AuxInt field. 402 // The zero ValAndOff encodes a value of 0 and an offset of 0. 403 // The high 32 bits hold a value. 404 // The low 32 bits hold a pointer offset. 405 type ValAndOff int64 406 407 func (x ValAndOff) Val() int32 { return int32(int64(x) >> 32) } 408 func (x ValAndOff) Val64() int64 { return int64(x) >> 32 } 409 func (x ValAndOff) Val16() int16 { return int16(int64(x) >> 32) } 410 func (x ValAndOff) Val8() int8 { return int8(int64(x) >> 32) } 411 412 func (x ValAndOff) Off64() int64 { return int64(int32(x)) } 413 func (x ValAndOff) Off() int32 { return int32(x) } 414 415 func (x ValAndOff) String() string { 416 return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off()) 417 } 418 419 // validVal reports whether the value can be used 420 // as an argument to makeValAndOff. 421 func validVal(val int64) bool { 422 return val == int64(int32(val)) 423 } 424 425 func makeValAndOff(val, off int32) ValAndOff { 426 return ValAndOff(int64(val)<<32 + int64(uint32(off))) 427 } 428 429 func (x ValAndOff) canAdd32(off int32) bool { 430 newoff := x.Off64() + int64(off) 431 return newoff == int64(int32(newoff)) 432 } 433 func (x ValAndOff) canAdd64(off int64) bool { 434 newoff := x.Off64() + off 435 return newoff == int64(int32(newoff)) 436 } 437 438 func (x ValAndOff) addOffset32(off int32) ValAndOff { 439 if !x.canAdd32(off) { 440 panic("invalid ValAndOff.addOffset32") 441 } 442 return makeValAndOff(x.Val(), x.Off()+off) 443 } 444 func (x ValAndOff) addOffset64(off int64) ValAndOff { 445 if !x.canAdd64(off) { 446 panic("invalid ValAndOff.addOffset64") 447 } 448 return makeValAndOff(x.Val(), x.Off()+int32(off)) 449 } 450 451 // int128 is a type that stores a 128-bit constant. 452 // The only allowed constant right now is 0, so we can cheat quite a bit. 453 type int128 int64 454 455 type BoundsKind uint8 456 457 const ( 458 BoundsIndex BoundsKind = iota // indexing operation, 0 <= idx < len failed 459 BoundsIndexU // ... with unsigned idx 460 BoundsSliceAlen // 2-arg slicing operation, 0 <= high <= len failed 461 BoundsSliceAlenU // ... with unsigned high 462 BoundsSliceAcap // 2-arg slicing operation, 0 <= high <= cap failed 463 BoundsSliceAcapU // ... with unsigned high 464 BoundsSliceB // 2-arg slicing operation, 0 <= low <= high failed 465 BoundsSliceBU // ... with unsigned low 466 BoundsSlice3Alen // 3-arg slicing operation, 0 <= max <= len failed 467 BoundsSlice3AlenU // ... with unsigned max 468 BoundsSlice3Acap // 3-arg slicing operation, 0 <= max <= cap failed 469 BoundsSlice3AcapU // ... with unsigned max 470 BoundsSlice3B // 3-arg slicing operation, 0 <= high <= max failed 471 BoundsSlice3BU // ... with unsigned high 472 BoundsSlice3C // 3-arg slicing operation, 0 <= low <= high failed 473 BoundsSlice3CU // ... with unsigned low 474 BoundsConvert // conversion to array pointer failed 475 BoundsKindCount 476 ) 477 478 // boundsABI determines which register arguments a bounds check call should use. For an [a:b:c] slice, we do: 479 // 480 // CMPQ c, cap 481 // JA fail1 482 // CMPQ b, c 483 // JA fail2 484 // CMPQ a, b 485 // JA fail3 486 // 487 // fail1: CALL panicSlice3Acap (c, cap) 488 // fail2: CALL panicSlice3B (b, c) 489 // fail3: CALL panicSlice3C (a, b) 490 // 491 // When we register allocate that code, we want the same register to be used for 492 // the first arg of panicSlice3Acap and the second arg to panicSlice3B. That way, 493 // initializing that register once will satisfy both calls. 494 // That desire ends up dividing the set of bounds check calls into 3 sets. This function 495 // determines which set to use for a given panic call. 496 // The first arg for set 0 should be the second arg for set 1. 497 // The first arg for set 1 should be the second arg for set 2. 498 func boundsABI(b int64) int { 499 switch BoundsKind(b) { 500 case BoundsSlice3Alen, 501 BoundsSlice3AlenU, 502 BoundsSlice3Acap, 503 BoundsSlice3AcapU, 504 BoundsConvert: 505 return 0 506 case BoundsSliceAlen, 507 BoundsSliceAlenU, 508 BoundsSliceAcap, 509 BoundsSliceAcapU, 510 BoundsSlice3B, 511 BoundsSlice3BU: 512 return 1 513 case BoundsIndex, 514 BoundsIndexU, 515 BoundsSliceB, 516 BoundsSliceBU, 517 BoundsSlice3C, 518 BoundsSlice3CU: 519 return 2 520 default: 521 panic("bad BoundsKind") 522 } 523 } 524 525 // arm64BitField is the GO type of ARM64BitField auxInt. 526 // if x is an ARM64BitField, then width=x&0xff, lsb=(x>>8)&0xff, and 527 // width+lsb<64 for 64-bit variant, width+lsb<32 for 32-bit variant. 528 // the meaning of width and lsb are instruction-dependent. 529 type arm64BitField int16