github.com/bir3/gocompiler@v0.3.205/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 type of result which (indexed 0, 1, etc). 242 func (a *AuxCall) NameOfResult(which int64) *ir.Name { 243 name := a.abiInfo.OutParam(int(which)).Name 244 if name == nil { 245 return nil 246 } 247 return name.(*ir.Name) 248 } 249 250 // TypeOfResult returns the type of result which (indexed 0, 1, etc). 251 func (a *AuxCall) TypeOfResult(which int64) *types.Type { 252 return a.abiInfo.OutParam(int(which)).Type 253 } 254 255 // TypeOfArg returns the type of argument which (indexed 0, 1, etc). 256 // If the call is to a method, the receiver is the first argument (i.e., index 0) 257 func (a *AuxCall) TypeOfArg(which int64) *types.Type { 258 return a.abiInfo.InParam(int(which)).Type 259 } 260 261 // SizeOfResult returns the size of result which (indexed 0, 1, etc). 262 func (a *AuxCall) SizeOfResult(which int64) int64 { 263 return a.TypeOfResult(which).Size() 264 } 265 266 // SizeOfArg returns the size of argument which (indexed 0, 1, etc). 267 // If the call is to a method, the receiver is the first argument (i.e., index 0) 268 func (a *AuxCall) SizeOfArg(which int64) int64 { 269 return a.TypeOfArg(which).Size() 270 } 271 272 // NResults returns the number of results. 273 func (a *AuxCall) NResults() int64 { 274 return int64(len(a.abiInfo.OutParams())) 275 } 276 277 // LateExpansionResultType returns the result type (including trailing mem) 278 // for a call that will be expanded later in the SSA phase. 279 func (a *AuxCall) LateExpansionResultType() *types.Type { 280 var tys []*types.Type 281 for i := int64(0); i < a.NResults(); i++ { 282 tys = append(tys, a.TypeOfResult(i)) 283 } 284 tys = append(tys, types.TypeMem) 285 return types.NewResults(tys) 286 } 287 288 // NArgs returns the number of arguments (including receiver, if there is one). 289 func (a *AuxCall) NArgs() int64 { 290 return int64(len(a.abiInfo.InParams())) 291 } 292 293 // String returns "AuxCall{<fn>}" 294 func (a *AuxCall) String() string { 295 var fn string 296 if a.Fn == nil { 297 fn = "AuxCall{nil" // could be interface/closure etc. 298 } else { 299 fn = fmt.Sprintf("AuxCall{%v", a.Fn) 300 } 301 // TODO how much of the ABI should be printed? 302 303 return fn + "}" 304 } 305 306 // StaticAuxCall returns an AuxCall for a static call. 307 func StaticAuxCall(sym *obj.LSym, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { 308 if paramResultInfo == nil { 309 panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym)) 310 } 311 var reg *regInfo 312 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { 313 reg = ®Info{} 314 } 315 return &AuxCall{Fn: sym, abiInfo: paramResultInfo, reg: reg} 316 } 317 318 // InterfaceAuxCall returns an AuxCall for an interface call. 319 func InterfaceAuxCall(paramResultInfo *abi.ABIParamResultInfo) *AuxCall { 320 var reg *regInfo 321 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { 322 reg = ®Info{} 323 } 324 return &AuxCall{Fn: nil, abiInfo: paramResultInfo, reg: reg} 325 } 326 327 // ClosureAuxCall returns an AuxCall for a closure call. 328 func ClosureAuxCall(paramResultInfo *abi.ABIParamResultInfo) *AuxCall { 329 var reg *regInfo 330 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { 331 reg = ®Info{} 332 } 333 return &AuxCall{Fn: nil, abiInfo: paramResultInfo, reg: reg} 334 } 335 336 func (*AuxCall) CanBeAnSSAAux() {} 337 338 // OwnAuxCall returns a function's own AuxCall. 339 func OwnAuxCall(fn *obj.LSym, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { 340 // TODO if this remains identical to ClosureAuxCall above after new ABI is done, should deduplicate. 341 var reg *regInfo 342 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { 343 reg = ®Info{} 344 } 345 return &AuxCall{Fn: fn, abiInfo: paramResultInfo, reg: reg} 346 } 347 348 const ( 349 auxNone auxType = iota 350 auxBool // auxInt is 0/1 for false/true 351 auxInt8 // auxInt is an 8-bit integer 352 auxInt16 // auxInt is a 16-bit integer 353 auxInt32 // auxInt is a 32-bit integer 354 auxInt64 // auxInt is a 64-bit integer 355 auxInt128 // auxInt represents a 128-bit integer. Always 0. 356 auxUInt8 // auxInt is an 8-bit unsigned integer 357 auxFloat32 // auxInt is a float32 (encoded with math.Float64bits) 358 auxFloat64 // auxInt is a float64 (encoded with math.Float64bits) 359 auxFlagConstant // auxInt is a flagConstant 360 auxNameOffsetInt8 // aux is a &struct{Name ir.Name, Offset int64}; auxInt is index in parameter registers array 361 auxString // aux is a string 362 auxSym // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none) 363 auxSymOff // aux is a symbol, auxInt is an offset 364 auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff 365 auxTyp // aux is a type 366 auxTypSize // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt 367 auxCCop // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan) 368 auxCall // aux is a *ssa.AuxCall 369 auxCallOff // aux is a *ssa.AuxCall, AuxInt is int64 param (in+out) size 370 371 // architecture specific aux types 372 auxARM64BitField // aux is an arm64 bitfield lsb and width packed into auxInt 373 auxS390XRotateParams // aux is a s390x rotate parameters object encoding start bit, end bit and rotate amount 374 auxS390XCCMask // aux is a s390x 4-bit condition code mask 375 auxS390XCCMaskInt8 // aux is a s390x 4-bit condition code mask, auxInt is a int8 immediate 376 auxS390XCCMaskUint8 // aux is a s390x 4-bit condition code mask, auxInt is a uint8 immediate 377 ) 378 379 // A SymEffect describes the effect that an SSA Value has on the variable 380 // identified by the symbol in its Aux field. 381 type SymEffect int8 382 383 const ( 384 SymRead SymEffect = 1 << iota 385 SymWrite 386 SymAddr 387 388 SymRdWr = SymRead | SymWrite 389 390 SymNone SymEffect = 0 391 ) 392 393 // A Sym represents a symbolic offset from a base register. 394 // Currently a Sym can be one of 3 things: 395 // - a *gc.Node, for an offset from SP (the stack pointer) 396 // - a *obj.LSym, for an offset from SB (the global pointer) 397 // - nil, for no offset 398 type Sym interface { 399 CanBeAnSSASym() 400 CanBeAnSSAAux() 401 } 402 403 // A ValAndOff is used by the several opcodes. It holds 404 // both a value and a pointer offset. 405 // A ValAndOff is intended to be encoded into an AuxInt field. 406 // The zero ValAndOff encodes a value of 0 and an offset of 0. 407 // The high 32 bits hold a value. 408 // The low 32 bits hold a pointer offset. 409 type ValAndOff int64 410 411 func (x ValAndOff) Val() int32 { return int32(int64(x) >> 32) } 412 func (x ValAndOff) Val64() int64 { return int64(x) >> 32 } 413 func (x ValAndOff) Val16() int16 { return int16(int64(x) >> 32) } 414 func (x ValAndOff) Val8() int8 { return int8(int64(x) >> 32) } 415 416 func (x ValAndOff) Off64() int64 { return int64(int32(x)) } 417 func (x ValAndOff) Off() int32 { return int32(x) } 418 419 func (x ValAndOff) String() string { 420 return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off()) 421 } 422 423 // validVal reports whether the value can be used 424 // as an argument to makeValAndOff. 425 func validVal(val int64) bool { 426 return val == int64(int32(val)) 427 } 428 429 func makeValAndOff(val, off int32) ValAndOff { 430 return ValAndOff(int64(val)<<32 + int64(uint32(off))) 431 } 432 433 func (x ValAndOff) canAdd32(off int32) bool { 434 newoff := x.Off64() + int64(off) 435 return newoff == int64(int32(newoff)) 436 } 437 func (x ValAndOff) canAdd64(off int64) bool { 438 newoff := x.Off64() + off 439 return newoff == int64(int32(newoff)) 440 } 441 442 func (x ValAndOff) addOffset32(off int32) ValAndOff { 443 if !x.canAdd32(off) { 444 panic("invalid ValAndOff.addOffset32") 445 } 446 return makeValAndOff(x.Val(), x.Off()+off) 447 } 448 func (x ValAndOff) addOffset64(off int64) ValAndOff { 449 if !x.canAdd64(off) { 450 panic("invalid ValAndOff.addOffset64") 451 } 452 return makeValAndOff(x.Val(), x.Off()+int32(off)) 453 } 454 455 // int128 is a type that stores a 128-bit constant. 456 // The only allowed constant right now is 0, so we can cheat quite a bit. 457 type int128 int64 458 459 type BoundsKind uint8 460 461 const ( 462 BoundsIndex BoundsKind = iota // indexing operation, 0 <= idx < len failed 463 BoundsIndexU // ... with unsigned idx 464 BoundsSliceAlen // 2-arg slicing operation, 0 <= high <= len failed 465 BoundsSliceAlenU // ... with unsigned high 466 BoundsSliceAcap // 2-arg slicing operation, 0 <= high <= cap failed 467 BoundsSliceAcapU // ... with unsigned high 468 BoundsSliceB // 2-arg slicing operation, 0 <= low <= high failed 469 BoundsSliceBU // ... with unsigned low 470 BoundsSlice3Alen // 3-arg slicing operation, 0 <= max <= len failed 471 BoundsSlice3AlenU // ... with unsigned max 472 BoundsSlice3Acap // 3-arg slicing operation, 0 <= max <= cap failed 473 BoundsSlice3AcapU // ... with unsigned max 474 BoundsSlice3B // 3-arg slicing operation, 0 <= high <= max failed 475 BoundsSlice3BU // ... with unsigned high 476 BoundsSlice3C // 3-arg slicing operation, 0 <= low <= high failed 477 BoundsSlice3CU // ... with unsigned low 478 BoundsConvert // conversion to array pointer failed 479 BoundsKindCount 480 ) 481 482 // boundsABI determines which register arguments a bounds check call should use. For an [a:b:c] slice, we do: 483 // 484 // CMPQ c, cap 485 // JA fail1 486 // CMPQ b, c 487 // JA fail2 488 // CMPQ a, b 489 // JA fail3 490 // 491 // fail1: CALL panicSlice3Acap (c, cap) 492 // fail2: CALL panicSlice3B (b, c) 493 // fail3: CALL panicSlice3C (a, b) 494 // 495 // When we register allocate that code, we want the same register to be used for 496 // the first arg of panicSlice3Acap and the second arg to panicSlice3B. That way, 497 // initializing that register once will satisfy both calls. 498 // That desire ends up dividing the set of bounds check calls into 3 sets. This function 499 // determines which set to use for a given panic call. 500 // The first arg for set 0 should be the second arg for set 1. 501 // The first arg for set 1 should be the second arg for set 2. 502 func boundsABI(b int64) int { 503 switch BoundsKind(b) { 504 case BoundsSlice3Alen, 505 BoundsSlice3AlenU, 506 BoundsSlice3Acap, 507 BoundsSlice3AcapU, 508 BoundsConvert: 509 return 0 510 case BoundsSliceAlen, 511 BoundsSliceAlenU, 512 BoundsSliceAcap, 513 BoundsSliceAcapU, 514 BoundsSlice3B, 515 BoundsSlice3BU: 516 return 1 517 case BoundsIndex, 518 BoundsIndexU, 519 BoundsSliceB, 520 BoundsSliceBU, 521 BoundsSlice3C, 522 BoundsSlice3CU: 523 return 2 524 default: 525 panic("bad BoundsKind") 526 } 527 } 528 529 // arm64BitField is the GO type of ARM64BitField auxInt. 530 // if x is an ARM64BitField, then width=x&0xff, lsb=(x>>8)&0xff, and 531 // width+lsb<64 for 64-bit variant, width+lsb<32 for 32-bit variant. 532 // the meaning of width and lsb are instruction-dependent. 533 type arm64BitField int16