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