2015-02-08 50 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

相关问题