github.com/cloudwego/frugal@v0.1.15/internal/atm/hir/ir.go (about) 1 /* 2 * Copyright 2022 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package hir 18 19 import ( 20 `fmt` 21 `strings` 22 `unsafe` 23 24 `github.com/cloudwego/frugal/internal/rt` 25 ) 26 27 type ( 28 OpCode byte 29 Constness byte 30 Likeliness byte 31 ) 32 33 const ( 34 OP_nop OpCode = iota // no operation 35 OP_ip // ptr(Pr) -> Pd 36 OP_lb // u64(*(* u8)(Ps + Iv)) -> Rx 37 OP_lw // u64(*(*u16)(Ps + Iv)) -> Rx 38 OP_ll // u64(*(*u32)(Ps + Iv)) -> Rx 39 OP_lq // *(*u64)(Ps + Iv) -> Rx 40 OP_lp // *(*ptr)(Ps + Iv) -> Pd 41 OP_sb // u8(Rx) -> *(*u8)(Pd + Iv) 42 OP_sw // u16(Rx) -> *(*u16)(Pd + Iv) 43 OP_sl // u32(Rx) -> *(*u32)(Pd + Iv) 44 OP_sq // Rx -> *(*u64)(Pd + Iv) 45 OP_sp // Ps -> *(*ptr)(Pd + Iv) 46 OP_ldaq // arg[Iv] -> Rx 47 OP_ldap // arg[Iv] -> Pd 48 OP_addp // Ps + Rx -> Pd 49 OP_subp // Ps - Rx -> Pd 50 OP_addpi // Ps + Iv -> Pd 51 OP_add // Rx + Ry -> Rz 52 OP_sub // Rx - Ry -> Rz 53 OP_bts // Ry & (1 << (Rx % PTR_BITS)) != 0 -> Rz, Ry |= 1 << (Rx % PTR_BITS) 54 OP_addi // Rx + Iv -> Ry 55 OP_muli // Rx * Iv -> Ry 56 OP_andi // Rx & Iv -> Ry 57 OP_xori // Rx ^ Iv -> Ry 58 OP_shri // Rx >> Iv -> Ry 59 OP_bsi // Rx | (1 << Iv) -> Ry 60 OP_swapw // bswap16(Rx) -> Ry 61 OP_swapl // bswap32(Rx) -> Ry 62 OP_swapq // bswap64(Rx) -> Ry 63 OP_sxlq // sign_extend_32_to_64(Rx) -> Ry 64 OP_beq // if (Rx == Ry) Br.PC -> PC 65 OP_bne // if (Rx != Ry) Br.PC -> PC 66 OP_blt // if (Rx < Ry) Br.PC -> PC 67 OP_bltu // if (u(Rx) < u(Ry)) Br.PC -> PC 68 OP_bgeu // if (u(Rx) >= u(Ry)) Br.PC -> PC 69 OP_beqp // if (Ps == Pd) Br.PC -> PC 70 OP_bnep // if (Ps == Pd) Br.PC -> PC 71 OP_bsw // if (u(Rx) < u(An)) Sw[u(Rx)].PC -> PC 72 OP_jmp // Br.PC -> PC 73 OP_bzero // memset(Pd, 0, Iv) 74 OP_bcopy // memcpy(Pd, Ps, Rx) 75 OP_ccall // call external C functions 76 OP_gcall // call external Go functions 77 OP_icall // call external Go iface methods 78 OP_ret // return from function 79 OP_break // trigger a debugger breakpoint 80 ) 81 82 const ( 83 Const Constness = iota 84 Volatile 85 ) 86 87 const ( 88 Likely Likeliness = iota 89 Unlikely 90 ) 91 92 type Ir struct { 93 Op OpCode 94 Rx GenericRegister 95 Ry GenericRegister 96 Rz GenericRegister 97 Ps PointerRegister 98 Pd PointerRegister 99 An uint8 100 Rn uint8 101 Ar [8]uint8 102 Rr [8]uint8 103 Iv int64 104 Pr unsafe.Pointer 105 Br *Ir 106 Ln *Ir 107 } 108 109 func (self *Ir) iv(v int64) *Ir { self.Iv = v; return self } 110 func (self *Ir) pr(v unsafe.Pointer) *Ir { self.Pr = v; return self } 111 func (self *Ir) rx(v GenericRegister) *Ir { self.Rx = v; return self } 112 func (self *Ir) ry(v GenericRegister) *Ir { self.Ry = v; return self } 113 func (self *Ir) rz(v GenericRegister) *Ir { self.Rz = v; return self } 114 func (self *Ir) ps(v PointerRegister) *Ir { self.Ps = v; return self } 115 func (self *Ir) pd(v PointerRegister) *Ir { self.Pd = v; return self } 116 117 func (self *Ir) constness(c Constness) *Ir { 118 if self.Op != OP_ip { 119 panic("constness only applicable to `OP_ip` instruction") 120 } else { 121 self.An = uint8(c) 122 return self 123 } 124 } 125 126 func (self *Ir) likeliness(p Likeliness) *Ir { 127 if !self.IsBranch() { 128 panic("likeliness only applicable to branch instructions") 129 } else if self.Op == OP_bsw { 130 panic("cannot specify likeliness for `OP_bsw`") 131 } else { 132 self.An = uint8(p) 133 return self 134 } 135 } 136 137 func (self *Ir) A0(v Register) *Ir { self.An, self.Ar[0] = 1, v.A(); return self } 138 func (self *Ir) A1(v Register) *Ir { self.An, self.Ar[1] = 2, v.A(); return self } 139 func (self *Ir) A2(v Register) *Ir { self.An, self.Ar[2] = 3, v.A(); return self } 140 func (self *Ir) A3(v Register) *Ir { self.An, self.Ar[3] = 4, v.A(); return self } 141 func (self *Ir) A4(v Register) *Ir { self.An, self.Ar[4] = 5, v.A(); return self } 142 func (self *Ir) A5(v Register) *Ir { self.An, self.Ar[5] = 6, v.A(); return self } 143 func (self *Ir) A6(v Register) *Ir { self.An, self.Ar[6] = 7, v.A(); return self } 144 func (self *Ir) A7(v Register) *Ir { self.An, self.Ar[7] = 8, v.A(); return self } 145 146 func (self *Ir) R0(v Register) *Ir { self.Rn, self.Rr[0] = 1, v.A(); return self } 147 func (self *Ir) R1(v Register) *Ir { self.Rn, self.Rr[1] = 2, v.A(); return self } 148 func (self *Ir) R2(v Register) *Ir { self.Rn, self.Rr[2] = 3, v.A(); return self } 149 func (self *Ir) R3(v Register) *Ir { self.Rn, self.Rr[3] = 4, v.A(); return self } 150 func (self *Ir) R4(v Register) *Ir { self.Rn, self.Rr[4] = 5, v.A(); return self } 151 func (self *Ir) R5(v Register) *Ir { self.Rn, self.Rr[5] = 6, v.A(); return self } 152 func (self *Ir) R6(v Register) *Ir { self.Rn, self.Rr[6] = 7, v.A(); return self } 153 func (self *Ir) R7(v Register) *Ir { self.Rn, self.Rr[7] = 8, v.A(); return self } 154 155 func (self *Ir) Const() *Ir { return self.constness(Const) } 156 func (self *Ir) Volatile() *Ir { return self.constness(Volatile) } 157 158 func (self *Ir) Likely() *Ir { return self.likeliness(Likely) } 159 func (self *Ir) Unlikely() *Ir { return self.likeliness(Unlikely) } 160 161 func (self *Ir) Free() { 162 freeInstr(self) 163 } 164 165 func (self *Ir) Switch() (p []*Ir) { 166 (*rt.GoSlice)(unsafe.Pointer(&p)).Ptr = self.Pr 167 (*rt.GoSlice)(unsafe.Pointer(&p)).Len = int(self.Iv) 168 (*rt.GoSlice)(unsafe.Pointer(&p)).Cap = int(self.Iv) 169 return 170 } 171 172 func (self *Ir) IsBranch() bool { 173 return self.Op >= OP_beq && self.Op <= OP_jmp 174 } 175 176 func (self *Ir) Constness() Constness { 177 if self.Op != OP_ip { 178 panic("constness only applicable to `OP_ip` instruction") 179 } else { 180 return Constness(self.An) 181 } 182 } 183 184 func (self *Ir) Likeliness() Likeliness { 185 if !self.IsBranch() { 186 panic("likeliness only applicable to branch instructions") 187 } else if self.Op == OP_bsw { 188 panic("`OP_bsw` does not have likeliness assigned") 189 } else { 190 return Likeliness(self.An) 191 } 192 } 193 194 func (self *Ir) formatCall() string { 195 return fmt.Sprintf( 196 "%s, %s", 197 self.formatArgs(&self.Ar, self.An), 198 self.formatArgs(&self.Rr, self.Rn), 199 ) 200 } 201 202 func (self *Ir) formatArgs(vv *[8]uint8, nb uint8) string { 203 i := uint8(0) 204 ret := make([]string, nb) 205 206 /* add each register */ 207 for i = 0; i < nb; i++ { 208 if v := vv[i]; (v & ArgPointer) == 0 { 209 ret[i] = "%" + GenericRegister(v & ArgMask).String() 210 } else { 211 ret[i] = "%" + PointerRegister(v & ArgMask).String() 212 } 213 } 214 215 /* compose the result */ 216 return fmt.Sprintf( 217 "{%s}", 218 strings.Join(ret, ", "), 219 ) 220 } 221 222 func (self *Ir) formatRefs(refs map[*Ir]string, v *Ir) string { 223 if vv, ok := refs[v]; ok { 224 return vv 225 } else { 226 return fmt.Sprintf("@%p", v) 227 } 228 } 229 230 func (self *Ir) formatTable(refs map[*Ir]string) string { 231 tab := self.Switch() 232 ret := make([]string, 0, self.Iv) 233 234 /* empty table */ 235 if self.Iv == 0 { 236 return "{}" 237 } 238 239 /* format every label */ 240 for i, lb := range tab { 241 if lb != nil { 242 ret = append(ret, fmt.Sprintf("%4ccase $%d: %s,\n", ' ', i, self.formatRefs(refs, lb))) 243 } 244 } 245 246 /* join them together */ 247 return fmt.Sprintf( 248 "{\n%s}", 249 strings.Join(ret, ""), 250 ) 251 } 252 253 func (self *Ir) Disassemble(refs map[*Ir]string) string { 254 switch self.Op { 255 case OP_nop : return "nop" 256 case OP_ip : return fmt.Sprintf("ip $%p, %%%s", self.Pr, self.Pd) 257 case OP_lb : return fmt.Sprintf("lb %d(%%%s), %%%s", self.Iv, self.Ps, self.Rx) 258 case OP_lw : return fmt.Sprintf("lw %d(%%%s), %%%s", self.Iv, self.Ps, self.Rx) 259 case OP_ll : return fmt.Sprintf("ll %d(%%%s), %%%s", self.Iv, self.Ps, self.Rx) 260 case OP_lq : return fmt.Sprintf("lq %d(%%%s), %%%s", self.Iv, self.Ps, self.Rx) 261 case OP_lp : return fmt.Sprintf("lp %d(%%%s), %%%s", self.Iv, self.Ps, self.Pd) 262 case OP_sb : return fmt.Sprintf("sb %%%s, %d(%%%s)", self.Rx, self.Iv, self.Pd) 263 case OP_sw : return fmt.Sprintf("sw %%%s, %d(%%%s)", self.Rx, self.Iv, self.Pd) 264 case OP_sl : return fmt.Sprintf("sl %%%s, %d(%%%s)", self.Rx, self.Iv, self.Pd) 265 case OP_sq : return fmt.Sprintf("sq %%%s, %d(%%%s)", self.Rx, self.Iv, self.Pd) 266 case OP_sp : return fmt.Sprintf("sp %%%s, %d(%%%s)", self.Ps, self.Iv, self.Pd) 267 case OP_ldaq : return fmt.Sprintf("ldaq $%d, %%%s", self.Iv, self.Rx) 268 case OP_ldap : return fmt.Sprintf("ldap $%d, %%%s", self.Iv, self.Pd) 269 case OP_addp : return fmt.Sprintf("addp %%%s, %%%s, %%%s", self.Ps, self.Rx, self.Pd) 270 case OP_subp : return fmt.Sprintf("subp %%%s, %%%s, %%%s", self.Ps, self.Rx, self.Pd) 271 case OP_addpi : return fmt.Sprintf("addpi %%%s, $%d, %%%s", self.Ps, self.Iv, self.Pd) 272 case OP_add : return fmt.Sprintf("add %%%s, %%%s, %%%s", self.Rx, self.Ry, self.Rz) 273 case OP_sub : return fmt.Sprintf("sub %%%s, %%%s, %%%s", self.Rx, self.Ry, self.Rz) 274 case OP_bts : return fmt.Sprintf("bts %%%s, %%%s, %%%s", self.Rx, self.Ry, self.Rz) 275 case OP_addi : return fmt.Sprintf("addi %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry) 276 case OP_muli : return fmt.Sprintf("muli %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry) 277 case OP_andi : return fmt.Sprintf("andi %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry) 278 case OP_xori : return fmt.Sprintf("xori %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry) 279 case OP_shri : return fmt.Sprintf("shri %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry) 280 case OP_bsi : return fmt.Sprintf("bsi %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry) 281 case OP_swapw : return fmt.Sprintf("swapw %%%s, %%%s", self.Rx, self.Ry) 282 case OP_swapl : return fmt.Sprintf("swapl %%%s, %%%s", self.Rx, self.Ry) 283 case OP_swapq : return fmt.Sprintf("swapq %%%s, %%%s", self.Rx, self.Ry) 284 case OP_sxlq : return fmt.Sprintf("sxlq %%%s, %%%s", self.Rx, self.Ry) 285 case OP_beq : return fmt.Sprintf("beq %%%s, %%%s, %s", self.Rx, self.Ry, self.formatRefs(refs, self.Br)) 286 case OP_bne : return fmt.Sprintf("bne %%%s, %%%s, %s", self.Rx, self.Ry, self.formatRefs(refs, self.Br)) 287 case OP_blt : return fmt.Sprintf("blt %%%s, %%%s, %s", self.Rx, self.Ry, self.formatRefs(refs, self.Br)) 288 case OP_bltu : return fmt.Sprintf("bltu %%%s, %%%s, %s", self.Rx, self.Ry, self.formatRefs(refs, self.Br)) 289 case OP_bgeu : return fmt.Sprintf("bgeu %%%s, %%%s, %s", self.Rx, self.Ry, self.formatRefs(refs, self.Br)) 290 case OP_beqp : return fmt.Sprintf("beq %%%s, %%%s, %s", self.Ps, self.Pd, self.formatRefs(refs, self.Br)) 291 case OP_bnep : return fmt.Sprintf("bne %%%s, %%%s, %s", self.Ps, self.Pd, self.formatRefs(refs, self.Br)) 292 case OP_bsw : return fmt.Sprintf("bsw %%%s, %s", self.Rx, self.formatTable(refs)) 293 case OP_jmp : return fmt.Sprintf("jmp %s", self.formatRefs(refs, self.Br)) 294 case OP_bzero : return fmt.Sprintf("bzero $%d, %s", self.Iv, self.Pd) 295 case OP_bcopy : return fmt.Sprintf("bcopy %%%s, %%%s, %%%s", self.Ps, self.Rx, self.Pd) 296 case OP_ccall : return fmt.Sprintf("ccall %s, %s", LookupCall(self.Iv), self.formatCall()) 297 case OP_gcall : return fmt.Sprintf("gcall %s, %s", LookupCall(self.Iv), self.formatCall()) 298 case OP_icall : return fmt.Sprintf("icall $%d, {%%%s, %%%s}, %s", LookupCall(self.Iv).Slot, self.Ps, self.Pd, self.formatCall()) 299 case OP_ret : return fmt.Sprintf("ret %s", self.formatArgs(&self.Rr, self.Rn)) 300 case OP_break : return "break" 301 default : panic(fmt.Sprintf("invalid OpCode: 0x%02x", self.Op)) 302 } 303 }