...

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

     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