2015-02-08 84 views
0

我正嘗試通過嵌入式操作碼創建一個PPU解釋器來執行處理程序來解釋指令。一條指令可以是幾種形式之一(I表單,B表單,D表單,X表單等),但是對於主操作碼31,X表單有一個小問題。我使用一個模板類InterpretArray自動分配數組中的處理程序。這個類也可以用作可以從處理程序調用的處理程序的子數組。編譯器VS2013給我致命的錯誤:有人可以解釋爲什麼我在這裏得到致命錯誤C1202以及如何解決它?

1>main.cpp(196): fatal error C1202: recursive type or function dependency context too complex

template < size_t xo_rc > 
struct Interpreter < X_Form_31_XORc <xo_rc> > 

這聽起來像編譯器不喜歡X_Form_31_XORc,任何想法,爲什麼?我怎樣才能避免它?

這裏如果X_FORM是不確定的,可以被編譯罰款來源:

#include <iostream> 

#define B_FORM 
//#define X_FORM 

using namespace std; 

// Dummy stuff 

typedef unsigned int u32; 
typedef signed int s32; 

union Instruction 
{ 
#define FIELD(from, to, type) struct{ u32:(32-to-1); type:(to-from+1); u32:from; } 
    u32 instruction; 

    // Opcode fields 
    FIELD(0, 5, u32 opcode); // Primary opcode 
    FIELD(26, 31, u32 op4);  // Extended opcode of 6-bits (up to 0x3F) 
    FIELD(21, 31, u32 op4_); // Extended opcode of 11-bits (up to 0x7FF) 
    FIELD(21, 30, u32 op19); // Extended opcode of 10-bits (up to 0x3FF) 
    FIELD(27, 29, u32 op30); // Extended opcode of 3-bits (up to 0x7) 
    FIELD(21, 30, u32 op31); // Extended opcode of 10-bits (up to 0x3FF) 
    FIELD(30, 31, u32 op58); // Extended opcode of 2-bits (up to 0x3) 
    FIELD(26, 30, u32 op59); // Extended opcode of 5-bits (up to 0x1F) 
    FIELD(30, 31, u32 op62); // Extended opcode of 2-bits (up to 0x3) 
    FIELD(26, 30, u32 op63); // Extended opcode of 5-bits (up to 0x1F) 
    FIELD(21, 30, u32 op63_); // Extended opcode of 10-bits (up to 0x3FF) 

