github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/isa/arm64/cond.go (about) 1 package arm64 2 3 import ( 4 "strconv" 5 6 "github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc" 7 "github.com/tetratelabs/wazero/internal/engine/wazevo/ssa" 8 ) 9 10 type ( 11 cond uint64 12 condKind byte 13 ) 14 15 const ( 16 // condKindRegisterZero represents a condition which checks if the register is zero. 17 // This indicates that the instruction must be encoded as CBZ: 18 // https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/CBZ--Compare-and-Branch-on-Zero- 19 condKindRegisterZero condKind = iota 20 // condKindRegisterNotZero indicates that the instruction must be encoded as CBNZ: 21 // https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/CBNZ--Compare-and-Branch-on-Nonzero- 22 condKindRegisterNotZero 23 // condKindCondFlagSet indicates that the instruction must be encoded as B.cond: 24 // https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/B-cond--Branch-conditionally- 25 condKindCondFlagSet 26 ) 27 28 // kind returns the kind of condition which is stored in the first two bits. 29 func (c cond) kind() condKind { 30 return condKind(c & 0b11) 31 } 32 33 func (c cond) asUint64() uint64 { 34 return uint64(c) 35 } 36 37 // register returns the register for register conditions. 38 // This panics if the condition is not a register condition (condKindRegisterZero or condKindRegisterNotZero). 39 func (c cond) register() regalloc.VReg { 40 if c.kind() != condKindRegisterZero && c.kind() != condKindRegisterNotZero { 41 panic("condition is not a register") 42 } 43 return regalloc.VReg(c >> 2) 44 } 45 46 func registerAsRegZeroCond(r regalloc.VReg) cond { 47 return cond(r)<<2 | cond(condKindRegisterZero) 48 } 49 50 func registerAsRegNotZeroCond(r regalloc.VReg) cond { 51 return cond(r)<<2 | cond(condKindRegisterNotZero) 52 } 53 54 func (c cond) flag() condFlag { 55 if c.kind() != condKindCondFlagSet { 56 panic("condition is not a flag") 57 } 58 return condFlag(c >> 2) 59 } 60 61 func (c condFlag) asCond() cond { 62 return cond(c)<<2 | cond(condKindCondFlagSet) 63 } 64 65 // condFlag represents a condition flag for conditional branches. 66 // The value matches the encoding of condition flags in the ARM64 instruction set. 67 // https://developer.arm.com/documentation/den0024/a/The-A64-instruction-set/Data-processing-instructions/Conditional-instructions 68 type condFlag uint8 69 70 const ( 71 eq condFlag = iota // eq represents "equal" 72 ne // ne represents "not equal" 73 hs // hs represents "higher or same" 74 lo // lo represents "lower" 75 mi // mi represents "minus or negative result" 76 pl // pl represents "plus or positive result" 77 vs // vs represents "overflow set" 78 vc // vc represents "overflow clear" 79 hi // hi represents "higher" 80 ls // ls represents "lower or same" 81 ge // ge represents "greater or equal" 82 lt // lt represents "less than" 83 gt // gt represents "greater than" 84 le // le represents "less than or equal" 85 al // al represents "always" 86 nv // nv represents "never" 87 ) 88 89 // invert returns the inverted condition. 90 func (c condFlag) invert() condFlag { 91 switch c { 92 case eq: 93 return ne 94 case ne: 95 return eq 96 case hs: 97 return lo 98 case lo: 99 return hs 100 case mi: 101 return pl 102 case pl: 103 return mi 104 case vs: 105 return vc 106 case vc: 107 return vs 108 case hi: 109 return ls 110 case ls: 111 return hi 112 case ge: 113 return lt 114 case lt: 115 return ge 116 case gt: 117 return le 118 case le: 119 return gt 120 case al: 121 return nv 122 case nv: 123 return al 124 default: 125 panic(c) 126 } 127 } 128 129 // String implements fmt.Stringer. 130 func (c condFlag) String() string { 131 switch c { 132 case eq: 133 return "eq" 134 case ne: 135 return "ne" 136 case hs: 137 return "hs" 138 case lo: 139 return "lo" 140 case mi: 141 return "mi" 142 case pl: 143 return "pl" 144 case vs: 145 return "vs" 146 case vc: 147 return "vc" 148 case hi: 149 return "hi" 150 case ls: 151 return "ls" 152 case ge: 153 return "ge" 154 case lt: 155 return "lt" 156 case gt: 157 return "gt" 158 case le: 159 return "le" 160 case al: 161 return "al" 162 case nv: 163 return "nv" 164 default: 165 panic(strconv.Itoa(int(c))) 166 } 167 } 168 169 // condFlagFromSSAIntegerCmpCond returns the condition flag for the given ssa.IntegerCmpCond. 170 func condFlagFromSSAIntegerCmpCond(c ssa.IntegerCmpCond) condFlag { 171 switch c { 172 case ssa.IntegerCmpCondEqual: 173 return eq 174 case ssa.IntegerCmpCondNotEqual: 175 return ne 176 case ssa.IntegerCmpCondSignedLessThan: 177 return lt 178 case ssa.IntegerCmpCondSignedGreaterThanOrEqual: 179 return ge 180 case ssa.IntegerCmpCondSignedGreaterThan: 181 return gt 182 case ssa.IntegerCmpCondSignedLessThanOrEqual: 183 return le 184 case ssa.IntegerCmpCondUnsignedLessThan: 185 return lo 186 case ssa.IntegerCmpCondUnsignedGreaterThanOrEqual: 187 return hs 188 case ssa.IntegerCmpCondUnsignedGreaterThan: 189 return hi 190 case ssa.IntegerCmpCondUnsignedLessThanOrEqual: 191 return ls 192 default: 193 panic(c) 194 } 195 } 196 197 // condFlagFromSSAFloatCmpCond returns the condition flag for the given ssa.FloatCmpCond. 198 func condFlagFromSSAFloatCmpCond(c ssa.FloatCmpCond) condFlag { 199 switch c { 200 case ssa.FloatCmpCondEqual: 201 return eq 202 case ssa.FloatCmpCondNotEqual: 203 return ne 204 case ssa.FloatCmpCondLessThan: 205 return mi 206 case ssa.FloatCmpCondLessThanOrEqual: 207 return ls 208 case ssa.FloatCmpCondGreaterThan: 209 return gt 210 case ssa.FloatCmpCondGreaterThanOrEqual: 211 return ge 212 default: 213 panic(c) 214 } 215 }