1 #include "l.h" 2 3 #define COMPREG(r) ((r & ~0x7) == 0x8) 4 #define COP_CR(op,rs,rd)\ 5 (op | (rs)<<2 | (rd)<<7) 6 #define COP_CI(op,rd,i)\ 7 (op | (rd)<<7 | ((i)&0x20)<<7 | ((i)&0x1F)<<2) 8 #define COP_CIW(op,rd,i)\ 9 (op | (rd)<<2 | (i)<<5) 10 #define COP_CJ(op,i)\ 11 (op | (i)<<2) 12 #define COP_CB(op,rs,i)\ 13 (op | (rs)<<7 | ((i)&0x1f)<<2 | ((i)&0xE0)<<5) 14 #define COP_CL(op,rs,rd,i)\ 15 (op | (rs)<<7 | (rd)<<2 | ((i)&0x7)<<4 | ((i)&0x38)<<7) 16 #define COP_CSS(op,rs,i)\ 17 (op | (rs)<<2 | ((i)&0x3F)<<7) 18 #define COP_CS(op,rs2,rs1,i)\ 19 (op | (rs2)<<2 | (rs1)<<7 | ((i)&0x7)<<4 | ((i)&0x38)<<7) 20 21 static int 22 immbits(int v, char *permute) 23 { 24 int r, i, c; 25 26 r = 0; 27 for(i = 0; (c = *permute++) != 0; i++) 28 r |= ((v>>c) & 0x01) << i; 29 return r; 30 } 31 32 long 33 asmcjmp(int a, Prog *p, int first) 34 { 35 long v; 36 37 if(p->cond == P) 38 v = 0; 39 else 40 v = (p->cond->pc - p->pc); 41 if(first || ((v&0x01) == 0 && v >= -0x800 && v < 0x800)) 42 return COP_CJ(a, immbits(v, "\5\1\2\3\7\6\12\10\11\4\13")); 43 return 0; 44 } 45 46 int 47 asmcbz(int a, Prog *p, int first) 48 { 49 long v; 50 int r; 51 52 r = p->reg; 53 if(r == REGZERO || r == NREG) 54 r = p->from.reg; 55 else if(p->from.reg != REGZERO) 56 return 0; 57 if(!COMPREG(r)) 58 return 0; 59 if(p->cond == P) 60 v = 0; 61 else 62 v = (p->cond->pc - p->pc); 63 if(first || ((v&0x01) == 0 && v >= -0x100 && v < 0x100)) 64 return COP_CB(a, r&0x7, immbits(v, "\5\1\2\6\7\3\4\10")); 65 return 0; 66 } 67 68 int 69 asmcload(Prog *p, int a, uint len, uint maxoff) 70 { 71 int v; 72 int r; 73 74 v = regoff(&p->from); 75 if((v & (len-1)) != 0 || v < 0) 76 return 0; 77 r = classreg(&p->from); 78 if(COMPREG(r) && COMPREG(p->to.reg)){ 79 if(v < maxoff){ 80 v |= (v>>5) & ~0x1; 81 return COP_CL(a, r&0x7, p->to.reg&0x7, v); 82 } 83 }else if(r == REGSP){ 84 if(v < 2*maxoff){ 85 v |= (v>>6); 86 return COP_CI(a | 0x2, p->to.reg, v); 87 } 88 } 89 return 0; 90 } 91 92 int 93 asmcstore(Prog *p, int a, uint len, uint maxoff) 94 { 95 int v; 96 int r; 97 98 v = regoff(&p->to); 99 if((v & (len-1)) != 0 || v < 0) 100 return 0; 101 r = classreg(&p->to); 102 if(COMPREG(r) && COMPREG(p->from.reg)){ 103 if(v < maxoff){ 104 v |= (v>>5) & ~0x1; 105 return COP_CS(a, p->from.reg&0x7, r&0x7, v); 106 } 107 }else if(r == REGSP){ 108 if(v < 2*maxoff){ 109 v |= (v>>6); 110 return COP_CSS(a | 0x2, (p->from.reg&0x1F), v); 111 } 112 } 113 return 0; 114 } 115 116 int 117 asmcompressed(Prog *p, Optab *o, int r, int first) 118 { 119 long v; 120 int a; 121 122 switch(o->ctype){ 123 case 1: /* C.ADD */ 124 if(p->from.reg != REGZERO && p->to.reg != REGZERO && r == p->to.reg) 125 return COP_CR(0x9002, p->from.reg, r); 126 break; 127 case 2: /* C.MV */ 128 if(p->from.type != D_REG) 129 diag("compress MOVW R,R doesn't apply\n%P", p); 130 if(p->to.reg != REGZERO){ 131 if(p->from.type == D_REG && p->from.reg != REGZERO) 132 return COP_CR(0x8002, p->from.reg, p->to.reg); 133 else 134 return COP_CI(0x4001, p->to.reg, 0); 135 } 136 break; 137 case 3: /* C.JALR */ 138 if(r == REGLINK && p->to.reg != REGZERO && p->to.offset == 0) 139 return COP_CR(0x9002, 0, p->to.reg); 140 break; 141 case 4: /* C.JR */ 142 if(p->to.reg != REGZERO &&p->to.offset == 0) 143 return COP_CR(0x8002, 0, p->to.reg); 144 break; 145 case 5: /* C.AND C.OR C.SUB C.XOR */ 146 if(r == p->to.reg && COMPREG(p->from.reg) && COMPREG(p->to.reg)){ 147 v = 0x8C01; 148 switch(o->as){ 149 case AXOR: 150 v |= 1<<5; 151 break; 152 case AOR: 153 v |= 2<<5; 154 break; 155 case AAND: 156 v |= 3<<5; 157 break; 158 } 159 return COP_CR(v, p->from.reg&0x7, p->to.reg&0x7); 160 } 161 break; 162 case 6: /* C.LI */ 163 v = p->from.offset; 164 if(p->to.reg != REGZERO && v >= -0x20 && v < 0x20){ 165 return COP_CI(0x4001, p->to.reg, v); 166 } 167 break; 168 case 7: /* C.LUI */ 169 v = p->from.offset; 170 if((v&0xFFF) != 0) 171 return 0; 172 v >>= 12; 173 if(p->to.reg != REGZERO && p->to.reg != REGSP && v >= -0x20 && v < 0x20) 174 return COP_CI(0x6001, p->to.reg, v); 175 break; 176 case 8: /* C.SLLI */ 177 v = p->from.offset; 178 if((v & 0x20) != 0 && thechar == 'i') 179 break; 180 if(r == p->to.reg && r != REGZERO && v != 0 && (v & ~0x3F) == 0) 181 return COP_CI(0x0002, p->to.reg, v); 182 break; 183 case 9: /* C.SRAI C.SRLI */ 184 v = p->from.offset; 185 if((v & 0x20) != 0 && thechar == 'i') 186 break; 187 a = (o->as == ASRA) << 10; 188 if(r == p->to.reg && COMPREG(r) && v != 0 && (v & ~0x3F) == 0) 189 return COP_CI(0x8001 | a, r&0x7, v); 190 break; 191 case 10: /* C.ADDI C.ADDI16SP C.ADDI4SPN C.NOP */ 192 v = p->from.offset; 193 if(r == p->to.reg && r != REGZERO && v != 0 && v >= -0x20 && v < 0x20) 194 return COP_CI(0x0001, p->to.reg, v); 195 if(r == p->to.reg && r == REGSP && v != 0 && (v&0xF) == 0 && v >= -0x200 && v < 0x200) 196 return COP_CI(0x6001, REGSP, immbits(v, "\5\7\10\6\4\11")); 197 if(r == REGSP && COMPREG(p->to.reg) && (v&0x3) == 0 && v > 0 && v < 0x400) 198 return COP_CIW(0x0000, p->to.reg&0x7, immbits(v, "\3\2\6\7\10\11\4\5")); 199 if(r == p->to.reg && r == REGZERO && v == 0) 200 return COP_CI(0x0001, 0, 0); 201 break; 202 case 11: /* C.JAL (rv32) */ 203 if(thechar != 'i') 204 break; 205 if(r == REGLINK) 206 return asmcjmp(0x2001, p, first); 207 break; 208 case 12: /* C.J */ 209 return asmcjmp(0xA001, p, first); 210 break; 211 case 13: /* C.ANDI */ 212 v = p->from.offset; 213 if(r == p->to.reg && COMPREG(r) && v >= -0x20 && v < 0x20) 214 return COP_CI(0x8801, r&0x7, v); 215 break; 216 case 14: /* C.BEQZ */ 217 return asmcbz(0xC001, p, first); 218 case 15: /* C.BNEZ */ 219 return asmcbz(0xE001, p, first); 220 case 16: /* C.LW C.LWSP */ 221 return asmcload(p, 0x4000, 4, 0x80); 222 case 17: /* C.FLW, C.FLWSP (rv32) */ 223 if(thechar != 'i') 224 break; 225 return asmcload(p, 0x6000, 4, 0x80); 226 case 18: /* C.FLD, C.FLDSP */ 227 return asmcload(p, 0x2000, 8, 0x100); 228 case 19: /* C.SW C.SWSP */ 229 return asmcstore(p, 0xC000, 4, 0x80); 230 case 20: /* C.FSW, C.FSWSP (rv32) */ 231 if(thechar != 'i') 232 break; 233 return asmcstore(p, 0xE000, 4, 0x80); 234 case 21: /* C.FSD, C.FSDSP */ 235 return asmcstore(p, 0xA000, 8, 0x100); 236 case 22: /* C.ADDW C.SUBW (rv64) */ 237 if(thechar != 'j') 238 break; 239 if(r == p->to.reg && COMPREG(p->from.reg) && COMPREG(p->to.reg)){ 240 v = 0x9C01; 241 switch(o->as){ 242 case AADDW: 243 v |= 1<<5; 244 break; 245 } 246 return COP_CR(v, p->from.reg&0x7, p->to.reg&0x7); 247 } 248 break; 249 case 23: /* C.ADDIW (rv64) */ 250 if(thechar != 'j') 251 break; 252 v = p->from.offset; 253 if(p->as == AMOVW){ 254 v = 0; 255 r = p->from.reg; 256 } 257 if(r == p->to.reg && r != REGZERO && v >= -0x20 && v < 0x20) 258 return COP_CI(0x2001, p->to.reg, v); 259 break; 260 case 24: /* C.LD (rv64) */ 261 if(thechar != 'j') 262 break; 263 return asmcload(p, 0x6000, 8, 0x100); 264 case 25: /* C.SD (rv64) */ 265 if(thechar != 'j') 266 break; 267 return asmcstore(p, 0xE000, 8, 0x100); 268 } 269 return 0; 270 } 271