in vm/jitrino/src/codegenerator/ipf/IpfEncoder.cpp [613:1146]
uint64 Encoder::getInstBits(InstructionType unit, Inst * inst) {
InstCode icode = inst->getInstCode();
OpndVector & opnds = inst->getOpnds();
CompVector & cmpls = inst->getComps();
int opndcount = opnds.size();
int cmplcount = cmpls.size();
uint64 qp = opnds[0]->getValue();
uint64 instbits = 0;
switch (icode) {
// special cases
case INST_NOP:
return getNopBits(unit, qp, opnds[1]->getValue());
case INST_HINT:
return getHintBits(unit, qp, opnds[1]->getValue());
case INST_BREAK:
return getBreakBits(unit, qp, opnds[1]->getValue());
case INST_BREAKPOINT:
return getBreakBits(unit, qp, INST_BREAKPOINT_IMM_VALUE);
// start insts processing
case INST_ADD:
if( opndcount == 5 ) { // add r1 = r2, r3, 1
return A1(0, 1, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
} else { // add r1 = r2, r3
return A1(0, 0, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
}
case INST_ADDS: // opnds[2]->getOpndKind() == OPND_IMM14
return A4(2, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_ADDL: // opnds[2]->getOpndKind() == OPND_IMM22
return A5(opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_ADDP4:
if (opnds[2]->getOpndKind() == OPND_G_REG) {
return A1(2, 0, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
} else {
return A4(3, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
}
case INST_ALLOC:
{
uint64 i, l, o, r, sof, sol, sor, r1;
r1 = opnds[1]->getValue();
i = opnds[2]->getValue();
l = opnds[3]->getValue();
o = opnds[4]->getValue();
r = opnds[5]->getValue();
sof = i + l + o;
sol = i +l;
sor = r >> 3;
return M34(sor, sol, sof, r1, qp);
}
case INST_AND:
case INST_ANDCM:
case INST_OR:
case INST_XOR:
case INST_SUB:
{
uint64 x4=3, x2b=0;
switch (icode) {
case INST_AND: x4=3; x2b=0; break;
case INST_ANDCM: x4=3; x2b=1; break;
case INST_OR: x4=3; x2b=2; break;
case INST_XOR: x4=3; x2b=3; break;
case INST_SUB: x4=1; if (opndcount == 5) x2b=0; else x2b=1; break;
default: assert(0); break;
}
if (opnds[2]->isImm(8)) {
x4 += 0x8;
return A3(x4, x2b, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
} else {
return A1(x4, x2b, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
}
}
case INST_CMP:
return cmp_cmp4(icode, inst, cmpls, opnds, qp);
case INST_CMP4:
return cmp_cmp4(icode, inst, cmpls, opnds, qp);
case INST_FABS:
return F9(0, 0x10, opnds[2]->getValue(), 0, opnds[1]->getValue(), qp);
case INST_FADD:
// pseudo-op of: (qp) fma.pc.sf f1 = f3, f1, f2
{
uint64 opcode=8, x=0, sf=0;
for (int i=0 ; i<cmplcount ; i++ ) {
switch (cmpls[i]) {
case CMPLT_PC_DYNAMIC: x=0; opcode=8; break;
case CMPLT_PC_SINGLE: x=1; opcode=8; break;
case CMPLT_PC_DOUBLE: x=0; opcode=9; break;
case CMPLT_SF0: sf=0; break;
case CMPLT_SF1: sf=1; break;
case CMPLT_SF2: sf=2; break;
case CMPLT_SF3: sf=3; break;
default: assert(0); break;
}
}
return F1(opcode, x, sf, 1, opnds[2]->getValue(), opnds[3]->getValue(), opnds[1]->getValue(), qp);
}
case INST_FNORM:
// (qp) fnorm.pc.sf f1 = f3 pseudo-op of: (qp) fma.pc.sf f1 = f3, f1, f0
{
uint64 opcode=8, x=0, sf=0;
for (int i=0 ; i<cmplcount ; i++ ) {
switch (cmpls[i]) {
case CMPLT_PC_DYNAMIC: x=0; opcode=8; break;
case CMPLT_PC_SINGLE: x=1; opcode=8; break;
case CMPLT_PC_DOUBLE: x=0; opcode=9; break;
case CMPLT_SF0: sf=0; break;
case CMPLT_SF1: sf=1; break;
case CMPLT_SF2: sf=2; break;
case CMPLT_SF3: sf=3; break;
default: assert(0); break;
}
}
return F1(opcode, x, sf, 1, opnds[2]->getValue(), 0, opnds[1]->getValue(), qp);
}
case INST_FAND:
return F9(0, 0x2C, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_FANDCM:
return F9(0, 0x2D, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_FC:
return M28(0, opnds[1]->getValue(), qp);
case INST_FC_I:
return M28(1, opnds[1]->getValue(), qp);
case INST_FCMP:
return fcmp(icode, inst, cmpls, opnds, qp);
case INST_FCLASS:
{
uint64 px, p1=opnds[1]->getValue(), p2=opnds[2]->getValue(), ta=0;
for (int i=0; i<cmplcount; ++i) {
if (cmpls[i]==CMPLT_FCMP_FCTYPE_UNC) { ta=1; }
else if (cmpls[i]==CMPLT_FCREL_NM) { px=p1; p1=p2; p2=px; }
}
return F5(opnds[4]->getValue(), p2, opnds[3]->getValue(), ta, p1, qp);
}
case INST_FCVT_FX:
case INST_FCVT_FXU:
case INST_FCVT_FX_TRUNC:
case INST_FCVT_FXU_TRUNC:
case INST_FPCVT_FX:
case INST_FPCVT_FXU:
case INST_FPCVT_FX_TRUNC:
case INST_FPCVT_FXU_TRUNC:
{
uint64 opcode=0, x6=0x18, sf=0;
if ( cmplcount==1 ) {
switch(cmpls[0]) {
case CMPLT_SF0: sf=0; break;
case CMPLT_SF1: sf=1; break;
case CMPLT_SF2: sf=2; break;
case CMPLT_SF3: sf=3; break;
default: assert(0); break;
}
}
switch (icode) {
case INST_FCVT_FX: opcode=0; x6=0x18; break;
case INST_FCVT_FXU: opcode=0; x6=0x19; break;
case INST_FCVT_FX_TRUNC: opcode=0; x6=0x1A; break;
case INST_FCVT_FXU_TRUNC: opcode=0; x6=0x1B; break;
case INST_FPCVT_FX: opcode=1; x6=0x18; break;
case INST_FPCVT_FXU: opcode=1; x6=0x19; break;
case INST_FPCVT_FX_TRUNC: opcode=1; x6=0x1A; break;
case INST_FPCVT_FXU_TRUNC: opcode=1; x6=0x1B; break;
default: assert(0); break;
}
return F10(opcode, sf, x6, opnds[2]->getValue(), opnds[1]->getValue(), qp);
}
case INST_FCVT_XF:
return F11(opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_FCVT_XUF:
case INST_FMA: {
uint64 opcode=0, x=0, pc=CMPLT_PC_DYNAMIC, sf=CMPLT_SF0;
if ( cmpls.size()==2 ) {
pc=cmpls[0];
sf=cmpls[1];
} else if ( cmpls.size()==1 ) {
switch ( cmpls[0] ) {
case CMPLT_PC_SINGLE:
case CMPLT_PC_DOUBLE:
case CMPLT_PC_DYNAMIC: pc=cmpls[0]; break;
default: sf=cmpls[0]; break;
}
}
switch (pc) {
case CMPLT_PC_DYNAMIC: opcode=8; x=0; break;
case CMPLT_PC_SINGLE: opcode=8; x=1; break;
case CMPLT_PC_DOUBLE: opcode=9; x=0; break;
}
switch ( sf ) {
case CMPLT_SF0: sf=0; break;
case CMPLT_SF1: sf=1; break;
case CMPLT_SF2: sf=2; break;
case CMPLT_SF3: sf=3; break;
}
if (icode==INST_FMA) {
return F1(opcode, x, sf
, opnds[3]->getValue(), opnds[2]->getValue()
, opnds[4]->getValue(), opnds[1]->getValue(), qp);
} else {
return F1(opcode, x, sf
, 1, opnds[2]->getValue()
, 0, opnds[1]->getValue(), qp);
}
}
case INST_FMIN:
case INST_FMAX:
case INST_FAMIN:
case INST_FAMAX:
case INST_FPMIN:
case INST_FPMAX:
case INST_FPAMIN:
case INST_FPAMAX:
case INST_FPCMP:
{
uint64 opcode=0, x6=0xFF, sf=0;
uint64 fx, f1=opnds[1]->getValue(), f2=opnds[2]->getValue(), f3=opnds[3]->getValue();
for (int i=0 ; i<cmplcount ; i++ ) {
switch (cmpls[i]) {
case CMPLT_SF0: sf=0; break;
case CMPLT_SF1: sf=1; break;
case CMPLT_SF2: sf=2; break;
case CMPLT_SF3: sf=3; break;
case CMPLT_FCMP_FREL_EQ: x6=0x30; break;
case CMPLT_FCMP_FREL_GT: fx=f2; f2=f3; f3=fx;
case CMPLT_FCMP_FREL_LT: x6=0x31; break;
case CMPLT_FCMP_FREL_GE: fx=f2; f2=f3; f3=fx;
case CMPLT_FCMP_FREL_LE: x6=0x32; break;
case CMPLT_FCMP_FREL_UNORD: x6=0x33; break;
case CMPLT_FCMP_FREL_NEQ: x6=0x34; break;
case CMPLT_FCMP_FREL_NGT: fx=f2; f2=f3; f3=fx;
case CMPLT_FCMP_FREL_NLT: x6=0x35; break;
case CMPLT_FCMP_FREL_NGE: fx=f2; f2=f3; f3=fx;
case CMPLT_FCMP_FREL_NLE: x6=0x36; break;
case CMPLT_FCMP_FREL_ORD: x6=0x37; break;
default: assert(0); break;
}
}
switch (icode) {
case INST_FMIN: opcode=0; x6=0x14; break;
case INST_FMAX: opcode=0; x6=0x15; break;
case INST_FAMIN: opcode=0; x6=0x16; break;
case INST_FAMAX: opcode=0; x6=0x17; break;
case INST_FPMIN: opcode=1; x6=0x14; break;
case INST_FPMAX: opcode=1; x6=0x15; break;
case INST_FPAMIN: opcode=1; x6=0x16; break;
case INST_FPAMAX: opcode=1; x6=0x17; break;
case INST_FPCMP: opcode=1; break;
default: assert(0); break;
}
return F8(opcode, sf, x6, f3, f2, f1, qp);
}
case INST_FMERGE_S:
return F9(0, 0x10, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_FNEG:
return F9(0, 0x11, opnds[2]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_FNMA: {
uint64 opcode=0xC, x=0, sf=0;
for ( int ci=0 ; ci<cmplcount ; ci++ ) {
switch(cmpls[ci]) {
case CMPLT_PC_SINGLE: x=1; break;
case CMPLT_PC_DOUBLE: opcode=0xD; break;
case CMPLT_SF1: sf=1; break;
case CMPLT_SF2: sf=2; break;
case CMPLT_SF3: sf=3; break;
default: break;
}
}
return F1(opcode, x, sf, opnds[3]->getValue(), opnds[2]->getValue(),
opnds[4]->getValue(), opnds[1]->getValue(), qp);
}
case INST_FRCPA: {
uint64 sf=0;
if ( cmplcount==1 ) {
switch(cmpls[0]) {
case CMPLT_SF1: sf=1; break;
case CMPLT_SF2: sf=2; break;
case CMPLT_SF3: sf=3; break;
default: break;
}
}
return F6(0, sf, opnds[2]->getValue(), opnds[4]->getValue(),
opnds[3]->getValue(), opnds[1]->getValue(), qp);
}
case INST_FSUB: { // qp) fsub.pc.sf f1 = f3, f2 pseudo-op of: (qp) fms.pc.sf f1 = f3, f4==1, f2
uint64 opcode=0xA, x=0, sf=0;
for ( int ci=0 ; ci<cmplcount ; ci++ ) {
switch(cmpls[ci]) {
case CMPLT_PC_SINGLE: opcode=0xA; x=1; break;
case CMPLT_PC_DOUBLE: opcode=0xB; x=0; break;
case CMPLT_SF0: sf=0; break;
case CMPLT_SF1: sf=1; break;
case CMPLT_SF2: sf=2; break;
case CMPLT_SF3: sf=3; break;
default:
assert(0);
break;
}
}
return F1(opcode, x, sf, 1, opnds[2]->getValue()
, opnds[3]->getValue(), opnds[1]->getValue(), qp);
}
case INST_GETF_S:
return M19(0x1e, opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_GETF_D:
return M19(0x1f, opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_GETF_EXP:
return M19(0x1d, opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_GETF_SIG:
return M19(0x1c, opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_LD:
case INST_LD16:
case INST_LD16_ACQ:
case INST_LD8_FILL:
{
uint64 x=0, x6=0x0, hint=0;
for (int i=0 ; i<cmplcount ; i++ ) {
switch (cmpls[i]) {
case CMPLT_SZ_1: x6 = (x6 & 0x3C) | 0x00; break;
case CMPLT_SZ_2: x6 = (x6 & 0x3C) | 0x01; break;
case CMPLT_SZ_4: x6 = (x6 & 0x3C) | 0x02; break;
case CMPLT_SZ_8: x6 = (x6 & 0x3C) | 0x03; break;
case CMPLT_LDTYPE_NORMAL: x6 = (x6 & 0x3) | (0x00 << 2); break;
case CMPLT_LDTYPE_S: x6 = (x6 & 0x3) | (0x01 << 2); break;
case CMPLT_LDTYPE_A: x6 = (x6 & 0x3) | (0x02 << 2); break;
case CMPLT_LDTYPE_SA: x6 = (x6 & 0x3) | (0x03 << 2); break;
case CMPLT_LDTYPE_BIAS: x6 = (x6 & 0x3) | (0x04 << 2); break;
case CMPLT_LDTYPE_ACQ: x6 = (x6 & 0x3) | (0x05 << 2); break;
case CMPLT_LDTYPE_C_CLR: x6 = (x6 & 0x3) | (0x08 << 2); break;
case CMPLT_LDTYPE_C_NC: x6 = (x6 & 0x3) | (0x09 << 2); break;
case CMPLT_LDTYPE_C_CLR_ACQ: x6 = (x6 & 0x3) | (0x0A << 2); break;
case CMPLT_HINT_NONE: hint=0; break;
case CMPLT_HINT_NT1: hint=1; break;
case CMPLT_HINT_NTA: hint=3; break;
default: assert(0); break;
}
}
if (icode==INST_LD16 ) {
x6 = 0x28;
x = 1;
} else if (icode==INST_LD16_ACQ ) {
x6 = 0x2C;
x = 1;
} else if (icode==INST_LD8_FILL ) {
x6 = 0x1B;
x = 0;
}
if (opndcount>=4 && opnds[3]->isImm(9)) {
return M3(x6, hint, opnds[2]->getValue(), opnds[3]->getValue()
, opnds[1]->getValue(), qp);
} else if (opndcount>=4 && opnds[3]->getOpndKind()==OPND_G_REG) {
return M2(x6, hint, opnds[2]->getValue(), opnds[3]->getValue()
, opnds[1]->getValue(), qp);
} else {
return M1(x6, hint, x, opnds[2]->getValue(), opnds[1]->getValue(), qp);
}
}
case INST_LDF:
case INST_LDF8:
case INST_LDF_FILL:
return ldfx(icode, inst, cmpls, opnds, qp);
case INST_MOV:
case INST_MOV_I:
case INST_MOV_M:
case INST_MOV_RET:
return mov(unit, icode, inst, cmpls, opnds, qp);
case INST_SETF_S:
return M18(0x1e, opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_SETF_D:
return M18(0x1f, opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_SETF_EXP:
return M18(0x1d, opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_SETF_SIG:
return M18(0x1c, opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_SHL:
assert(opndcount>=4);
if (opnds[3]->getOpndKind()==OPND_G_REG) {
return I7(1, 1, opnds[3]->getValue(), opnds[2]->getValue()
, opnds[1]->getValue(), qp);
} else {
// pos6 = count6; len6 = 64-pos6; len6 = len6d + 1; pos6 = 63 - cpos6c
return I12(63-(uint64)opnds[3]->getValue(), 63-(uint64)opnds[3]->getValue()
, opnds[2]->getValue(), opnds[1]->getValue(), qp);
}
case INST_SHLADD:
return A2(4, opnds[3]->getValue() & 0x3, opnds[4]->getValue()
, opnds[2]->getValue(), opnds[1]->getValue(), qp);
case INST_SHR:
assert(opndcount>=4);
if (opnds[3]->getOpndKind()==OPND_G_REG) {
return I5(1, 1, 2, opnds[2]->getValue(), opnds[3]->getValue()
, opnds[1]->getValue(), qp);
} else {
return I11(64-opnds[3]->getValue(), opnds[2]->getValue()
, opnds[3]->getValue(), 1, opnds[1]->getValue(), qp);
}
case INST_SHR_U:
assert(opndcount>=4);
if (opnds[3]->getOpndKind()==OPND_G_REG) {
return I5(1, 1, 0, opnds[2]->getValue(), opnds[3]->getValue()
, opnds[1]->getValue(), qp);
} else {
return I11(64-opnds[3]->getValue(), opnds[2]->getValue()
, opnds[3]->getValue(), 0, opnds[1]->getValue(), qp);
}
case INST_ST:
{
uint64 x6=0x30, hint=0;
for (int i=0, ii=cmplcount ; i<ii ; i++) {
switch (cmpls[i]) {
case CMPLT_SZ_1: x6 = (x6 & 0x3C) | 0x00; break;
case CMPLT_SZ_2: x6 = (x6 & 0x3C) | 0x01; break;
case CMPLT_SZ_4: x6 = (x6 & 0x3C) | 0x02; break;
case CMPLT_SZ_8: x6 = (x6 & 0x3C) | 0x03; break;
case CMPLT_ST_TYPE_NORMAL: x6 = (x6 & 0x3) | (0x0C << 2);break;
case CMPLT_ST_TYPE_REL: x6 = (x6 & 0x3) | (0x0D << 2); break;
case CMPLT_HINT_NONE: hint=0; break;
case CMPLT_HINT_NTA: hint=3; break;
default: assert(0); break;
}
}
if (opndcount==4 && opnds[3]->isImm(9)) {
return M5(x6, hint, opnds[1]->getValue(), opnds[2]->getValue(), opnds[3]->getValue(), qp);
} else {
return M4(x6, hint, 0, opnds[1]->getValue(), opnds[2]->getValue(), qp);
}
}
case INST_ST8_SPILL:
if ( opndcount==3 ) {
return M4(0x3B, (cmplcount>0 && cmpls[0]==CMPLT_HINT_NTA?3:0)
, 0, opnds[1]->getValue(), opnds[2]->getValue(), qp);
} else {
return M5(0x3B, (cmplcount>0 && cmpls[0]==CMPLT_HINT_NTA?3:0)
, opnds[1]->getValue(), opnds[2]->getValue(), opnds[3]->getValue(), qp);
}
case INST_ST16:
{
uint64 x6=0x30, hint=0;
for (int i=0, ii=cmpls.size() ; i<ii ; i++) {
switch (cmpls[i]) {
case CMPLT_ST_TYPE_NORMAL: x6 = 0x30;break;
case CMPLT_ST_TYPE_REL: x6 = 0x34; break;
case CMPLT_HINT_NONE: hint=0; break;
case CMPLT_HINT_NTA: hint=3; break;
default: assert(0); break;
}
}
return M4(x6, hint, 1, opnds[1]->getValue(), opnds[2]->getValue(), qp);
}
case INST_STF:
case INST_STF8:
case INST_STF_SPILL:
{
uint64 x6=0x32, hint=0;
if (icode==INST_STF_SPILL) {
x6=0x3B;
} else if (icode==INST_STF8) {
x6=0x31;
} else {
switch (cmpls[0]) {
case CMPLT_FSZ_S: x6=0x32; break;
case CMPLT_FSZ_D: x6=0x33; break;
case CMPLT_FSZ_E: x6=0x30; break;
default: assert(0); break;
}
}
if (cmplcount>=1 && cmpls[0]==CMPLT_HINT_NTA ) hint=3;
else if (cmplcount>=2 && cmpls[1]==CMPLT_HINT_NTA ) hint=3;
if (opnds.size()>=4 ) {
return M10(x6, hint, opnds[1]->getValue(), opnds[2]->getValue(), opnds[3]->getValue(), qp);
} else {
return M9(x6, hint, opnds[1]->getValue(), opnds[2]->getValue(), qp);
}
}
case INST_SXT:
case INST_ZXT:
{
uint64 x6 = 0xFF;
switch (cmpls[0]) {
case CMPLT_XSZ_1: x6 = 0x14; break;
case CMPLT_XSZ_2: x6 = 0x15; break;
case CMPLT_XSZ_4: x6 = 0x16; break;
default: assert(0); break;
}
if (icode==INST_ZXT) x6 = x6 - 4;
return I29(x6, opnds[2]->getValue(), opnds[1]->getValue(), qp);
}
case INST_XMA_L:
case INST_XMA_LU:
return F2(0, opnds[3]->getValue(), opnds[2]->getValue()
, opnds[4]->getValue(), opnds[1]->getValue(), qp);
case INST_XMA_H:
return F2(3, opnds[3]->getValue(), opnds[2]->getValue()
, opnds[4]->getValue(), opnds[1]->getValue(), qp);
case INST_XMA_HU:
return F2(2, opnds[3]->getValue(), opnds[2]->getValue()
, opnds[4]->getValue(), opnds[1]->getValue(), qp);
default:
IPF_ERR << __FILE__ << ": " << __LINE__
<< " IpfEncoder ERROR: NOT YET IMPLEMENTED INSTRUCTION: "
<< Encoder::getMnemonic(icode) << "\n";
break;
}
return instbits;
}