Home | History | Annotate | Download | only in 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 	symEffect         SymEffect // effect this op has on symbol in aux
     39 }
     40 
     41 type inputInfo struct {
     42 	idx  int     // index in Args array
     43 	regs regMask // allowed input registers
     44 }
     45 
     46 type outputInfo struct {
     47 	idx  int     // index in output tuple
     48 	regs regMask // allowed output registers
     49 }
     50 
     51 type regInfo struct {
     52 	inputs   []inputInfo // ordered in register allocation order
     53 	clobbers regMask
     54 	outputs  []outputInfo // ordered in register allocation order
     55 }
     56 
     57 type auxType int8
     58 
     59 const (
     60 	auxNone         auxType = iota
     61 	auxBool                 // auxInt is 0/1 for false/true
     62 	auxInt8                 // auxInt is an 8-bit integer
     63 	auxInt16                // auxInt is a 16-bit integer
     64 	auxInt32                // auxInt is a 32-bit integer
     65 	auxInt64                // auxInt is a 64-bit integer
     66 	auxInt128               // auxInt represents a 128-bit integer.  Always 0.
     67 	auxFloat32              // auxInt is a float32 (encoded with math.Float64bits)
     68 	auxFloat64              // auxInt is a float64 (encoded with math.Float64bits)
     69 	auxString               // aux is a string
     70 	auxSym                  // aux is a symbol (a *gc.Node for locals or an *obj.LSym for globals)
     71 	auxSymOff               // aux is a symbol, auxInt is an offset
     72 	auxSymValAndOff         // aux is a symbol, auxInt is a ValAndOff
     73 	auxTyp                  // aux is a type
     74 	auxTypSize              // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt
     75 
     76 	auxSymInt32 // aux is a symbol, auxInt is a 32-bit integer
     77 )
     78 
     79 // A SymEffect describes the effect that an SSA Value has on the variable
     80 // identified by the symbol in its Aux field.
     81 type SymEffect int8
     82 
     83 const (
     84 	SymRead SymEffect = 1 << iota
     85 	SymWrite
     86 	SymAddr
     87 
     88 	SymRdWr = SymRead | SymWrite
     89 
     90 	SymNone SymEffect = 0
     91 )
     92 
     93 // A ValAndOff is used by the several opcodes. It holds
     94 // both a value and a pointer offset.
     95 // A ValAndOff is intended to be encoded into an AuxInt field.
     96 // The zero ValAndOff encodes a value of 0 and an offset of 0.
     97 // The high 32 bits hold a value.
     98 // The low 32 bits hold a pointer offset.
     99 type ValAndOff int64
    100 
    101 func (x ValAndOff) Val() int64 {
    102 	return int64(x) >> 32
    103 }
    104 func (x ValAndOff) Off() int64 {
    105 	return int64(int32(x))
    106 }
    107 func (x ValAndOff) Int64() int64 {
    108 	return int64(x)
    109 }
    110 func (x ValAndOff) String() string {
    111 	return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
    112 }
    113 
    114 // validVal reports whether the value can be used
    115 // as an argument to makeValAndOff.
    116 func validVal(val int64) bool {
    117 	return val == int64(int32(val))
    118 }
    119 
    120 // validOff reports whether the offset can be used
    121 // as an argument to makeValAndOff.
    122 func validOff(off int64) bool {
    123 	return off == int64(int32(off))
    124 }
    125 
    126 // validValAndOff reports whether we can fit the value and offset into
    127 // a ValAndOff value.
    128 func validValAndOff(val, off int64) bool {
    129 	if !validVal(val) {
    130 		return false
    131 	}
    132 	if !validOff(off) {
    133 		return false
    134 	}
    135 	return true
    136 }
    137 
    138 // makeValAndOff encodes a ValAndOff into an int64 suitable for storing in an AuxInt field.
    139 func makeValAndOff(val, off int64) int64 {
    140 	if !validValAndOff(val, off) {
    141 		panic("invalid makeValAndOff")
    142 	}
    143 	return ValAndOff(val<<32 + int64(uint32(off))).Int64()
    144 }
    145 
    146 func (x ValAndOff) canAdd(off int64) bool {
    147 	newoff := x.Off() + off
    148 	return newoff == int64(int32(newoff))
    149 }
    150 
    151 func (x ValAndOff) add(off int64) int64 {
    152 	if !x.canAdd(off) {
    153 		panic("invalid ValAndOff.add")
    154 	}
    155 	return makeValAndOff(x.Val(), x.Off()+off)
    156 }
    157