Source file src/cmd/compile/internal/ssa/op.go

Documentation: cmd/compile/internal/ssa

     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  	"cmd/internal/obj"
     9  	"fmt"
    10  )
    11  
    12  // An Op encodes the specific operation that a Value performs.
    13  // Opcodes' semantics can be modified by the type and aux fields of the Value.
    14  // For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type.
    15  // Semantics of each op are described in the opcode files in gen/*Ops.go.
    16  // There is one file for generic (architecture-independent) ops and one file
    17  // for each architecture.
    18  type Op int32
    19  
    20  type opInfo struct {
    21  	name              string
    22  	reg               regInfo
    23  	auxType           auxType
    24  	argLen            int32 // the number of arguments, -1 if variable length
    25  	asm               obj.As
    26  	generic           bool      // this is a generic (arch-independent) opcode
    27  	rematerializeable bool      // this op is rematerializeable
    28  	commutative       bool      // this operation is commutative (e.g. addition)
    29  	resultInArg0      bool      // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
    30  	resultNotInArgs   bool      // outputs must not be allocated to the same registers as inputs
    31  	clobberFlags      bool      // this op clobbers flags register
    32  	call              bool      // is a function call
    33  	nilCheck          bool      // this op is a nil check on arg0
    34  	faultOnNilArg0    bool      // this op will fault if arg0 is nil (and aux encodes a small offset)
    35  	faultOnNilArg1    bool      // this op will fault if arg1 is nil (and aux encodes a small offset)
    36  	usesScratch       bool      // this op requires scratch memory space
    37  	hasSideEffects    bool      // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
    38  	zeroWidth         bool      // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width.
    39  	symEffect         SymEffect // effect this op has on symbol in aux
    40  	scale             uint8     // amd64/386 indexed load scale
    41  }
    42  
    43  type inputInfo struct {
    44  	idx  int     // index in Args array
    45  	regs regMask // allowed input registers
    46  }
    47  
    48  type outputInfo struct {
    49  	idx  int     // index in output tuple
    50  	regs regMask // allowed output registers
    51  }
    52  
    53  type regInfo struct {
    54  	// inputs encodes the register restrictions for an instruction's inputs.
    55  	// Each entry specifies an allowed register set for a particular input.
    56  	// They are listed in the order in which regalloc should pick a register
    57  	// from the register set (most constrained first).
    58  	// Inputs which do not need registers are not listed.
    59  	inputs []inputInfo
    60  	// clobbers encodes the set of registers that are overwritten by
    61  	// the instruction (other than the output registers).
    62  	clobbers regMask
    63  	// outputs is the same as inputs, but for the outputs of the instruction.
    64  	outputs []outputInfo
    65  }
    66  
    67  type auxType int8
    68  
    69  const (
    70  	auxNone         auxType = iota
    71  	auxBool                 // auxInt is 0/1 for false/true
    72  	auxInt8                 // auxInt is an 8-bit integer
    73  	auxInt16                // auxInt is a 16-bit integer
    74  	auxInt32                // auxInt is a 32-bit integer
    75  	auxInt64                // auxInt is a 64-bit integer
    76  	auxInt128               // auxInt represents a 128-bit integer.  Always 0.
    77  	auxFloat32              // auxInt is a float32 (encoded with math.Float64bits)
    78  	auxFloat64              // auxInt is a float64 (encoded with math.Float64bits)
    79  	auxString               // aux is a string
    80  	auxSym                  // aux is a symbol (a *gc.Node for locals or an *obj.LSym for globals)
    81  	auxSymOff               // aux is a symbol, auxInt is an offset
    82  	auxSymValAndOff         // aux is a symbol, auxInt is a ValAndOff
    83  	auxTyp                  // aux is a type
    84  	auxTypSize              // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt
    85  	auxCCop                 // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan)
    86  
    87  	auxSymInt32 // aux is a symbol, auxInt is a 32-bit integer
    88  )
    89  
    90  // A SymEffect describes the effect that an SSA Value has on the variable
    91  // identified by the symbol in its Aux field.
    92  type SymEffect int8
    93  
    94  const (
    95  	SymRead SymEffect = 1 << iota
    96  	SymWrite
    97  	SymAddr
    98  
    99  	SymRdWr = SymRead | SymWrite
   100  
   101  	SymNone SymEffect = 0
   102  )
   103  
   104  // A ValAndOff is used by the several opcodes. It holds
   105  // both a value and a pointer offset.
   106  // A ValAndOff is intended to be encoded into an AuxInt field.
   107  // The zero ValAndOff encodes a value of 0 and an offset of 0.
   108  // The high 32 bits hold a value.
   109  // The low 32 bits hold a pointer offset.
   110  type ValAndOff int64
   111  
   112  func (x ValAndOff) Val() int64 {
   113  	return int64(x) >> 32
   114  }
   115  func (x ValAndOff) Off() int64 {
   116  	return int64(int32(x))
   117  }
   118  func (x ValAndOff) Int64() int64 {
   119  	return int64(x)
   120  }
   121  func (x ValAndOff) String() string {
   122  	return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
   123  }
   124  
   125  // validVal reports whether the value can be used
   126  // as an argument to makeValAndOff.
   127  func validVal(val int64) bool {
   128  	return val == int64(int32(val))
   129  }
   130  
   131  // validOff reports whether the offset can be used
   132  // as an argument to makeValAndOff.
   133  func validOff(off int64) bool {
   134  	return off == int64(int32(off))
   135  }
   136  
   137  // validValAndOff reports whether we can fit the value and offset into
   138  // a ValAndOff value.
   139  func validValAndOff(val, off int64) bool {
   140  	if !validVal(val) {
   141  		return false
   142  	}
   143  	if !validOff(off) {
   144  		return false
   145  	}
   146  	return true
   147  }
   148  
   149  // makeValAndOff encodes a ValAndOff into an int64 suitable for storing in an AuxInt field.
   150  func makeValAndOff(val, off int64) int64 {
   151  	if !validValAndOff(val, off) {
   152  		panic("invalid makeValAndOff")
   153  	}
   154  	return ValAndOff(val<<32 + int64(uint32(off))).Int64()
   155  }
   156  
   157  // offOnly returns the offset half of ValAndOff vo.
   158  // It is intended for use in rewrite rules.
   159  func offOnly(vo int64) int64 {
   160  	return ValAndOff(vo).Off()
   161  }
   162  
   163  // valOnly returns the value half of ValAndOff vo.
   164  // It is intended for use in rewrite rules.
   165  func valOnly(vo int64) int64 {
   166  	return ValAndOff(vo).Val()
   167  }
   168  
   169  func (x ValAndOff) canAdd(off int64) bool {
   170  	newoff := x.Off() + off
   171  	return newoff == int64(int32(newoff))
   172  }
   173  
   174  func (x ValAndOff) add(off int64) int64 {
   175  	if !x.canAdd(off) {
   176  		panic("invalid ValAndOff.add")
   177  	}
   178  	return makeValAndOff(x.Val(), x.Off()+off)
   179  }
   180  
   181  type BoundsKind uint8
   182  
   183  const (
   184  	BoundsIndex       BoundsKind = iota // indexing operation, 0 <= idx < len failed
   185  	BoundsIndexU                        // ... with unsigned idx
   186  	BoundsSliceAlen                     // 2-arg slicing operation, 0 <= high <= len failed
   187  	BoundsSliceAlenU                    // ... with unsigned high
   188  	BoundsSliceAcap                     // 2-arg slicing operation, 0 <= high <= cap failed
   189  	BoundsSliceAcapU                    // ... with unsigned high
   190  	BoundsSliceB                        // 2-arg slicing operation, 0 <= low <= high failed
   191  	BoundsSliceBU                       // ... with unsigned low
   192  	BoundsSlice3Alen                    // 3-arg slicing operation, 0 <= max <= len failed
   193  	BoundsSlice3AlenU                   // ... with unsigned max
   194  	BoundsSlice3Acap                    // 3-arg slicing operation, 0 <= max <= cap failed
   195  	BoundsSlice3AcapU                   // ... with unsigned max
   196  	BoundsSlice3B                       // 3-arg slicing operation, 0 <= high <= max failed
   197  	BoundsSlice3BU                      // ... with unsigned high
   198  	BoundsSlice3C                       // 3-arg slicing operation, 0 <= low <= high failed
   199  	BoundsSlice3CU                      // ... with unsigned low
   200  	BoundsKindCount
   201  )
   202  
   203  // boundsAPI determines which register arguments a bounds check call should use. For an [a:b:c] slice, we do:
   204  //   CMPQ c, cap
   205  //   JA   fail1
   206  //   CMPQ b, c
   207  //   JA   fail2
   208  //   CMPQ a, b
   209  //   JA   fail3
   210  //
   211  // fail1: CALL panicSlice3Acap (c, cap)
   212  // fail2: CALL panicSlice3B (b, c)
   213  // fail3: CALL panicSlice3C (a, b)
   214  //
   215  // When we register allocate that code, we want the same register to be used for
   216  // the first arg of panicSlice3Acap and the second arg to panicSlice3B. That way,
   217  // initializing that register once will satisfy both calls.
   218  // That desire ends up dividing the set of bounds check calls into 3 sets. This function
   219  // determines which set to use for a given panic call.
   220  // The first arg for set 0 should be the second arg for set 1.
   221  // The first arg for set 1 should be the second arg for set 2.
   222  func boundsABI(b int64) int {
   223  	switch BoundsKind(b) {
   224  	case BoundsSlice3Alen,
   225  		BoundsSlice3AlenU,
   226  		BoundsSlice3Acap,
   227  		BoundsSlice3AcapU:
   228  		return 0
   229  	case BoundsSliceAlen,
   230  		BoundsSliceAlenU,
   231  		BoundsSliceAcap,
   232  		BoundsSliceAcapU,
   233  		BoundsSlice3B,
   234  		BoundsSlice3BU:
   235  		return 1
   236  	case BoundsIndex,
   237  		BoundsIndexU,
   238  		BoundsSliceB,
   239  		BoundsSliceBU,
   240  		BoundsSlice3C,
   241  		BoundsSlice3CU:
   242  		return 2
   243  	default:
   244  		panic("bad BoundsKind")
   245  	}
   246  }
   247  

View as plain text