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