blob: 4f393e1d87a57ef31276f8b09a05e40f6568be0f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Intel, Konstantin M. Anisimov, Igor V. Chebykin
*
*/
#include "IpfEncoder.h"
#include "IpfCfg.h"
#include "IpfOpndManager.h"
#include "IpfVerifier.h"
#define O(n) ((opnds)[n])
#define K(n) ((opnds)[n]->getOpndKind())
#define V(n) ((opnds)[n]->getValue())
#define C(n) ((cmpls)[n])
#define GR(n) ((RegOpnd *)O(n))
#define IS_O(n) ((opnds).size()>=(n+1))
#define IS_C(n) ((cmpls).size()>=(n+1))
#define IS_AR(n) (IS_O(n) && K(n)==OPND_A_REG)
#define IS_GR(n) (IS_O(n) && K(n)==OPND_G_REG)
#define IS_FR(n) (IS_O(n) && K(n)==OPND_F_REG)
#define IS_PR(n) (IS_O(n) && K(n)==OPND_P_REG)
#define IS_BR(n) (IS_O(n) && K(n)==OPND_B_REG)
#define IS_IMM(n) (IS_O(n) && O(n)->isImm())
#define IS_IMM6(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 6))
#define IS_IMM8(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 8))
#define IS_IMM9(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 9))
#define IS_IMM13(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 13))
#define IS_IMM14(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 14))
#define IS_IMM22(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 22))
#define IS_IMM25(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 25))
#define IS_IMM64(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 64))
#define IS_CONST_REF(n) (IS_O(n) && O(n)->isImm() && (O(n)->getDataKind()==DATA_CONST_REF))
#define IS_NODE_REF(n) (IS_O(n) && O(n)->isImm() && (O(n)->getDataKind()==DATA_NODE_REF))
#define IS_SWITCH_REF(n) (IS_O(n) && O(n)->isImm() && (O(n)->getDataKind()==DATA_SWITCH_REF))
#define IS_REF(n) (IS_CONST_REF(n) || IS_NODE_REF(n) || IS_SWITCH_REF(n))
namespace Jitrino {
namespace IPF {
IpfVerifier::IpfVerifier(Cfg & cfg_, CompilationInterface & compilationinterface_) :
cfg(cfg_), compilationinterface(compilationinterface_), mm(cfg_.getMM())
{
methodDesc = compilationinterface.getMethodToCompile();
methodString = new(mm) string("");
if (methodDesc != NULL) {
methodString->append((methodDesc->getParentType()!=NULL
? methodDesc->getParentType()->getName()
: ""));
methodString->append(".");
methodString->append(methodDesc->getName());
methodString->append(methodDesc->getSignatureString());
}
}
//----------------------------------------------------------------------------//
bool IpfVerifier::verifyMethod(char * str) {
bool ret = true;
ret = ret && verifyMethodInsts();
ret = ret && verifyMethodNodes();
ret = ret && verifyMethodEdges();
return ret;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::verifyMethodInsts(char * str) {
BbNode * node = (BbNode *)cfg.getEnterNode();
bool ret = true;
do {
ret = ret && verifyNodeInsts(node);
} while( (node = node->getLayoutSucc()) != NULL );
return ret;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::verifyMethodNodes(char * str) {
uint16 size1 = cfg.search(SEARCH_DIRECT_ORDER).size();
uint16 size2 = cfg.search(SEARCH_POST_ORDER).size();
if(size1 != size2) {
cerr << "VERIFY ERROR: " << *methodString << " SEARCH_DIRECT_ORDER gives size " << size1;
cerr << " SEARCH_POST_ORDER gives size " << size2 << endl;
return false;
}
return true;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::verifyMethodEdges(char * str) {
BbNode* node = (BbNode*) cfg.getEnterNode();
bool ret = true;
do {
ret = ret && verifyNodeEdges(node);
} while( (node = node->getLayoutSucc()) != NULL );
return ret;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::verifyNodeInsts(BbNode * node) {
InstVector & insts = node->getInsts();
Inst * inst;
bool ret = true;
string * res = new(mm) string();
for (int i=0, ii=insts.size() ; i<ii ; i++ ) {
inst = insts[i];
res->erase();
if( !verifyInst(res, inst) ) {
cerr << "VERIFY METHOD ERROR: " << *methodString;
cerr << "; node id: " << node->getId()
<< ", inst index: " << i
<< ", inst code: " << IrPrinter::toString(inst)
<< (res->empty() ? "" : " : ") << *res
<< "\n";
ret = false;
#ifndef NDEBUG
verifyInst(res, inst); // verify again for debugger
#endif
}
}
return ret;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::verifyInst(string * res, Inst * inst) {
InstCode icode = inst->getInstCode();
OpndVector & opnds = inst->getOpnds();
CompVector & cmpls = inst->getComps();
if ( !IS_PR(0) ) return false;
switch (icode) {
// special cases
case INST_NOP:
return true;
case INST_HINT:
return true;
case INST_BREAK:
return true;
case INST_BREAKPOINT:
return true;
case INST_BR13:
case INST_BRL13:
case INST_BR:
case INST_BRL:
case INST_BRP:
case INST_BRP_RET:
return br(res, inst, icode, opnds, cmpls);
case INST_ADD:
if (!IS_O(3)) return false;
if (IS_GR(1) && IS_GR(2) && IS_GR(3)) return true;
if (IS_GR(1) && IS_IMM14(2) && IS_GR(3)) return true;
if (IS_GR(1) && IS_IMM22(2) && IS_GR(3)) {
if (V(2)<=3 && V(2)>=0) return true;
}
break;;
case INST_ADDS:
if (!IS_O(3)) return false;
if (IS_GR(1) && IS_IMM14(2) && IS_GR(3)) return true;
break;;
case INST_ADDL: // opnds[2]->getOpndKind() == OPND_IMM22
if (!IS_O(3)) return false;
if (IS_GR(1) && IS_IMM22(2) && IS_GR(3)) {
if (opnds[2]->getValue()<=3 && opnds[2]->getValue()>=0) return true;
}
break;;
case INST_ADDP4:
if (!IS_O(3)) return false;
if (IS_GR(1) && IS_GR(2) && IS_GR(3)) return true;
if (IS_GR(1) && IS_IMM14(2) && IS_GR(3)) return true;
break;
case INST_ALLOC:
if (!IS_O(5)) return false;
if (IS_GR(1) && IS_IMM(2) && IS_IMM(3) && IS_IMM(4) && IS_IMM(5)) {
if (V(0)!=0) return false;
if ((V(2) + V(3) + V(4))>96) return false;
if (V(5)>(V(2) + V(3) + V(4))) return false;
if ((V(2) + V(3))>(V(2) + V(3) + V(4))) return false;
if (V(5)%8 != 0) return false;
return true;
}
break;
case INST_AND:
case INST_ANDCM:
case INST_OR:
case INST_XOR:
if (!IS_O(3)) return false;
if (IS_GR(1) && IS_GR(2) && IS_GR(3)) return true;
if (IS_GR(1) && IS_IMM8(2) && IS_GR(3)) return true;
break;
case INST_SUB:
if (!IS_O(3)) return false;
if (IS_GR(1) && IS_GR(2) && IS_GR(3) && IS_O(4)) {
if (IS_IMM(4) && V(4)==1) return true;
return false;
}
if (IS_GR(1) && IS_GR(2) && IS_GR(3)) return true;
if (IS_GR(1) && IS_IMM8(2) && IS_GR(3)) return true;
break;
case INST_CMP:
case INST_CMP4:
return cmp_cmp4(res, inst, icode, opnds, cmpls);
case INST_FABS:
if (!IS_O(2)) return false;
if (IS_FR(1) && IS_FR(2)) return true;
break;
case INST_FADD:
{
uint64 opcode=8, x=0, sf=0;
if (!IS_O(3) || IS_O(4)) return false;
if (!(IS_FR(1) && IS_FR(2) && IS_FR(3))) return false;
for (uint64 i=0 ; IS_C(i) ; i++ ) {
switch (C(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: return false;
}
}
return true;
}
case INST_FAND:
case INST_FANDCM:
if ( !IS_O(3) || IS_O(4)) return false;
if (IS_FR(1) && IS_FR(2) && IS_FR(3)) return true;
break;
case INST_FC:
case INST_FC_I:
if (IS_GR(1) && !IS_O(2)) return true;
break;
case INST_FCMP:
return fcmp(res, inst, icode, opnds, cmpls);
case INST_FCLASS:
if (!IS_O(4) || IS_O(5)) return false;
for (unsigned int i=0 ; IS_C(i) ; ++i) {
if ( !(C(i)==CMPLT_FCMP_FCTYPE_UNC
|| C(i)==CMPLT_FCMP_FCTYPE_NONE
|| C(i)==CMPLT_FCMP_FCTYPE_NORMAL
|| C(i)==CMPLT_FCREL_NM
|| C(i)==CMPLT_FCREL_M) ) {
return false;
}
}
if (IS_PR(1) && IS_PR(2) && IS_FR(3) && IS_IMM9(4)) return true;
break;
case INST_FCVT_FX:
case INST_FCVT_FX_TRUNC:
case INST_FCVT_FXU:
case INST_FCVT_FXU_TRUNC:
if ( IS_C(0) ) {
switch(C(0)) {
case CMPLT_SF0:
case CMPLT_SF1:
case CMPLT_SF2:
case CMPLT_SF3:
break;
default:
return false;
}
}
if (IS_FR(1) && IS_FR(2)) return true;
break;
case INST_FCVT_XF:
if (IS_FR(1) && IS_FR(2)) return true;
break;
case INST_FCVT_XUF:
if (IS_C(2)) return false;
for (U_32 i=0 ; IS_C(i) ; i++) {
switch (C(i)) {
case CMPLT_PC_SINGLE:
case CMPLT_PC_DOUBLE:
case CMPLT_PC_DYNAMIC:
case CMPLT_SF0:
case CMPLT_SF1:
case CMPLT_SF2:
case CMPLT_SF3:
break;
default:
return false;
}
}
if (IS_FR(1) && IS_FR(2)) return true;
break;
case INST_FMA:
for (U_32 i=0 ; IS_C(i) ; i++) {
switch (C(i)) {
case CMPLT_PC_SINGLE:
case CMPLT_PC_DOUBLE:
case CMPLT_PC_DYNAMIC:
case CMPLT_SF0:
case CMPLT_SF1:
case CMPLT_SF2:
case CMPLT_SF3:
break;
default:
return false;
}
}
if (IS_FR(1) && IS_FR(2) && IS_FR(3) && IS_FR(4)) return true;
break;
case INST_FMIN:
case INST_FMAX:
case INST_FAMIN:
case INST_FAMAX:
case INST_FPMIN:
case INST_FPMAX:
case INST_FPAMIN:
case INST_FPAMAX:
for (U_32 i=0 ; IS_C(i) ; i++) {
switch (C(i)) {
case CMPLT_SF0:
case CMPLT_SF1:
case CMPLT_SF2:
case CMPLT_SF3:
break;
default:
return false;
}
}
if (IS_FR(1) && IS_FR(2) && IS_FR(3)) return true;
break;
case INST_FPCMP:
for (U_32 i=0 ; IS_C(i) ; i++) {
switch (C(i)) {
case CMPLT_SF0:
case CMPLT_SF1:
case CMPLT_SF2:
case CMPLT_SF3:
case CMPLT_FCMP_FREL_EQ:
case CMPLT_FCMP_FREL_GT:
case CMPLT_FCMP_FREL_LT:
case CMPLT_FCMP_FREL_GE:
case CMPLT_FCMP_FREL_LE:
case CMPLT_FCMP_FREL_UNORD:
case CMPLT_FCMP_FREL_NEQ:
case CMPLT_FCMP_FREL_NGT:
case CMPLT_FCMP_FREL_NLT:
case CMPLT_FCMP_FREL_NGE:
case CMPLT_FCMP_FREL_NLE:
case CMPLT_FCMP_FREL_ORD:
break;
default:
return false;
}
}
if (IS_FR(1) && IS_FR(2) && IS_FR(3) && !IS_O(4)) return true;
break;
case INST_FMERGE_NS:
case INST_FMERGE_S:
case INST_FMERGE_SE:
if (IS_FR(1) && IS_FR(2) && IS_FR(3) && !IS_O(4)) return true;
break;
case INST_FNEG:
if (IS_FR(1) && IS_FR(2) && !IS_O(3) && !IS_C(0)) return true;
break;
case INST_FNMA:
for ( U_32 i=0 ; IS_C(i) ; i++ ) {
switch(C(i)) {
case CMPLT_PC_SINGLE:
case CMPLT_PC_DOUBLE:
case CMPLT_PC_DYNAMIC:
case CMPLT_SF0:
case CMPLT_SF1:
case CMPLT_SF2:
case CMPLT_SF3:
break;
default:
return false;
}
}
if (IS_FR(1) && IS_FR(2) && IS_FR(3) && IS_FR(4) && !IS_O(5)) return true;
break;
case INST_FNORM:
for ( U_32 i=0 ; IS_C(i) ; i++ ) {
switch(C(i)) {
case CMPLT_PC_SINGLE:
case CMPLT_PC_DOUBLE:
case CMPLT_PC_DYNAMIC:
case CMPLT_SF0:
case CMPLT_SF1:
case CMPLT_SF2:
case CMPLT_SF3:
break;
default:
return false;
}
}
if (IS_FR(1) && IS_FR(2) && !IS_FR(3)) return true;
break;
case INST_FSUB:
if (IS_FR(1) && IS_FR(2) && IS_FR(3) && !IS_O(4) && !IS_C(2)) return true;
break;
case INST_FRCPA:
if ( IS_C(0) ) {
switch(C(0)) {
case CMPLT_SF0:
case CMPLT_SF1:
case CMPLT_SF2:
case CMPLT_SF3:
break;
default:
return false;
}
}
if (IS_FR(1) && IS_PR(2) && IS_FR(3) && IS_FR(4) && !IS_O(5)) return true;
break;
case INST_GETF_S:
case INST_GETF_D:
case INST_GETF_EXP:
case INST_GETF_SIG:
if (IS_GR(1) && IS_FR(2) && !IS_O(3)) return true;
break;
case INST_LD:
case INST_LD16:
case INST_LD16_ACQ:
case INST_LD8_FILL:
return ldx(res, inst, icode, opnds, cmpls);
case INST_LDF:
case INST_LDF8:
case INST_LDF_FILL:
return ldfx(res, inst, icode, opnds, cmpls);
case INST_MOV:
case INST_MOV_I:
case INST_MOV_M:
case INST_MOV_RET:
return mov(res, inst, icode, opnds, cmpls);
case INST_MOVL:
if (IS_GR(1) && IS_IMM64(2)) return true;
break;
case INST_SETF_S:
case INST_SETF_D:
case INST_SETF_EXP:
case INST_SETF_SIG:
if (!IS_O(3) && !IS_C(0) && IS_FR(1) && IS_GR(2)) return true;
break;
case INST_SHL:
case INST_SHR:
case INST_SHR_U:
if (!IS_C(0) && !IS_O(4) && IS_GR(1) && IS_GR(2)
&& (IS_GR(3) || (IS_IMM(3) && (V(3)&0x3F)==V(3)))) return true;
break;
case INST_SHLADD:
if (V(3)>4 || V(3)<1) { res->append("shift value must be 1...4"); return false; }
if (!IS_C(0) && !IS_O(5) && IS_GR(1) && IS_GR(2) && IS_GR(4)) return true;
break;
case INST_ST:
case INST_ST8_SPILL:
case INST_ST16:
return stx(res, inst, icode, opnds, cmpls);
case INST_STF:
case INST_STF8:
case INST_STF_SPILL:
for (uint64 i=0 ; IS_C(i) ; i++) {
switch (C(i)) {
case CMPLT_FSZ_D:
case CMPLT_FSZ_E:
case CMPLT_FSZ_S:
if (icode==INST_STF && i!=0) return false;
break;
case CMPLT_HINT_NONE:
case CMPLT_HINT_NTA:
if (icode!=INST_STF && i!=0) return false;
break;
default:
return false;
}
}
if (!IS_C(2) && IS_GR(1) && IS_FR(2) && (!IS_O(3) || IS_IMM9(3))) return true;
break;
case INST_SXT:
case INST_ZXT:
if (!IS_C(0)) return false;
switch (C(0)) {
case CMPLT_XSZ_1:
case CMPLT_XSZ_2:
case CMPLT_XSZ_4:
break;
default:
return false;
}
if (!IS_C(1) && IS_GR(1) && IS_GR(2)) return true;
break;
case INST_DEF:
case INST_USE:
return true;
case INST_XMA_L:
case INST_XMA_LU:
case INST_XMA_H:
case INST_XMA_HU:
if (!IS_C(0) && IS_FR(1) && IS_FR(2) && IS_FR(3) && IS_FR(4)) return true;
break;
default:
IPF_ERR << ": NOT YET IMPLEMENTED VERIFIER FOR INSTRUCTION: "
<< IrPrinter::toString(inst) << "\n";
return true;;
}
return false;
}
bool IpfVerifier::br(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) {
unsigned int is13 = (icode==INST_BR13 || icode==INST_BRL13 ? 1 : 0); // must be 1 or 0
switch (icode) {
case INST_BRL13:
case INST_BRL:
if (IS_C(0) && C(0)==CMPLT_BTYPE_CALL) {
if (!IS_O(is13 + 2)) return false;
if (!IS_IMM64(is13 + 2)) return false;
if (!IS_BR(is13 + 1)) return false;
} else {
if (!IS_O(is13 + 1)) return false;
if (!IS_IMM64(is13 + 1)) return false;
}
for (uint64 i=1 ; IS_C(i) ; i++ ) {
switch (C(i)) {
case CMPLT_DH_CLR:
case CMPLT_WH_SPTK:
case CMPLT_WH_SPNT:
case CMPLT_WH_DPTK:
case CMPLT_WH_DPNT:
case CMPLT_PH_FEW:
case CMPLT_PH_MANY:
break;
default:
return false;
}
}
return true;
case INST_BR:
case INST_BR13:
if (!IS_O(is13 + 1)) return false;
{
OpndKind okind1 = K(is13 + 1);
uint64 cmplt_btype=CMPLT_BTYPE_COND, btype=0, ph=0, bwh=0, dh=0;
for (uint64 i=0 ; IS_C(i) ; i++) {
switch (C(i)) {
case CMPLT_BTYPE_COND: btype=0; cmplt_btype=C(i); break;
case CMPLT_BTYPE_IA: btype=1; cmplt_btype=C(i); break;
case CMPLT_BTYPE_RET: btype=4; cmplt_btype=C(i); break;
case CMPLT_BTYPE_CLOOP: btype=5; cmplt_btype=C(i); break;
case CMPLT_BTYPE_CEXIT: btype=6; cmplt_btype=C(i); break;
case CMPLT_BTYPE_CTOP: btype=7; cmplt_btype=C(i); break;
case CMPLT_BTYPE_WEXIT: btype=2; cmplt_btype=C(i); break;
case CMPLT_BTYPE_WTOP: btype=3; cmplt_btype=C(i); break;
case CMPLT_BTYPE_CALL: btype=(uint64)-1; cmplt_btype=C(i); break;
//----------------------------
// Branch_Whether_Hint, NOT for all branch instructions!
case CMPLT_WH_SPTK: bwh=0; break;
case CMPLT_WH_SPNT: bwh=1; break;
case CMPLT_WH_DPTK: bwh=2; break;
case CMPLT_WH_DPNT: bwh=3; break;
//----------------------------
// Branch_Sequential_Prefetch_Hint (br, brl)
case CMPLT_PH_FEW: ph=0; break;
case CMPLT_PH_MANY: ph=1; break;
//----------------------------
// Branch_Cache_Deallocation_Hint (br, brl)
case CMPLT_DH_NOT_CLR: dh=0; break;
case CMPLT_DH_CLR: dh=1; break;
default:
return false;
}
}
if (cmplt_btype==CMPLT_BTYPE_CALL) {
if (!IS_O(is13 + 2)) return false;
if (!IS_BR(is13 + 1)) return false;
if (IS_BR(is13 + 2)) {
return true;
} else {
if (!IS_IMM25(is13 + 2)) return false;
if ( IS_NODE_REF(is13 + 2) ) {
return true;
} else {
return true;
}
}
} else if (cmplt_btype==CMPLT_BTYPE_RET) {
return true;
} else if (cmplt_btype==CMPLT_BTYPE_CLOOP
|| cmplt_btype==CMPLT_BTYPE_CEXIT
|| cmplt_btype==CMPLT_BTYPE_CTOP) {
if ( IS_NODE_REF(is13 + 1) ) {
//assert(target != 0);
return true;
} else {
return true;
}
} else if (okind1==OPND_B_REG) {
return true;
} else {
if (!IS_IMM25(is13 + 1)) return false;
if ( IS_NODE_REF(is13 + 1) ) {
//assert(target!=0);
return true;
} else {
return true;
}
}
}
// fall to assert(0)
default:
IPF_LOG << __FILE__ << ": " << __LINE__
<< ": NOT YET IMPLEMENTED VERIFIER FOR INSTRUCTION: "
<< IrPrinter::toString(inst) << "\n";
return false;
}
return false;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::fcmp(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) {
if (!IS_O(4) || !IS_C(0) || IS_O(5)) return false;
if (!IS_PR(1) || !IS_PR(2) || !IS_FR(3) || !IS_FR(4)) return false;
switch (C(0)) {
case CMPLT_FCMP_FREL_EQ:
case CMPLT_FCMP_FREL_LT:
case CMPLT_FCMP_FREL_LE:
case CMPLT_FCMP_FREL_GT:
case CMPLT_FCMP_FREL_GE:
case CMPLT_FCMP_FREL_UNORD:
case CMPLT_FCMP_FREL_NEQ:
case CMPLT_FCMP_FREL_NLT:
case CMPLT_FCMP_FREL_NLE:
case CMPLT_FCMP_FREL_NGT:
case CMPLT_FCMP_FREL_NGE:
case CMPLT_FCMP_FREL_ORD:
break;
default:
res->append("WRONG COMPLETER");
return false;
}
if (IS_C(2)) {
switch (C(1)) {
case CMPLT_FCMP_FCTYPE_NONE:
case CMPLT_FCMP_FCTYPE_UNC: break;
default:
res->append("WRONG COMPLETER");
return false;
}
switch (C(2)) {
case CMPLT_SF0:
case CMPLT_SF1:
case CMPLT_SF2:
case CMPLT_SF3: break;
default:
res->append("WRONG COMPLETER");
return false;
}
} else if (IS_C(1)) {
switch (C(1)) {
case CMPLT_FCMP_FCTYPE_NONE:
case CMPLT_FCMP_FCTYPE_UNC:
case CMPLT_SF0:
case CMPLT_SF1:
case CMPLT_SF2:
case CMPLT_SF3: break;
default:
res->append("WRONG COMPLETER");
return false;
}
}
return true;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::cmp_cmp4(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) {
if (!IS_O(4) || !IS_C(0)) return false;
if (!IS_PR(1) || !IS_PR(2) || !(IS_GR(3) || IS_IMM(3)) || !IS_GR(4)) return false;
if (IS_GR(3) && IS_GR(4)) {
// if (GR(3)->getDataKind() != GR(4)->getDataKind()) {
// res->append(IrPrinter::toString(O(3))
// + " and "
// + IrPrinter::toString(O(4))
// + " have different DataKind: "
// + getDataKindStr(GR(3)->getDataKind())
// + ", "
// + getDataKindStr(GR(4)->getDataKind()));
// return false;
// }
}
int64 p1=V(1), p2=V(2);
int64 r2=V(3), r3=V(4);
OpndKind okind3=K(3);
Completer crel = C(0);
Completer ctype = ( IS_C(1) ? C(1) : CMPLT_INVALID );
uint64 opcode=0, ta=0, c=0, x2;
int64 tmp;
// parse pseudo-op
if ( !IS_C(1) || ctype==CMPLT_CMP_CTYPE_UNC ) {
if ( IS_IMM8(3) ) {
switch (crel) {
case CMPLT_CMP_CREL_NE:
crel=CMPLT_CMP_CREL_EQ;
tmp = p1; p1 = p2; p2 = tmp;
break;
case CMPLT_CMP_CREL_LE:
crel=CMPLT_CMP_CREL_LT;
r2--;
break;
case CMPLT_CMP_CREL_GT:
crel=CMPLT_CMP_CREL_LT;
r2--;
tmp = p1; p1 = p2; p2 = tmp;
break;
case CMPLT_CMP_CREL_GE:
crel=CMPLT_CMP_CREL_LT;
tmp = p1; p1 = p2; p2 = tmp;
break;
case CMPLT_CMP_CREL_LEU:
crel=CMPLT_CMP_CREL_LTU;
r2--;
break;
case CMPLT_CMP_CREL_GTU:
crel=CMPLT_CMP_CREL_LTU;
r2--;
tmp = p1; p1 = p2; p2 = tmp;
break;
case CMPLT_CMP_CREL_GEU:
crel=CMPLT_CMP_CREL_LTU;
tmp = p1; p1 = p2; p2 = tmp;
break;
default:
break;
}
} else {
switch (crel) {
case CMPLT_CMP_CREL_NE:
crel=CMPLT_CMP_CREL_EQ;
tmp = p1; p1 = p2; p2 = tmp;
break;
case CMPLT_CMP_CREL_LE:
crel=CMPLT_CMP_CREL_LT;
tmp = r3; r3 = r2; r2 = tmp;
tmp = p1; p1 = p2; p2 = tmp;
break;
case CMPLT_CMP_CREL_GT:
crel=CMPLT_CMP_CREL_LT;
tmp = r3; r3 = r2; r2 = tmp;
break;
case CMPLT_CMP_CREL_GE:
crel=CMPLT_CMP_CREL_LT;
tmp = p1; p1 = p2; p2 = tmp;
break;
case CMPLT_CMP_CREL_LEU:
crel=CMPLT_CMP_CREL_LTU;
tmp = r3; r3 = r2; r2 = tmp;
tmp = p1; p1 = p2; p2 = tmp;
break;
case CMPLT_CMP_CREL_GTU:
crel=CMPLT_CMP_CREL_LTU;
tmp = r3; r3 = r2; r2 = tmp;
break;
case CMPLT_CMP_CREL_GEU:
crel=CMPLT_CMP_CREL_LTU;
tmp = p1; p1 = p2; p2 = tmp;
break;
default:
break;
}
}
} else if ( crel!=CMPLT_CMP_CREL_EQ && crel!=CMPLT_CMP_CREL_NE ) {
if ( crel==CMPLT_CMP_CREL_LT && r2>0 ) {
crel=CMPLT_CMP_CREL_GT;
tmp = r3; r3 = r2; r2 = tmp;
} else if ( crel==CMPLT_CMP_CREL_LE && r2>0 ) {
crel=CMPLT_CMP_CREL_GE;
tmp = r3; r3 = r2; r2 = tmp;
} else if ( crel==CMPLT_CMP_CREL_GT && r2>0 ) {
crel=CMPLT_CMP_CREL_LT;
tmp = r3; r3 = r2; r2 = tmp;
} else if ( crel==CMPLT_CMP_CREL_GE && r2>0 ) {
crel=CMPLT_CMP_CREL_LE;
tmp = r3; r3 = r2; r2 = tmp;
}
}
switch (ctype) {
case CMPLT_CMP_CTYPE_AND: opcode=0xC; break;
case CMPLT_CMP_CTYPE_OR: opcode=0xD; break;
case CMPLT_CMP_CTYPE_OR_ANDCM: opcode=0xE; break;
default:
switch (crel) {
case CMPLT_CMP_CREL_LT: opcode=0xC; break;
case CMPLT_CMP_CREL_LTU: opcode=0xD; break;
case CMPLT_CMP_CREL_EQ: opcode=0xE; break;
default:
return false;
}
}
switch (crel) {
case CMPLT_CMP_CREL_NE: ta=1; c=1; break;
case CMPLT_CMP_CREL_GE: ta=1; c=0; break;
case CMPLT_CMP_CREL_LE: ta=0; c=1; break;
case CMPLT_CMP_CREL_GT: ta=0; c=0; break;
case CMPLT_CMP_CREL_LTU: ta=0; c=(ctype==CMPLT_CMP_CTYPE_UNC ? 1 : 0); break;
case CMPLT_CMP_CREL_EQ:
if ( cmpls.size()==1 ) { ta=0; c=0; }
else if ( ctype==CMPLT_CMP_CTYPE_UNC ) { ta=0; c=1; }
else { ta=1; c=0; }
break;
case CMPLT_CMP_CREL_LT:
if ( cmpls.size()==1 ) { ta=0; c=0; }
else if ( ctype==CMPLT_CMP_CTYPE_UNC ) { ta=0; c=1; }
else { ta=1; c=1; }
break;
default:
return false;
}
if ( (ctype==CMPLT_CMP_CTYPE_NORMAL || ctype==CMPLT_CMP_CTYPE_UNC
|| crel==CMPLT_CMP_CREL_NE || crel==CMPLT_CMP_CREL_EQ || cmpls.size()==1)
&& okind3==OPND_G_REG ) {
x2 = icode==INST_CMP ? 0 : 1;
return true;
} else if ( IS_IMM8(3) ) {
x2 = icode==INST_CMP ? 2 : 3;
return true;
} else {
if (r2!=0) return false;
x2 = icode==INST_CMP ? 0 : 1;
return true;
}
return false;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::stx(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) {
switch (icode) {
case INST_ST:
for (uint64 i=0 ; IS_C(i) ; i++) {
switch (C(i)) {
case CMPLT_SZ_1:
case CMPLT_SZ_2:
case CMPLT_SZ_4:
case CMPLT_SZ_8:
case CMPLT_ST_TYPE_NORMAL:
case CMPLT_ST_TYPE_REL:
case CMPLT_HINT_NONE:
case CMPLT_HINT_NTA:
break;
default:
return false;
}
}
if (!IS_C(3) && IS_GR(1) && IS_GR(2) && (!IS_O(3) || IS_IMM9(3))) return true;
break;
case INST_ST8_SPILL:
if (!IS_C(1)
&& (!IS_C(0) || (IS_C(0) && (C(0)==CMPLT_HINT_NONE || C(0)==CMPLT_HINT_NTA)))
&& IS_GR(1) && IS_GR(2) && (!IS_O(3) || IS_IMM9(3))) return true;
break;
case INST_ST16:
for (uint64 i=0 ; IS_C(i) ; i++) {
switch (C(i)) {
case CMPLT_ST_TYPE_NORMAL:
case CMPLT_ST_TYPE_REL:
case CMPLT_HINT_NONE:
case CMPLT_HINT_NTA:
break;
default:
return false;
}
}
if (!IS_C(2) && IS_GR(1) && IS_GR(2)) return true;
break;
default:
return false;
}
return false;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::ldx(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) {
for (U_32 i=0 ; IS_C(i) ; i++ ) {
switch (C(i)) {
case CMPLT_SZ_1:
case CMPLT_SZ_2:
case CMPLT_SZ_4:
case CMPLT_SZ_8:
case CMPLT_LDTYPE_NORMAL:
case CMPLT_LDTYPE_S:
case CMPLT_LDTYPE_A:
case CMPLT_LDTYPE_SA:
case CMPLT_LDTYPE_BIAS:
case CMPLT_LDTYPE_ACQ:
case CMPLT_LDTYPE_C_CLR:
case CMPLT_LDTYPE_C_NC:
case CMPLT_LDTYPE_C_CLR_ACQ:
case CMPLT_HINT_NONE:
case CMPLT_HINT_NT1:
case CMPLT_HINT_NTA:
break;
default:
return false;
}
}
switch (icode) {
case INST_LD:
if (IS_C(2)) return false;
if (IS_GR(1) && IS_GR(2) && (!IS_O(3) || IS_GR(3) || IS_IMM9(3))) return true;
break;
case INST_LD16:
case INST_LD16_ACQ:
if (IS_C(1)) return false;
if (IS_GR(1) && IS_GR(2) && !IS_O(3)) return true;
break;
case INST_LD8_FILL:
if (IS_C(1)) return false;
if (IS_GR(1) && IS_GR(2) && (!IS_O(3) || IS_GR(3) || IS_IMM9(3))) return true;
break;
default:
break;
}
return false;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::ldfx(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) {
for (U_32 i=0 ; IS_C(i) ; i++ ) {
switch (C(i)) {
case CMPLT_FSZ_E:
case CMPLT_FSZ_S:
case CMPLT_FSZ_D:
case CMPLT_LDTYPE_NORMAL:
case CMPLT_LDTYPE_S:
case CMPLT_LDTYPE_A:
case CMPLT_LDTYPE_SA:
case CMPLT_LDTYPE_C_CLR:
case CMPLT_LDTYPE_C_NC:
case CMPLT_HINT_NONE:
case CMPLT_HINT_NT1:
case CMPLT_HINT_NTA:
break;
default:
return false;
}
}
switch (icode) {
case INST_LDF:
if (IS_C(3)) return false;
break;
case INST_LDF8:
if (IS_C(2)) return false;
break;
case INST_LDF_FILL:
if (IS_C(1)) return false;
break;
default:
break;
}
if (IS_FR(1) && IS_GR(2) && (!IS_O(3) || IS_GR(3) || IS_IMM9(3))) return true;
return false;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::mov(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) {
if (icode!=INST_MOV_RET && IS_O(1) && IS_O(2) && !IS_O(3)
&& ((IS_AR(1) && IS_GR(2)) || (IS_GR(1) && IS_AR(2)) || (IS_AR(1) && IS_IMM8(2))))
return true;
if (icode==INST_MOV && !IS_O(3) && ((IS_GR(1) && IS_BR(2)) || (IS_BR(1) && IS_GR(2))))
return true;
if ((icode==INST_MOV || icode==INST_MOV_RET) && IS_O(3) && IS_BR(1) && IS_GR(2) && IS_IMM13(3)) {
for (U_32 i=0 ; IS_C(i) ; i++){
switch (C(i)) {
case CMPLT_IH_NOT_IMP:
case CMPLT_IH_IMP:
case CMPLT_WH_DPTK:
case CMPLT_WH_SPTK:
case CMPLT_WH_IGNORE:
break;
default:
return false;
}
}
return true;
}
if (icode==INST_MOV && !IS_O(3) && !IS_C(0) && IS_FR(1) && IS_FR(2)) return true;
if (icode==INST_MOV && !IS_O(3) && !IS_C(0) && IS_GR(1) && IS_GR(2)) return true;
if (icode==INST_MOV && !IS_O(3) && !IS_C(0) && IS_GR(1) && (IS_IMM22(2) || IS_REF(2))) return true;
return false;
}
//----------------------------------------------------------------------------//
bool IpfVerifier::verifyNodeEdges(BbNode * node) {
string * res = new(mm) string();
ostringstream oss;
EdgeVector& outEdges = node->getOutEdges();
if(outEdges.size() == 0 && cfg.getExitNode() != node) {
oss << endl << " does not have out edges";
}
for(uint16 i=0; i<outEdges.size(); i++) {
switch(outEdges[i]->getEdgeKind()) {
case EDGE_BRANCH : edgeBranch(node, outEdges[i], oss); break;
case EDGE_THROUGH : edgeThrough(node, outEdges[i], oss); break;
case EDGE_DISPATCH : break;
case EDGE_EXCEPTION : break;
case EDGE_INVALID : edgeInvalid(node, oss); break;
}
}
res->append(oss.str());
if(!res->empty()) {
cerr << "VERIFY ERROR: " << *methodString << " " << *res << endl;
return false;
}
return true;
}
//----------------------------------------------------------------------------//
void IpfVerifier::edgeBranch(Node* node, Edge* edge, ostream& os) {
if(node->getNodeKind() != NODE_BB) {
os << endl << " is not BB, but contains EDGE_BRANCH";
return;
}
InstVector& insts = ((BbNode*) node)->getInsts();
if(insts.size() == 0) {
os << endl << " does not have insts, but contains EDGE_BRANCH";
return;
}
Inst* branchInst = insts.back();
if(Encoder::isBranchInst(branchInst) == false) {
os << endl << " contains EDGE_BRANCH, but last inst is not \"br\"";
return;
}
Opnd* targetOpnd = branchInst->getOpnd(1);
if(targetOpnd->getDataKind() != DATA_NODE_REF) return; // it must be switch
NodeRef* targetNodeRef = (NodeRef*) targetOpnd;
Node* targetNode=targetNodeRef->getNode();
Node* edgeTarget= edge->getTarget();
if (targetNode!=edgeTarget) {
os << "node" << node->getId() << " branch edge target and \"br\" instruction target are different";
return;
}
}
//----------------------------------------------------------------------------//
void IpfVerifier::edgeThrough(Node* node, Edge* edge, ostream& os) {
if(node->getNodeKind() != NODE_BB) {
os << endl << " is not BB, but contains EDGE_THROUGH";
return;
}
Node* edgeTarget = edge->getTarget();
Node* layoutSucc = ((BbNode*) node)->getLayoutSucc();
if(edgeTarget != layoutSucc) {
// check if last inst is br.ret
Inst* lastInst = NULL;
InstVector & insts = ((BbNode*) node)->getInsts();
if (insts.size()>0) lastInst = insts.back();
if(lastInst!=NULL && lastInst->getComps().size()>0 && lastInst->getComp(0)==CMPLT_BTYPE_RET)
return;
os << endl
<< " through edge target (node"
<< (edgeTarget ? edgeTarget->getId() : (uint64)-1)
<< ") and layout successor (node"
<< (layoutSucc ? layoutSucc->getId() : (uint64)-1)
<< ") are different";
return;
}
}
//----------------------------------------------------------------------------//
void IpfVerifier::edgeInvalid(Node* node, ostream& os) {
os << endl << " contains EDGE_INVALID";
}
//----------------------------------------------------------------------------//
char * IpfVerifier::getDataKindStr(DataKind datakind) {
switch ( datakind ) {
case DATA_BASE: return "DATA_BASE";
case DATA_MPTR: return "DATA_MPTR";
case DATA_I8: return "DATA_I8";
case DATA_U8: return "DATA_U8";
case DATA_I16: return "DATA_I16";
case DATA_U16: return "DATA_U16";
case DATA_I32: return "DATA_I32";
case DATA_U32: return "DATA_U32";
case DATA_I64: return "DATA_I64";
case DATA_U64: return "DATA_U64";
case DATA_S: return "DATA_S";
case DATA_D: return "DATA_D";
case DATA_F: return "DATA_F";
case DATA_P: return "DATA_P";
default: return "DATA_XXX";
}
return "DATA_XXX";
}
} // IPF
} // Jitrino