    // Instruction fields 
    FIELD(30, 30, u32 aa);  // Bit/Flags: Absolute address bit 
    FIELD(31, 31, u32 lk);  // Bit/Flags: Link bit: Update the link register (LR) 
    FIELD(21, 21, u32 oe);  // Bit/Flags: OE bit: Enable enable setting OV and SO in the XER 
    FIELD(31, 31, u32 rc);  // Bit/Flags: Record bit: Update the condition register (CR) 
    FIELD(6, 6, u32 l6);  // Bit/Flags: ? 
    FIELD(10, 10, u32 l10);  // Bit/Flags: ? 
    FIELD(11, 11, u32 l11);  // Bit/Flags: ? 
    FIELD(9, 10, u32 l9_10); // Bit/Flags: ? 
    FIELD(6, 10, u32 bo);  // Branching: Options for the branch conditional instructions 
    FIELD(11, 15, u32 bi);  // Branching: CR bit to trigger branch conditional instructions 
    FIELD(16, 29, s32 bd);  // Branching: Immediate 14-bit signed integer for branch displacement 
    FIELD(19, 20, u32 bh);  // ? 
    FIELD(11, 13, u32 bfa);  // ? 
    FIELD(6, 8, u32 crfd); // CR fields: Destination CR or FPSCR field 
    FIELD(11, 13, u32 crfs); // CR fields: Source CR or FPSCR field 
    FIELD(6, 10, u32 crbd); // CR fields: Destination bit in the CR or FPSCR 
    FIELD(11, 15, u32 crba); // CR fields: Source bit in the CR 
    FIELD(16, 20, u32 crbb); // CR fields: Source bit in the CR 
    FIELD(12, 19, u32 crm);  // Identify the CR fields that are to be updated by the mtcrf instruction 
    FIELD(16, 31, s32 d);  // Immediate 16-bit signed integer 
    FIELD(16, 27, u32 dq);  // ? 
    FIELD(16, 29, s32 ds);  // ? 
    FIELD(7, 14, u32 fm);  // ? 
    FIELD(6, 10, u32 frd);  // FPR: Destination 
    FIELD(6, 10, u32 frs);  // FPR: Source 
    FIELD(11, 15, u32 fra);  // FPR: Source 
    FIELD(16, 20, u32 frb);  // FPR: Source 
    FIELD(21, 25, u32 frc);  // FPR: Source 
    FIELD(16, 19, u32 imm);  // Immediate for to place in FPSCR 
    FIELD(6, 29, s32 li);  // Branching: 
    FIELD(6, 29, s32 ll);  // Branching: 
    FIELD(21, 25, u32 mb);  // First '1' bit of a 64-bit mask in rotate instructions 
    FIELD(26, 26, u32 mb_);  // First '1' bit of a 64-bit mask in rotate instructions: Split field 
    FIELD(26, 30, u32 me);  // Last '1' bit of a 64-bit mask in rotate instructions 
    FIELD(21, 25, u32 me_);  // Last '1' bit of a 64-bit mask in rotate instructions: Split field 
    FIELD(26, 26, u32 me__); // Last '1' bit of a 64-bit mask in rotate instructions: Split field 
    FIELD(16, 20, u32 nb);  // Number of bytes to move in an immediate string load or store 
    FIELD(6, 10, u32 rd);  // GPR: Destination 
    FIELD(6, 10, u32 rs);  // GPR: Source 
    FIELD(11, 15, u32 ra);  // GPR: Source 
    FIELD(16, 20, u32 rb);  // GPR: Source 
    FIELD(16, 20, u32 sh);  // Shift amount 
    FIELD(30, 30, u32 sh_);  // Shift amount: Split field 
    FIELD(11, 20, u32 spr);  // Special-purpose register 
    FIELD(9, 10, u32 strm); // ? 
    FIELD(20, 26, u32 lev);  // ? 
    FIELD(16, 31, s32 simm); // Immediate 16-bit signed integer 
    FIELD(16, 31, u32 uimm); // Immediate 16-bit unsigned integer 
    FIELD(9, 10, u32 th);  // Data stream variant of the dcbt instruction 
    FIELD(6, 10, u32 to);  // Trap conditions 
    FIELD(6, 10, u32 vd);  // Vector/SIMD: Destination vector register 
    FIELD(6, 10, u32 vs);  // Vector/SIMD: Source vector register 
    FIELD(11, 15, u32 va);  // Vector/SIMD: Source vector register 
    FIELD(16, 20, u32 vb);  // Vector/SIMD: Source vector register 
    FIELD(21, 25, u32 vc);  // Vector/SIMD: Source vector register 
    FIELD(22, 25, u32 vshb); // Vector/SIMD: Specifies a shift amount in bytes 
    FIELD(11, 15, s32 vsimm); // Vector/SIMD: Immediate 5-bit signed integer 
    FIELD(11, 15, u32 vuimm); // Vector/SIMD: Immediate 5-bit unsigned integer 
#undef FIELD 
}; 

struct PPUThread {}; // register context but we do not need it here 

// Opcode part 

// auto-initialize by recursively assigning all handlers in an opcode array 
template< template<typename> class Handler, 
      template< size_t > class Indexer, 
      size_t      start_index, 
      size_t      end_index > 
struct OpcodeArrayRange 
{ 
    template< typename Owner > 
    static __forceinline void initialize(Owner & owner) 
    { 
     owner.array[start_index] = Handler< Indexer<start_index> >::handle; 
     OpcodeArrayRange< Handler, Indexer, start_index + 1, end_index >::initialize(owner); 
    } 
}; 

// auto-initialize by assigning the last handler in an opcode array 
template< template<typename> class Handler, 
      template< size_t > class Indexer, 
      size_t      start_index > 
struct OpcodeArrayRange < Handler, Indexer, start_index, start_index > 
{ 
    template< typename Owner > 
    static __forceinline void initialize(Owner & owner) 
    { 
     owner.array[start_index] = Handler< Indexer<start_index> >::handle; 
    } 
}; 

