Created
April 4, 2020 22:30
-
-
Save tommythorn/a45433c01e20c2a01d6d5fa8d2acfb80 to your computer and use it in GitHub Desktop.
RVC Decoder aka. GCC destroyer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// RVC decoder, Copyright (C) 2020 Tommy Thorn | |
/* This file is based on RVC.scala, licensed under Apache License Version 2.0 */ | |
// *** WARNING *** | |
// This is work-in-progress | |
// Released just to show how it totally destroys GCC (~ 2 lines/s and | |
// 6 GiB working set) | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <assert.h> | |
uint32_t | |
rvcdecoder(uint32_t insn, int xlen) | |
{ | |
#define _sz(f) (0 ? f) | |
#define _da(f) (1 ? f) | |
#define pack(da,sz) da : sz | |
#define x(hi,lo) ((insn >> lo) & ((1 << (hi-lo+1))-1)) : hi-lo+1 | |
#define bf(v,hi,lo) ((_da(v) >> lo) & ((1 << (hi-lo+1))-1)) : hi-lo+1 | |
#define b(v,p) bf(v,p,p) | |
#define fill(n,a) (_da(a) ? (1<<n)-1 : 0) : n | |
#define cat2(a,b) (_da(a) << _sz(b)) + _da(b) : _sz(a) + _sz(b) | |
#define cat3(a,b,c) cat2(a,cat2(b,c)) | |
#define cat4(a,b,c,d) cat2(a,cat3(b,c,d)) | |
#define cat5(a,b,c,d,e) cat2(a,cat4(b,c,d,e)) | |
#define cat6(a,b,c,d,e,f) cat2(a,cat5(b,c,d,e,f)) | |
#define cat7(a,b,c,d,e,f,g) cat2(a,cat6(b,c,d,e,f,g)) | |
#define cat8(a,b,c,d,e,f,g,h) cat2(a,cat7(b,c,d,e,f,g,h)) | |
#define cat9(a,b,c,d,e,f,g,h,i) cat2(a,cat8(b,c,d,e,f,g,h,i)) | |
#define rs1p cat2(pack(1,2), x(9,7)) | |
#define rs2p cat2(pack(1,2), x(4,2)) | |
#define rs2 x(6,2) | |
#define rd x(11,7) | |
#define addi4spnImm cat5(x(10,7), x(12,11), x(5,5), x(6,6), pack(0,2)) | |
#define lwImm cat4(x(5,5), x(12,10), x(6,6), pack(0,2)) | |
#define ldImm cat3(x(6,5), x(12,10), pack(0,3)) | |
#define lwspImm cat4(x(3,2), x(12,12), x(6,4), pack(0,2)) | |
#define ldspImm cat4(x(4,2), x(12,12), x(6,5), pack(0,3)) | |
#define swspImm cat3(x(8,7), x(12,9), pack(0,2)) | |
#define sdspImm cat3(x(9,7), x(12,10), pack(0,3)) | |
#define luiImm cat3(fill(15, x(12,12)), x(6,2), pack(0,12)) | |
#define addi16spImm cat6(fill(3, x(12,12)), x(4,3), x(5,5), x(2,2), x(6,6), pack(0,4)) | |
#define addiImm cat2(fill(7, x(12,12)), x(6,2)) | |
#define jImm cat9(fill(10, x(12,12)), x(8,8), x(10,9), x(6,6), x(7,7), x(2,2), x(11,11), x(5,3), pack(0,1)) | |
#define bImm cat6(fill(5, x(12,12)), x(6,5), x(2,2), x(11,10), x(4,3), pack(0,1)) | |
#define shamt cat2(x(12,12), x(6,2)) | |
#define x0 pack(0,5) | |
#define ra pack(1,5) | |
#define sp pack(2,5) | |
#define ld cat5(ldImm, rs1p, pack(3,3), rs2p, pack(3,7)) | |
#define lw cat5(lwImm, rs1p, pack(2,3), rs2p, pack(3,7)) | |
#define fld cat5(ldImm, rs1p, pack(3,3), rs2p, pack(7,7)) | |
#define flw cat5(lwImm, rs1p, pack(2,3), rs2p, pack(7,7)) | |
#define sd cat6(bf(ldImm,7,5), rs2p, rs1p, pack(3,3), bf(ldImm,4,0), pack(0x23,7)) | |
#define sw cat6(bf(lwImm,6,5), rs2p, rs1p, pack(2,3), bf(lwImm,4,0), pack(0x23,7)) | |
#define fsd cat6(bf(ldImm,7,5), rs2p, rs1p, pack(3,3), bf(ldImm,4,0), pack(0x27,7)) | |
#define fsw cat6(bf(lwImm,6,5), rs2p, rs1p, pack(2,3), bf(lwImm,4,0), pack(0x27,7)) | |
switch (_da(cat2(x(1,0), x(15,13)))) { | |
// Q0 | |
case 0: { | |
uint32_t opc = _da(x(12,5)) ? 0x13 : 0x1F; | |
return _da(cat5(addi4spnImm, sp, pack(0,3), rs2p, pack(opc,7))); | |
} | |
case 1: return _da(fld); | |
case 2: return _da(lw); | |
case 3: return xlen == 32 ? _da(flw) : _da(ld); | |
case 4: { | |
// uimp | |
return _da(cat6(bf(lwImm,6,5), rs2p, rs1p, pack(2,3), bf(lwImm,4,0), pack(0x3F,7))); | |
} | |
case 5: return _da(fsd); | |
case 6: return _da(sw); | |
case 7: return xlen == 32 ? _da(fsw) : _da(sd); | |
// Q1 | |
case 8: return _da(cat5(addiImm, rd, pack(0,3), rd, pack(0x13, 7))); | |
case 9: | |
if (xlen == 32) | |
return _da(cat6(b(jImm,20), bf(jImm,10,1), b(jImm,11), bf(jImm,19,12), ra, pack(0x6F,7))); | |
return _da(cat5(addiImm, rd, pack(0,3), rd, pack(_da(rd) ? 0x1B : 0x1F,7))); | |
case 10: return _da(cat5(addiImm, x0, pack(0,3), rd, pack(0x13,7))); | |
case 11: | |
if (_da(rd) == 0 || _da(rd) == 2) { | |
int opc = _da(addiImm) ? 0x13 : 0x1F; | |
return _da(cat5(addi16spImm, rd, pack(0,3), rd, pack(opc,7))); | |
} else { | |
int opc = _da(addiImm) ? 0x37 : 0x3F; | |
return _da(cat3(bf(luiImm,31,12), rd, pack(opc,7))); | |
} | |
case 12: | |
// arith | |
switch (_da(x(11,10))) { | |
case 0: return _da(cat5(shamt, rs1p, pack(5,3), rs1p, pack(0x13,7))); // srli | |
case 1: return _da(cat5(shamt, rs1p, pack(5,3), rs1p, pack(0x13,7))) | 1<<30; // srai | |
case 2: return _da(cat5(addiImm, rs1p, pack(7,3), rs1p, pack(0x13,7))); // andi | |
case 3: { // rtype | |
// val funct = Seq(0.U, 4.U, 6.U, 7.U, 0.U, 0.U, 2.U, 3.U)(Cat(x(12), x(6,5))) | |
uint32_t funct = 0x04670023 >> _da(cat3(x(12,12),x(6,5),pack(0,4))) & 0xF; | |
uint32_t sub = _da(x(6,5)) == 0 ? 1 << 30 : 0; | |
uint32_t opc = _da(x(12,12)) ? 0x3B : 0x33; | |
return _da(cat5(rs2p, rs1p, pack(funct, 3), rs1p, pack(opc, 7))) | sub; | |
}} | |
case 13: return _da(cat6(b(jImm,20), bf(jImm,10,1), b(jImm,11), bf(jImm,19,12), x0, pack(0x6F,7))); | |
case 14: return _da(cat8(b(bImm,12), bf(bImm,10,5), x0, rs1p, pack(0,3), bf(bImm,4,1), bf(bImm,11,11), pack(0x63,7))); | |
case 15: return _da(cat8(b(bImm,12), bf(bImm,10,5), x0, rs1p, pack(1,3), bf(bImm,4,1), bf(bImm,11,11), pack(0x63,7))); | |
default: return insn; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The solution is to trust the optimizer and use
etc. All the constants gets eliminated and we end up with a good result.