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 5package ssa 6 7import ( 8 "cmd/compile/internal/abi" 9 "cmd/compile/internal/ir" 10 "cmd/compile/internal/types" 11 "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. 22type Op int32 23 24type 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 50type inputInfo struct { 51 idx int // index in Args array 52 regs regMask // allowed input registers 53} 54 55type outputInfo struct { 56 idx int // index in output tuple 57 regs regMask // allowed output registers 58} 59 60type 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 74func (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 95type auxType int8 96 97type AuxNameOffset struct { 98 Name *ir.Name 99 Offset int64 100} 101 102func (a *AuxNameOffset) CanBeAnSSAAux() {} 103func (a *AuxNameOffset) String() string { 104 return fmt.Sprintf("%s+%d", a.Name.Sym().Name, a.Offset) 105} 106 107func (a *AuxNameOffset) FrameOffset() int64 { 108 return a.Name.FrameOffset() + a.Offset 109} 110 111type 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. 127func (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} 159func (a *AuxCall) ABI() *abi.ABIConfig { 160 return a.abiInfo.Config() 161} 162func (a *AuxCall) ABIInfo() *abi.ABIParamResultInfo { 163 return a.abiInfo 164} 165func (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. 185func 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). 197func 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. 208func (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). 213func (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). 218func (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) 225func (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). 231func (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) 237func (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). 242func (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). 247func (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) 253func (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). 258func (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) 264func (a *AuxCall) SizeOfArg(which int64) int64 { 265 return a.TypeOfArg(which).Size() 266} 267 268// NResults returns the number of results. 269func (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. 275func (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). 285func (a *AuxCall) NArgs() int64 { 286 return int64(len(a.abiInfo.InParams())) 287} 288 289// String returns "AuxCall{<fn>}" 290func (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. 303func 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. 315func 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. 324func 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 332func (*AuxCall) CanBeAnSSAAux() {} 333 334// OwnAuxCall returns a function's own AuxCall. 335func 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 344const ( 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 auxCCop // auxInt is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan) 357 auxNameOffsetInt8 // aux is a &struct{Name ir.Name, Offset int64}; auxInt is index in parameter registers array 358 auxString // aux is a string 359 auxSym // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none) 360 auxSymOff // aux is a symbol, auxInt is an offset 361 auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff 362 auxTyp // aux is a type 363 auxTypSize // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt 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. 377type SymEffect int8 378 379const ( 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 394type 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. 405type ValAndOff int64 406 407func (x ValAndOff) Val() int32 { return int32(int64(x) >> 32) } 408func (x ValAndOff) Val64() int64 { return int64(x) >> 32 } 409func (x ValAndOff) Val16() int16 { return int16(int64(x) >> 32) } 410func (x ValAndOff) Val8() int8 { return int8(int64(x) >> 32) } 411 412func (x ValAndOff) Off64() int64 { return int64(int32(x)) } 413func (x ValAndOff) Off() int32 { return int32(x) } 414 415func (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. 421func validVal(val int64) bool { 422 return val == int64(int32(val)) 423} 424 425func makeValAndOff(val, off int32) ValAndOff { 426 return ValAndOff(int64(val)<<32 + int64(uint32(off))) 427} 428 429func (x ValAndOff) canAdd32(off int32) bool { 430 newoff := x.Off64() + int64(off) 431 return newoff == int64(int32(newoff)) 432} 433func (x ValAndOff) canAdd64(off int64) bool { 434 newoff := x.Off64() + off 435 return newoff == int64(int32(newoff)) 436} 437 438func (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} 444func (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. 453type int128 int64 454 455type BoundsKind uint8 456 457const ( 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. 498func 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. 529type arm64BitField int16 530