template < size_t po > 
struct OPCD // Primary opcode, used for Indexer in OpcodeArrayRange 
{ 
}; 

#ifdef B_FORM 

template < size_t po > 
using B_Form = OPCD <po>; 

template < size_t bo_bi > 
struct B_Form_BOBI 
{ 
}; 

#endif 

#ifdef X_FORM 

template < size_t po > 
using X_Form = OPCD <po> ; // Primary opcode + Extended opcode + Record bit 

template < size_t po, size_t xo, size_t rc > 
struct X_Form_XO_Rc // Primary opcode + Extended opcode + Record bit 
{ 
}; 

template < size_t po, size_t xo_rc > 
struct X_Form_XORc // glue Extended opcode and Record bit into one field, used for Indexer in OpcodeArrayRange 
{ 
}; 

template < size_t xo_rc > 
using X_Form_31_XORc = X_Form_XORc < 31, xo_rc > ; // alias to X_Form_XORc with Primary opcode 31 

#endif 

// Interpreter part 

template< typename T > 
struct Interpreter 
{ 
}; 

// generic interpreter array 
template< template<size_t> class OpcodeFormat, 
      size_t     start_index, 
      size_t     end_index > 
struct InterpretArray : 
    OpcodeArrayRange < Interpreter, OpcodeFormat, start_index, end_index > 
{ 
    InterpretArray() 
    { 
     initialize(*this); 
    } 

    __forceinline void operator()(size_t  index, 
            Instruction code, 
            PPUThread& thread) 
    { 
     array[index](code, thread); 
    } 

    void(*array[1 + end_index - start_index])(Instruction, PPUThread&); 
}; 

// implementation for interpreting opcodes 

template< size_t po > 
struct Interpreter < OPCD <po> > 
{ 
    static void handle(Instruction /*code*/, PPUThread& /*thread*/) 
    { 
     std::cout 
      << "OPCD #" 
      << po 
      << std::endl; 
    } 
}; 

#ifdef B_FORM 

template < size_t bo_bi > 
struct Interpreter < B_Form_BOBI <bo_bi> > 
{ 
    static void handle(Instruction code, PPUThread& thread) 
    { 
     std::cout 
      << "OPCD #31, BO #" 
      << (bo_bi >> 5) 
      << ", BI #" 
      << (bo_bi & 31) 
      << ", AA #" 
      << (code.aa) 
      << ", LK #" 
      << (code.lk) 
      << std::endl; 
    } 
}; 

static InterpretArray < B_Form_BOBI, 0, 0x3FF > interpret_B_Form_BOBI; 

template< > 
struct Interpreter < B_Form <16> > 
{ 
    static void handle(Instruction code, PPUThread& thread) 
    { 
     interpret_B_Form_BOBI((code.instruction >> 16) & 0x3FF, code, thread); 
    } 
}; 

#endif 

#ifdef X_FORM 

template < size_t xo_rc > 
struct Interpreter < X_Form_31_XORc <xo_rc> > 
{ 
    static void handle(Instruction /*code*/, PPUThread& /*thread*/) 
    { 
     std::cout 
      << "OPCD #31, XO #" 
      << (xo_rc >> 1) 
      << ", RC#" 
      << (xo_rc & 1) 
      << std::endl; 
    } 
}; 

// specific interpreter array for instructions selected by their extended code 
// and Record bit when primary opcode is 31 
static InterpretArray < X_Form_31_XORc, 0, 0x7FF > interpret_X_Form_31; 

template< > 
struct Interpreter < X_Form <31> > // note that X_Form is an alias to OPCD 
{ 
    static void handle(Instruction code, PPUThread& thread) 
    { 
     interpret_X_Form_31((code.instruction & 0x7FF), code, thread); 
    } 
}; 

#endif 

// specific interpreter array for instructions 
// selected by primary opcode 
static InterpretArray < OPCD, 0, 0x3F > interpret; 

