Commit 0cfda81b authored by wchen37's avatar wchen37 Committed by gbsbuild

add indirect stack call support to vISA.

-- add new vISA ocpode and associated parsing/printing code.

-- expand IFCALL to add/pseudo_fcall pair, where the add
comptues the relative offset between call and the function.

-- add relocation framework

Change-Id: I0c39bc5e5bc9d1905b1ba3dd9d337a88aca86c6d
parent 85a81547
......@@ -2292,6 +2292,38 @@ BinaryEncoding::Status BinaryEncoding::EncodeSplitSendSrc0(G4_INST* inst)
return SUCCESS;
}
// Gen encodes target for call as src1, though internally we store it in src0
BinaryEncoding::Status BinaryEncoding::EncodeIndirectCallTarget(G4_INST* inst)
{
BinInst *mybin = inst->getBinInst();
G4_Operand* funcAddr = inst->getSrc(0);
EncodeSrc1RegFile(mybin, funcAddr);
EncodeSrc1Type(mybin, funcAddr);
if (funcAddr->isImm())
{
EncodeSrcImmData(mybin, funcAddr);
}
else
{
G4_SrcRegRegion *srcRegion = funcAddr->asSrcRegRegion();
EncodeSrc1RegNum(inst, mybin, srcRegion);
EncodeSrc1ArchRegNum(inst, mybin, srcRegion);
EncodeSrc1IndirectRegNum(inst, mybin, srcRegion);
EncodeSrc1AddrMode(mybin, srcRegion);
EncodeSrc1RepCtrl(mybin, srcRegion);
EncodeSrc1Modifier(mybin, srcRegion);
EncodeSrc1ChanSelect(inst, mybin, srcRegion);
RegionDesc *rd = srcRegion->getRegion();
bool WidthValid = EncodeSrc1Width(inst, mybin, rd, srcRegion);
bool HorzStrideValid = EncodeSrc1HorzStride(inst, mybin, rd, srcRegion);
EncodeSrc1VertStride(inst, mybin, rd, srcRegion, WidthValid, HorzStrideValid);
}
return SUCCESS;
}
BinaryEncoding::Status BinaryEncoding::EncodeOperandSrc1(G4_INST* inst)
{
BinInst *mybin = inst->getBinInst();
......@@ -3160,36 +3192,48 @@ bool BinaryEncoding::EncodeConditionalBranches(G4_INST *inst,
}
}
if ( op == G4_call &&
inst->getSrc(0) &&
inst->getSrc(0)->isLabel() )
{
G4_Operand *opnd = inst->getSrc(0);
std::string jmpLabel = ((G4_Label*) opnd)->getLabel();
int32_t info = GetLabelInfo(this->LabelMap, jmpLabel);
if (info == -1)
{
return false;
}
int32_t jmpOffset = info - insOffset;
if ( !isValidIPOffset(jmpOffset) )
if ( op == G4_call && inst->getSrc(0))
{
if (inst->getSrc(0)->isLabel())
{
MUST_BE_TRUE(false, "invalid IP offset for call");
}
G4_Operand *opnd = inst->getSrc(0);
std::string jmpLabel = ((G4_Label*)opnd)->getLabel();
int32_t info = GetLabelInfo(this->LabelMap, jmpLabel);
if (info == -1)
{
return false;
}
int32_t jmpOffset = info - insOffset;
if (!isValidIPOffset(jmpOffset))
{
MUST_BE_TRUE(false, "invalid IP offset for call");
}
jmpOffset *= (int32_t)JUMP_INST_COUNT_SIZE;
jmpOffset *= (int32_t)JUMP_INST_COUNT_SIZE;
BinInst *mybin = inst->getBinInst();
BinInst *mybin = inst->getBinInst();
SetSrc0VertStride(mybin, 2);
SetSrc0Width(mybin, 2);
SetSrc0HorzStride(mybin, 1);
SetSrc0VertStride(mybin, 2);
SetSrc0Width(mybin, 2);
SetSrc0HorzStride(mybin, 1);
SetSrc1RegFile(mybin, REG_FILE_I);
SetSrc1Type(mybin, SRC_IMM_TYPE_D);
SetSrc1RegFile(mybin, REG_FILE_I);
SetSrc1Type(mybin, SRC_IMM_TYPE_D);
SetCmpSrc1Imm32(mybin, jmpOffset, opnd);
SetCmpSrc1Imm32(mybin, jmpOffset, opnd);
}
else
{
// indirect call
BinInst *mybin = inst->getBinInst();
SetSrc0VertStride(mybin, 2);
SetSrc0Width(mybin, 2);
SetSrc0HorzStride(mybin, 1);
EncodeIndirectCallTarget(inst);
}
}
return true;
}
......@@ -737,6 +737,8 @@ namespace vISA
Status EncodeSplitSendSrc1(G4_INST*);
Status EncodeSplitSendSrc2(G4_INST*);
Status EncodeIndirectCallTarget(G4_INST*);
void SetCmpSrc1Imm32(BinInst *mybin, uint32_t immediateData, G4_Operand* src);
virtual void SetCompactCtrl(BinInst *mybin, uint32_t value);
......
......@@ -2220,9 +2220,31 @@ BinaryEncodingCNL::Status BinaryEncodingCNL::DoAllEncodingCALL(G4_INST* inst)
EncodeInstHeader(inst, oneSrc.GetHeader());
EncodeOperandDst(inst, oneSrc.GetOperandControl());
//Needed for correctness
oneSrc.SetSrc1Regfile(G9HDL::REGFILE_IMM);
oneSrc.SetSrc1Srctype(GetOperandSrcHDLImmType(Type_D));
if (inst->getSrc(0) && !inst->getSrc(0)->isLabel())
{
// indirect call
G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC* ptr = (G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC*)&oneSrc;
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_REG_REG, 1>::EncodeEuInstructionSourcesReg(
inst, inst->getSrc(0), ptr->GetRegsource() //by reference
);
ptr->GetRegsource().SetSrc1Regfile(TranslateVisaToHDLRegFile(EncodingHelper::GetSrcRegFile(inst->getSrc(0))));
if (!inst->getSrc(0)->isImm())
{
ptr->GetRegsource().SetSrc1Srctype(GetOperandSrcHDLType(inst->getSrc(0)->getType()));
}
}
else
{
//Needed for correctness
oneSrc.SetSrc1Regfile(G9HDL::REGFILE_IMM);
oneSrc.SetSrc1Srctype(GetOperandSrcHDLImmType(Type_D));
}
bin->DWords[0] = oneSrc.GetDWORD(0);
bin->DWords[1] = oneSrc.GetDWORD(1);
......
......@@ -684,6 +684,14 @@ public:
unsigned return_size,
int line_no);
bool CISA_create_ifcall_instruction(VISA_opnd *pred_opnd,
Common_VISA_EMask_Ctrl emask,
unsigned exec_size,
VISA_opnd* funcAddr,
unsigned arg_size,
unsigned return_size,
int line_no);
bool CISA_create_raw_send_instruction(ISA_Opcode opcode,
unsigned char modifier,
Common_VISA_EMask_Ctrl emask,
......
......@@ -596,27 +596,43 @@ static void propagateCalleeInfo(G4_Kernel* kernel, G4_Kernel* callee)
// After compiling each compilation unit this function is invoked which stitches together callers
// with their callees. It modifies pseudo_fcall/fret in to call/ret opcodes.
void Stitch_Compiled_Units( common_isa_header header, std::list<G4_Kernel*> compilation_units )
void Stitch_Compiled_Units( common_isa_header header, std::list<G4_Kernel*>& compilation_units )
{
list <int> callee_index;
G4_Kernel* kernel = NULL;
for (std::list<G4_Kernel*>::iterator it = compilation_units.begin();
it != compilation_units.end();
it++ )
bool hasIndirectCall = false;
for (auto cur : compilation_units)
{
G4_Kernel* cur = (*it);
if( (*it)->fg.builder->getIsKernel() == true )
if (cur->fg.builder->getIsKernel())
{
ASSERT_USER( kernel == NULL, "Multiple kernel objects found when stitching together");
kernel = cur;
}
if (cur->hasIndirectCall())
{
hasIndirectCall = true;
}
}
ASSERT_USER( kernel != NULL, "Valid kernel not found when stitching compiled units");
Enumerate_Callees( header, kernel, compilation_units, callee_index );
if (hasIndirectCall)
{
// we have to include every function
for (auto&& cu : compilation_units)
{
if (!cu->fg.builder->getIsKernel())
{
callee_index.push_back(cu->fg.builder->getFuncId());
}
}
}
else
{
Enumerate_Callees(header, kernel, compilation_units, callee_index);
}
callee_index.sort();
callee_index.unique();
......@@ -628,12 +644,9 @@ void Stitch_Compiled_Units( common_isa_header header, std::list<G4_Kernel*> comp
#endif
// Append flowgraph of all callees to kernel
for( std::list<int>::iterator it = callee_index.begin();
it != callee_index.end();
it++ )
for (auto calleeId : callee_index)
{
int cur = (*it);
G4_Kernel* callee = Get_Resolved_Compilation_Unit( header, compilation_units, cur );
G4_Kernel* callee = Get_Resolved_Compilation_Unit(header, compilation_units, calleeId);
propagateCalleeInfo(kernel, callee);
for( BB_LIST_ITER bb = callee->fg.BBs.begin();
......@@ -648,49 +661,49 @@ void Stitch_Compiled_Units( common_isa_header header, std::list<G4_Kernel*> comp
kernel->fg.reassignBlockIDs();
// Change fcall/fret to call/ret and setup caller/callee edges
for( BB_LIST_ITER it = kernel->fg.BBs.begin();
it != kernel->fg.BBs.end();
it++ )
for (G4_BB* cur : kernel->fg.BBs)
{
G4_BB* cur = (*it);
if( cur->size() > 0 && cur->isEndWithFCall() )
{
// Setup successor/predecessor
G4_INST* fcall = cur->back();
int calleeIndex = fcall->asCFInst()->getCalleeIndex();
G4_Kernel* callee = Get_Resolved_Compilation_Unit( header, compilation_units, calleeIndex );
G4_BB* retBlock = cur->Succs.front();
ASSERT_USER( cur->Succs.size() == 1, "fcall basic block cannot have more than 1 successor");
ASSERT_USER( retBlock->Preds.size() == 1, "block after fcall cannot have more than 1 predecessor");
if (!fcall->asCFInst()->isIndirectCall())
{
int calleeIndex = fcall->asCFInst()->getCalleeIndex();
G4_Kernel* callee = Get_Resolved_Compilation_Unit(header, compilation_units, calleeIndex);
G4_BB* retBlock = cur->Succs.front();
ASSERT_USER(cur->Succs.size() == 1, "fcall basic block cannot have more than 1 successor");
ASSERT_USER(retBlock->Preds.size() == 1, "block after fcall cannot have more than 1 predecessor");
// Remove old edge
retBlock->Preds.erase(retBlock->Preds.begin());
cur->Succs.erase(cur->Succs.begin());
// Remove old edge
retBlock->Preds.erase(retBlock->Preds.begin());
cur->Succs.erase(cur->Succs.begin());
// Connect new fg
kernel->fg.addPredSuccEdges( cur, callee->fg.getEntryBB() );
kernel->fg.addPredSuccEdges( callee->fg.getUniqueReturnBlock(), retBlock );
// Connect new fg
kernel->fg.addPredSuccEdges(cur, callee->fg.getEntryBB());
kernel->fg.addPredSuccEdges(callee->fg.getUniqueReturnBlock(), retBlock);
G4_INST* calleeLabel = callee->fg.getEntryBB()->front();
ASSERT_USER( calleeLabel->isLabel() == true, "Entry inst is not label");
G4_INST* calleeLabel = callee->fg.getEntryBB()->front();
ASSERT_USER(calleeLabel->isLabel() == true, "Entry inst is not label");
// ret/e-mask
fcall->setSrc( fcall->getSrc(0), 1 );
// ret/e-mask
fcall->setSrc(fcall->getSrc(0), 1);
// dst label
fcall->setSrc( calleeLabel->getSrc(0), 0 );
fcall->setOpcode( G4_call );
// dst label
fcall->setSrc(calleeLabel->getSrc(0), 0);
fcall->setOpcode(G4_call);
}
else
{
fcall->setSrc(fcall->getSrc(0), 1);
fcall->setOpcode(G4_call);
}
}
}
// Change fret to ret
for( BB_LIST_ITER it = kernel->fg.BBs.begin();
it != kernel->fg.BBs.end();
it++ )
for (G4_BB* cur : kernel->fg.BBs)
{
G4_BB* cur = (*it);
if( cur->size() > 0 && cur->isEndWithFRet() )
{
G4_INST* fret = cur->back();
......@@ -701,14 +714,12 @@ void Stitch_Compiled_Units( common_isa_header header, std::list<G4_Kernel*> comp
}
// Append declarations and color attributes from all callees to kernel
for( list<int>::iterator it = callee_index.begin(); it != callee_index.end(); ++it ) {
G4_Kernel* callee;
callee = Get_Resolved_Compilation_Unit( header, compilation_units, (*it) );
for (auto it = callee_index.begin(); it != callee_index.end(); ++it )
{
G4_Kernel* callee = Get_Resolved_Compilation_Unit( header, compilation_units, (*it) );
for( DECLARE_LIST_ITER dcl_it = callee->Declares.begin(); dcl_it != callee->Declares.end(); ++dcl_it ) {
G4_Declare* curDcl;
curDcl = *dcl_it;
for (auto curDcl : callee->Declares)
{
kernel->Declares.push_back( curDcl );
}
}
......@@ -2672,6 +2683,20 @@ bool CISA_IR_Builder::CISA_create_fcall_instruction(VISA_opnd *pred_opnd,
return true;
}
bool CISA_IR_Builder::CISA_create_ifcall_instruction(VISA_opnd *pred_opnd,
Common_VISA_EMask_Ctrl emask,
unsigned exec_size,
VISA_opnd* funcAddr,
unsigned arg_size,
unsigned return_size,
int line_no) //last index
{
Common_ISA_Exec_Size executionSize = Get_Common_ISA_Exec_Size_From_Raw_Size(exec_size);
m_kernel->AppendVISACFIndirectFuncCallInst((VISA_PredOpnd *)pred_opnd, emask, executionSize,
(VISA_VectorOpnd*) funcAddr, (uint8_t) arg_size, (uint8_t) return_size);
return true;
}
bool CISA_IR_Builder::CISA_create_raw_send_instruction(ISA_Opcode opcode,
unsigned char modifier,
Common_VISA_EMask_Ctrl emask,
......
......@@ -1806,6 +1806,13 @@ public:
uint8_t argSize,
uint8_t returnSize);
int translateVISACFIFCallInst(Common_ISA_Exec_Size execsize,
Common_VISA_EMask_Ctrl emask,
G4_Predicate *predOpnd,
G4_Operand* funcAddr,
uint8_t argSize,
uint8_t returnSize);
int translateVISACFFretInst(Common_ISA_Exec_Size execsize,
Common_VISA_EMask_Ctrl emask,
G4_Predicate *predOpnd);
......
......@@ -1225,6 +1225,17 @@ static void readInstructionControlFlow(unsigned& bytePos, const char* buf, ISA_O
return;
}
case ISA_IFCALL:
{
readExecSizeNG(bytePos, buf, esize, emask, container);
VISA_PredOpnd* pred = hasPredicate(opcode) ? readPredicateOperandNG(bytePos, buf, container) : nullptr;
VISA_VectorOpnd* funcAddr = readVectorOperandNG(bytePos, buf, container, false);
uint8_t argSize = readPrimitiveOperandNG<uint8_t>(bytePos, buf);
uint8_t retSize = readPrimitiveOperandNG<uint8_t>(bytePos, buf);
kernelBuilder->AppendVISACFIndirectFuncCallInst(pred, emask, esize, funcAddr, argSize, retSize);
return;
}
case ISA_SWITCHJMP:
{
Common_VISA_EMask_Ctrl emask = vISA_EMASK_M1;
......
......@@ -396,7 +396,13 @@ jmp|call|ret|fret|fcall|goto {
TRACE("\n** branch INST ");
CISAlval.opcode = str2opcode(yytext);
return BRANCH_OP;
}
}
ifcall {
TRACE("\n** indirect call INST ");
CISAlval.opcode = ISA_IFCALL;
return IFCALL;
}
switchjmp {
TRACE("\n** branch INST ");
......
......@@ -394,6 +394,7 @@ VISA_RawOpnd* rawOperandArray[16];
%token <opcode> VME_SIC_OP
%token <opcode> VME_FBR_OP
%token <opcode> BRANCH_OP
%token <opcode> IFCALL
%token <opcode> SWITCHJMP_OP
%token <opcode> SIMDCF_OP
%token <opcode> MOVS_OP
......@@ -1307,6 +1308,12 @@ BranchInstruction : Predicate BRANCH_OP ExecSize TargetLabel
//int num_parameters = 1;
pCisaBuilder->CISA_create_fcall_instruction($1.cisa_gen_opnd, $2, $3.emask, $3.exec_size, (unsigned)$4, (unsigned)$5, (unsigned)$6, CISAlineno);
}
// 1 2 3 4 5 6
| Predicate IFCALL ExecSize VecSrcOperand_G_I_IMM NUMBER NUMBER
{
pCisaBuilder->CISA_create_ifcall_instruction($1.cisa_gen_opnd, $3.emask, $3.exec_size,
$4.cisa_gen_opnd, (unsigned)$5, (unsigned)$6, CISAlineno);
}
// 1 2 3
CondtionInstruction : Predicate SIMDCF_OP ExecSize
......
......@@ -508,8 +508,9 @@ bool hasExecSize(ISA_Opcode op, uint8_t subOp)
bool hasLabelSrc(ISA_Opcode op)
{
if( ISA_Inst_Table[op].type == ISA_Inst_Flow){
if( op == ISA_RET || op == ISA_FRET )
if( ISA_Inst_Table[op].type == ISA_Inst_Flow)
{
if (op == ISA_RET || op == ISA_FRET || op == ISA_IFCALL)
return false;
else //( op == ISA_SUBROUTINE || op == ISA_LABEL || op == ISA_JMP || op == ISA_CALL || op == ISA_FCALL )
return true;
......
......@@ -5902,6 +5902,56 @@ unsigned int G4_Kernel::getNumCalleeSaveRegs()
return totalGRFs - calleeSaveStart() - getNumScratchRegs();
}
void RelocationEntry::doRelocation(void* binary, uint32_t binarySize)
{
switch (relocType)
{
case RelocationType::IndirectCall:
{
// need an IGA function
// replaceImm32Value(char* instOffset, uint32_t val);
// that will replace the imm32 value used by the instruction
// located at instOffset with value 'val'
// for now we assume inst is uncompacted and the imm32 is always at byte 3
uint32_t relocVal = (uint32_t) indirectCallInst->getGenOffset();
uint32_t instOffset = (uint32_t) inst->getGenOffset();
assert (relocVal < binarySize && instOffset < binarySize && "invalid relocation offset");
uint32_t* immLoc = (uint32_t*) ((char*) binary + instOffset + 12);
*immLoc = relocVal;
break;
}
default:
assert(false && "unhandled relocation type");
}
}
void RelocationEntry::dump() const
{
std::cerr << "Relocation entry: " << getTypeString() << "\n";
std::cerr << "\t";
inst->dump();
switch (relocType)
{
case RelocationType::IndirectCall:
std::cerr << "call inst (offset=" << indirectCallInst->getGenOffset() << "):\t";
indirectCallInst->dump();
}
std::cerr << "\n";
}
//
// perform relocation for every entry in the allocation table
//
void G4_Kernel::doRelocation(void* binary, uint32_t binarySize)
{
for (auto&& entry : relocationTable)
{
entry.doRelocation(binary, binarySize);
}
}
void SCCAnalysis::run()
{
SCCNodes.resize(cfg.getNumBB());
......
......@@ -1168,6 +1168,66 @@ private:
gtpin::igc::igc_init_t* gtpin_init = nullptr;
};
enum class RelocationType
{
IndirectCall, // patched value is the address of an indirect call inst
};
class RelocationEntry
{
G4_INST* inst; // instruction to be relocated
int opndPos; // operand to be relocated. This should be a RelocImm
RelocationType relocType;
G4_INST* indirectCallInst = nullptr; // the call inst for the indirect call relocation
RelocationEntry(G4_INST* i, int pos, RelocationType type, G4_INST* call) :
inst(i), opndPos(pos), relocType(type), indirectCallInst(call) {}
public:
static RelocationEntry createIndirectCallReloc(G4_INST* inst, int opndPos, G4_INST* callInst)
{
RelocationEntry entry(inst, opndPos, RelocationType::IndirectCall, callInst);
return entry;
}
G4_INST* getInst() const
{
return inst;
}
RelocationType getType() const
{
return relocType;
}
const char* getTypeString() const
{
switch (relocType)
{
case RelocationType::IndirectCall:
return "IndirectCall";
default:
assert(false && "unhanlded relocation type");
return "";
}
}
uint32_t getOpndPos() const
{
return opndPos;
}
G4_INST* getIndirectCallInst() const
{
assert(relocType == RelocationType::IndirectCall && "invalid relocation type");
return indirectCallInst;
}
void doRelocation(void* binary, uint32_t binarySize);
void dump() const;
};
class G4_Kernel
{
const char* name;
......@@ -1203,6 +1263,11 @@ class G4_Kernel
unsigned int callerSaveLastGRF;
bool m_hasIndirectCall = false;
// stores all relocations to be performed after binary encoding
std::vector<RelocationEntry> relocationTable;
public:
FlowGraph fg;
DECLARE_LIST Declares;
......@@ -1363,6 +1428,22 @@ public:
unsigned int getNumCalleeSaveRegs();
void renameAliasDeclares();
bool hasIndirectCall() const
{
return m_hasIndirectCall;
}
void setHasIndirectCall()
{
m_hasIndirectCall = true;
}
void addRelocation(RelocationEntry& entry)
{
relocationTable.push_back(entry);
}
void doRelocation(void* binary, uint32_t binarySize);
};
class SCCAnalysis
......
......@@ -611,9 +611,7 @@ class G4_FCALL
public:
G4_FCALL(uint16_t argVarSz, uint16_t retVarSz) : argSize(argVarSz), retSize(retVarSz)
{
}
{}
void *operator new(size_t sz, Mem_Manager& m) {return m.alloc(sz);}
......@@ -1299,6 +1297,8 @@ class G4_InstCF : public G4_INST
public:
static const uint32_t unknownCallee = 0xFFFF;
G4_InstCF(
USE_DEF_ALLOCATOR& allocator,
std::vector<G4_INST*>& instList,
......@@ -1312,7 +1312,7 @@ public:
G4_Operand* s1,
unsigned int opt) :
G4_INST(allocator, instList, prd, o, m, sat, size, d, s0, s1, opt),
jip(NULL), uip(NULL), isBackwardBr(false), calleeIndex(0),
jip(NULL), uip(NULL), isBackwardBr(false), calleeIndex(unknownCallee),
assocPseudoVCA(nullptr), assocPseudoA0Save(nullptr), assocPseudoFlagSave(nullptr)
{
if( o == G4_break || o == G4_cont || o == G4_halt )
......@@ -1414,6 +1414,25 @@ public:
return calleeIndex;
}
bool isIndirectCall() const
{
return op == G4_pseudo_fcall && getCalleeIndex() == G4_InstCF::unknownCallee;
}
// for direct call, this is null till after the compilation units are stitched together
// for indirect call, this is src0
G4_Operand* getCalleeAddress() const
{
if (op == G4_pseudo_fcall)
{
return getSrc(0);
}
else
{
return nullptr;
}
}
void setAssocPseudoVCA(G4_RegVar* var)
{
MUST_BE_TRUE(op == G4_pseudo_fcall, "Must be a FCALL");
......
......@@ -116,7 +116,7 @@ struct ISA_Inst_Info ISA_Inst_Table[ISA_OPCODE_ENUM_SIZE] =
{ ISA_SCATTER4_TYPED, ISA_Inst_Data_Port, "scatter4_typed", 8, 0 },
{ ISA_VA_SKL_PLUS, ISA_Inst_Sampler, "va_skl_plus", 0, 0 },
{ ISA_SVM, ISA_Inst_SVM, "svm", 0, 0 },
{ ISA_RESERVED_4F, ISA_Inst_Reserved, "reserved4F", 0, 0 },
{ ISA_IFCALL, ISA_Inst_Flow, "ifcall", 3, 0 },
{ ISA_RESERVED_50, ISA_Inst_Misc, "reserved50", 0, 0 },
{ ISA_FILE, ISA_Inst_Misc, "file", 1, 0 },
{ ISA_LOC, ISA_Inst_Misc, "loc", 1, 0 },
......@@ -1092,8 +1092,13 @@ VISA_INST_Desc CISA_INST_table[ISA_NUM_OPCODE] =
},
/// 79
{ ALL, ISA_RESERVED_4F, ISA_Inst_Reserved, "reserved_4f", 0, 0,
{ ALL, ISA_IFCALL, ISA_Inst_Flow, "ifcall", 5, 0,
{
{ OPND_EXECSIZE, ISA_TYPE_UB, 0 },
{ OPND_PRED, ISA_TYPE_UW, 0 },
{ OPND_KIND, ISA_TYPE_UD, 0 }, /// function_addr
{ OPND_KIND, ISA_TYPE_UB, 0 }, /// arg_size
{ OPND_KIND, ISA_TYPE_UB, 0 }, /// return_size
},
},
......
......@@ -905,23 +905,17 @@ static string printInstructionControlFlow(const common_isa_header& isaHeader, co
case ISA_GOTO:
case ISA_FCALL:
{
if (opcode == ISA_JMP ||
opcode == ISA_CALL ||
opcode == ISA_GOTO ||
opcode == ISA_FCALL)
{
/// label / function id to jump / call to.
label_id = getPrimitiveOperand<uint16_t>(inst, i++);
/// label / function id to jump / call to.
label_id = getPrimitiveOperand<uint16_t>(inst, i++);
if (opcode == ISA_FCALL)
{
sstr << " " << (unsigned) label_id;
}
else
{
sstr << " " << header->strings[header->labels[label_id].name_index];
if (header->labels[label_id].kind == LABEL_SUBROUTINE) sstr << "_" << label_id;
}
if (opcode == ISA_FCALL)
{
sstr << " " << (unsigned)label_id;
}
else
{
sstr << " " << header->strings[header->labels[label_id].name_index];
if (header->labels[label_id].kind == LABEL_SUBROUTINE) sstr << "_" << label_id;
}
if (opcode == ISA_FCALL)
......@@ -935,6 +929,15 @@ static string printInstructionControlFlow(const common_isa_header& isaHeader, co
break;
}
case ISA_IFCALL:
{
sstr << printOperand(isaHeader, header, inst, i++, opt);
/// arg size
sstr << " " << getPrimitiveOperand<unsigned>(inst, i++);