int main() 
{ 
    Instruction insn; 
    PPUThread thread; 

    { 
     insn.opcode = 2; 
     interpret(insn.opcode, insn, thread); 
    } 
#ifdef B_FORM 
    { 
     insn.opcode = 16; 
     insn.bo = 2; 
     insn.bi = 3; 
     insn.aa = 1; 
     insn.lk = 1; 
     interpret(insn.opcode, insn, thread); 
    } 
#endif 
#ifdef X_FORM 
    { 
     insn.opcode = 31; 
     insn.op31 = 2; 
     insn.rc = 0; 
     interpret(insn.opcode, insn, thread); 
    } 
    { 
     insn.opcode = 31; 
     insn.op31 = 2; 
     insn.rc = 1; 
     interpret(insn.opcode, insn, thread); 
    } 
#endif 
} 

編輯:我加B_Form它類似於X_Form但不使用別名,它的工作原理(但建設速度很慢) 。

+0

我添加了B_Form,它類似於X_Form,但沒有使用別名,它的工作原理(但建設很慢) – hlide 2015-02-08 18:16:24

回答

2
template< template<typename> class Handler, 
      template< size_t > class Indexer, 
      size_t      start_index, 
      size_t      end_index > 
struct OpcodeArrayRange 
{ 
    template< typename Owner > 
    static __forceinline void initialize(Owner & owner) 
    { 
     owner.array[start_index] = Handler< Indexer<start_index> >::handle; 
     OpcodeArrayRange< Handler, Indexer, start_index + 1, end_index >::initialize(owner); 
    } 
}; 

...

template< template<size_t> class OpcodeFormat, 
      size_t     start_index, 
      size_t     end_index > 
struct InterpretArray : 
    OpcodeArrayRange < Interpreter, OpcodeFormat, start_index, end_index > 

...

static InterpretArray < X_Form_31_XORc, 0, 0x7FF > interpret_X_Form_31; 

InterpretArray < X_Form_31_XORc, 0, 0x7FF >實例化觸發它的基類OpcodeArrayRange < Interpreter, X_Form_31_XORc, 0, 0x7FF >的實例化。

OpcodeArrayRange < Interpreter, X_Form_31_XORc, 0, 0x7FF >的實例化觸發了OpcodeArrayRange < Interpreter, X_Form_31_XORc, 1, 0x7FF >的實例化,因爲您如何定義了initialize方法。

由於您如何定義initialize方法,因此OpcodeArrayRange < Interpreter, X_Form_31_XORc, 1, 0x7FF >的實例化會觸發OpcodeArrayRange < Interpreter, X_Form_31_XORc, 2, 0x7FF >的實例化。

OpcodeArrayRange < Interpreter, X_Form_31_XORc, 2, 0x7FF >的實例化觸發了OpcodeArrayRange < Interpreter, X_Form_31_XORc, 3, 0x7FF >的實例化,因爲您如何定義了initialize方法。

這種遞歸的模板實例化受到限制。你已經超出了你的編譯器的限制(以及GCC和clang的)。您可能根本不應該在您的initialize方法中引用其他模板實例。

+0

所以我認爲AndyG(是否抹去了他的評論?爲什麼? vc2012/2013,因爲如果我嘗試使用vc2015 +的在線編譯器(http://webcompiler.cloudapp.net/)構建,我不會看到這個錯誤,但編譯器會停止,因爲構建過程需要太多時間。 – hlide 2015-02-08 18:26:01

+0

@hlide在VC2015中可能已經更改了允許的最大模板實例化深度。從[C++ 11/14 Visual Studio 14 CTP1特性表]的評論(http://blogs.msdn.com/b/vcblog/archive/2014/06/11/c-11-14-feature- tables-for-visual-studio-14-ctp1.aspx):「IIRC,編譯器的限制是500. N3936的建議限制是1024或更高,所以我會要求編譯器團隊考慮更改它。」 - Stephan T. Lavavej – hvd 2015-02-08 18:43:23

+0

我在vc2013(限制:500次迭代)下構建B_FORM(1024次迭代),沒有致命錯誤。你的評論是正確的,我上面提到的情況(因爲我真的有這個問題),但不是你回答的那個。我認爲這是因爲這裏沒有遞歸實例,可能是因爲它只是一個調用另一個靜態函數的靜態函數,而不是遞歸派生類的實例。 – hlide 2015-02-08 19:02:06

相關問題