X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=utils%2FTableGen%2FEDEmitter.cpp;h=e171da02a2f8c664e0c2ddb3e2f78968cc8f4a08;hb=5d4314ef720630e6547fe41efec1608d4c14c78e;hp=214941071ebb668cda2bb4c27ea62dcdd396b6c8;hpb=5e81716425dc3373fbc834bfa7936a5c1205579b;p=oota-llvm.git diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp index 214941071eb..e171da02a2f 100644 --- a/utils/TableGen/EDEmitter.cpp +++ b/utils/TableGen/EDEmitter.cpp @@ -19,15 +19,14 @@ #include "CodeGenTarget.h" #include "Record.h" +#include "llvm/MC/EDInstInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" -#include +#include #include - -#define MAX_OPERANDS 5 -#define MAX_SYNTAXES 2 +#include using namespace llvm; @@ -36,39 +35,39 @@ using namespace llvm; /////////////////////////////////////////////////////////// namespace { - + class EnumEmitter { private: std::string Name; std::vector Entries; public: - EnumEmitter(const char *N) : Name(N) { + EnumEmitter(const char *N) : Name(N) { } - int addEntry(const char *e) { + int addEntry(const char *e) { Entries.push_back(std::string(e)); - return Entries.size() - 1; + return Entries.size() - 1; } void emit(raw_ostream &o, unsigned int &i) { o.indent(i) << "enum " << Name.c_str() << " {" << "\n"; i += 2; - + unsigned int index = 0; unsigned int numEntries = Entries.size(); - for(index = 0; index < numEntries; ++index) { + for (index = 0; index < numEntries; ++index) { o.indent(i) << Entries[index]; - if(index < (numEntries - 1)) + if (index < (numEntries - 1)) o << ","; o << "\n"; } - + i -= 2; o.indent(i) << "};" << "\n"; } - + void emitAsFlags(raw_ostream &o, unsigned int &i) { o.indent(i) << "enum " << Name.c_str() << " {" << "\n"; i += 2; - + unsigned int index = 0; unsigned int numEntries = Entries.size(); unsigned int flag = 1; @@ -79,98 +78,101 @@ namespace { o << "\n"; flag <<= 1; } - - i -= 2; - o.indent(i) << "};" << "\n"; - } - }; - class StructEmitter { - private: - std::string Name; - std::vector MemberTypes; - std::vector MemberNames; - public: - StructEmitter(const char *N) : Name(N) { - } - void addMember(const char *t, const char *n) { - MemberTypes.push_back(std::string(t)); - MemberNames.push_back(std::string(n)); - } - void emit(raw_ostream &o, unsigned int &i) { - o.indent(i) << "struct " << Name.c_str() << " {" << "\n"; - i += 2; - - unsigned int index = 0; - unsigned int numMembers = MemberTypes.size(); - for (index = 0; index < numMembers; ++index) { - o.indent(i) << MemberTypes[index] << " " << MemberNames[index] << ";"; - o << "\n"; - } - i -= 2; o.indent(i) << "};" << "\n"; } }; - + class ConstantEmitter { public: virtual ~ConstantEmitter() { } virtual void emit(raw_ostream &o, unsigned int &i) = 0; }; - + class LiteralConstantEmitter : public ConstantEmitter { private: - std::string Literal; + bool IsNumber; + union { + int Number; + const char* String; + }; public: - LiteralConstantEmitter(const char *literal) : Literal(literal) { + LiteralConstantEmitter(int number = 0) : + IsNumber(true), + Number(number) { + } + void set(const char *string) { + IsNumber = false; + Number = 0; + String = string; } - LiteralConstantEmitter(int literal) { - char buf[256]; - snprintf(buf, 256, "%d", literal); - Literal = buf; + bool is(const char *string) { + return !strcmp(String, string); } void emit(raw_ostream &o, unsigned int &i) { - o << Literal; + if (IsNumber) + o << Number; + else + o << String; } }; - + class CompoundConstantEmitter : public ConstantEmitter { private: - std::vector Entries; + unsigned int Padding; + std::vector Entries; public: - CompoundConstantEmitter() { - } - ~CompoundConstantEmitter() { - unsigned int index; - unsigned int numEntries = Entries.size(); - for (index = 0; index < numEntries; ++index) { - delete Entries[index]; - } + CompoundConstantEmitter(unsigned int padding = 0) : Padding(padding) { } CompoundConstantEmitter &addEntry(ConstantEmitter *e) { Entries.push_back(e); + return *this; } + ~CompoundConstantEmitter() { + while (Entries.size()) { + ConstantEmitter *entry = Entries.back(); + Entries.pop_back(); + delete entry; + } + } void emit(raw_ostream &o, unsigned int &i) { o << "{" << "\n"; i += 2; - + unsigned int index; unsigned int numEntries = Entries.size(); - for (index = 0; index < numEntries; ++index) { + + unsigned int numToPrint; + + if (Padding) { + if (numEntries > Padding) { + fprintf(stderr, "%u entries but %u padding\n", numEntries, Padding); + llvm_unreachable("More entries than padding"); + } + numToPrint = Padding; + } else { + numToPrint = numEntries; + } + + for (index = 0; index < numToPrint; ++index) { o.indent(i); - Entries[index]->emit(o, i); - if (index < (numEntries - 1)) + if (index < numEntries) + Entries[index]->emit(o, i); + else + o << "-1"; + + if (index < (numToPrint - 1)) o << ","; o << "\n"; } - + i -= 2; o.indent(i) << "}"; } }; - + class FlagsConstantEmitter : public ConstantEmitter { private: std::vector Flags; @@ -186,7 +188,7 @@ namespace { unsigned int numFlags = Flags.size(); if (numFlags == 0) o << "0"; - + for (index = 0; index < numFlags; ++index) { o << Flags[index].c_str(); if (index < (numFlags - 1)) @@ -216,50 +218,41 @@ void populateOperandOrder(CompoundConstantEmitter *operandOrder, const CodeGenInstruction &inst, unsigned syntax) { unsigned int numArgs = 0; - + AsmWriterInst awInst(inst, syntax, -1, -1); - + std::vector::iterator operandIterator; - + for (operandIterator = awInst.Operands.begin(); operandIterator != awInst.Operands.end(); ++operandIterator) { - if (operandIterator->OperandType == + if (operandIterator->OperandType == AsmWriterOperand::isMachineInstrOperand) { - char buf[2]; - snprintf(buf, sizeof(buf), "%u", operandIterator->CGIOpNo); - operandOrder->addEntry(new LiteralConstantEmitter(buf)); + operandOrder->addEntry( + new LiteralConstantEmitter(operandIterator->CGIOpNo)); numArgs++; } } - - for(; numArgs < MAX_OPERANDS; numArgs++) { - operandOrder->addEntry(new LiteralConstantEmitter("-1")); - } } ///////////////////////////////////////////////////// // Support functions for handling X86 instructions // ///////////////////////////////////////////////////// -#define ADDFLAG(flag) flags->addEntry(flag) +#define SET(flag) { type->set(flag); return 0; } -#define REG(str) if (name == str) { ADDFLAG("kOperandFlagRegister"); return 0; } -#define MEM(str) if (name == str) { ADDFLAG("kOperandFlagMemory"); return 0; } -#define LEA(str) if (name == str) { ADDFLAG("kOperandFlagEffectiveAddress"); \ - return 0; } -#define IMM(str) if (name == str) { ADDFLAG("kOperandFlagImmediate"); \ - return 0; } -#define PCR(str) if (name == str) { ADDFLAG("kOperandFlagMemory"); \ - ADDFLAG("kOperandFlagPCRelative"); \ - return 0; } +#define REG(str) if (name == str) SET("kOperandTypeRegister"); +#define MEM(str) if (name == str) SET("kOperandTypeX86Memory"); +#define LEA(str) if (name == str) SET("kOperandTypeX86EffectiveAddress"); +#define IMM(str) if (name == str) SET("kOperandTypeImmediate"); +#define PCR(str) if (name == str) SET("kOperandTypeX86PCRelative"); -/// X86FlagFromOpName - Processes the name of a single X86 operand (which is -/// actually its type) and translates it into an operand flag +/// X86TypeFromOpName - Processes the name of a single X86 operand (which is +/// actually its type) and translates it into an operand type /// -/// @arg flags - The flags object to add the flag to +/// @arg flags - The type object to set /// @arg name - The name of the operand -static int X86FlagFromOpName(FlagsConstantEmitter *flags, +static int X86TypeFromOpName(LiteralConstantEmitter *type, const std::string &name) { REG("GR8"); REG("GR8_NOREX"); @@ -276,12 +269,23 @@ static int X86FlagFromOpName(FlagsConstantEmitter *flags, REG("RFP64"); REG("RFP80"); REG("VR128"); + REG("VR256"); REG("RST"); REG("SEGMENT_REG"); REG("DEBUG_REG"); - REG("CONTROL_REG_32"); - REG("CONTROL_REG_64"); - + REG("CONTROL_REG"); + + IMM("i8imm"); + IMM("i16imm"); + IMM("i16i8imm"); + IMM("i32imm"); + IMM("i32i8imm"); + IMM("i64imm"); + IMM("i64i8imm"); + IMM("i64i32imm"); + IMM("SSECC"); + + // all R, I, R, I, R MEM("i8mem"); MEM("i8mem_NOREX"); MEM("i16mem"); @@ -298,32 +302,32 @@ static int X86FlagFromOpName(FlagsConstantEmitter *flags, MEM("f80mem"); MEM("opaque80mem"); MEM("i128mem"); + MEM("i256mem"); MEM("f128mem"); + MEM("f256mem"); MEM("opaque512mem"); - + + // all R, I, R, I LEA("lea32mem"); LEA("lea64_32mem"); LEA("lea64mem"); - - IMM("i8imm"); - IMM("i16imm"); - IMM("i16i8imm"); - IMM("i32imm"); - IMM("i32imm_pcrel"); - IMM("i32i8imm"); - IMM("i64imm"); - IMM("i64i8imm"); - IMM("i64i32imm"); - IMM("i64i32imm_pcrel"); - IMM("SSECC"); - + + // all I + PCR("i16imm_pcrel"); + PCR("i32imm_pcrel"); + PCR("i64i32imm_pcrel"); PCR("brtarget8"); PCR("offset8"); PCR("offset16"); PCR("offset32"); PCR("offset64"); PCR("brtarget"); - + PCR("uncondbrtarget"); + PCR("bltarget"); + + // all I, ARM mode only, conditional/unconditional + PCR("br_target"); + PCR("bl_target"); return 1; } @@ -332,7 +336,8 @@ static int X86FlagFromOpName(FlagsConstantEmitter *flags, #undef LEA #undef IMM #undef PCR -#undef ADDFLAG + +#undef SET /// X86PopulateOperands - Handles all the operands in an X86 instruction, adding /// the appropriate flags to their descriptors @@ -340,23 +345,23 @@ static int X86FlagFromOpName(FlagsConstantEmitter *flags, /// @operandFlags - A reference the array of operand flag objects /// @inst - The instruction to use as a source of information static void X86PopulateOperands( - FlagsConstantEmitter *(&operandFlags)[MAX_OPERANDS], + LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS], const CodeGenInstruction &inst) { if (!inst.TheDef->isSubClassOf("X86Inst")) return; - + unsigned int index; - unsigned int numOperands = inst.OperandList.size(); - + unsigned int numOperands = inst.Operands.size(); + for (index = 0; index < numOperands; ++index) { - const CodeGenInstruction::OperandInfo &operandInfo = - inst.OperandList[index]; + const CGIOperandList::OperandInfo &operandInfo = inst.Operands[index]; Record &rec = *operandInfo.Rec; - - if (X86FlagFromOpName(operandFlags[index], rec.getName())) { + + if (X86TypeFromOpName(operandTypes[index], rec.getName()) && + !rec.isSubClassOf("PointerLikeRegClass")) { errs() << "Operand type: " << rec.getName().c_str() << "\n"; errs() << "Operand name: " << operandInfo.Name.c_str() << "\n"; - errs() << "Instruction mame: " << inst.TheDef->getName().c_str() << "\n"; + errs() << "Instruction name: " << inst.TheDef->getName().c_str() << "\n"; llvm_unreachable("Unhandled type"); } } @@ -369,163 +374,155 @@ static void X86PopulateOperands( /// between names and operand indices /// @opName - The name of the operand /// @flag - The name of the flag to add -static inline void decorate1(FlagsConstantEmitter *(&operandFlags)[MAX_OPERANDS], - const CodeGenInstruction &inst, - const char *opName, - const char *opFlag) { +static inline void decorate1( + FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS], + const CodeGenInstruction &inst, + const char *opName, + const char *opFlag) { unsigned opIndex; - - opIndex = inst.getOperandNamed(std::string(opName)); - + + opIndex = inst.Operands.getOperandNamed(std::string(opName)); + operandFlags[opIndex]->addEntry(opFlag); } #define DECORATE1(opName, opFlag) decorate1(operandFlags, inst, opName, opFlag) -#define MOV(source, target) { \ - instFlags.addEntry("kInstructionFlagMove"); \ - DECORATE1(source, "kOperandFlagSource"); \ - DECORATE1(target, "kOperandFlagTarget"); \ +#define MOV(source, target) { \ + instType.set("kInstructionTypeMove"); \ + DECORATE1(source, "kOperandFlagSource"); \ + DECORATE1(target, "kOperandFlagTarget"); \ } -#define BRANCH(target) { \ - instFlags.addEntry("kInstructionFlagBranch"); \ - DECORATE1(target, "kOperandFlagTarget"); \ +#define BRANCH(target) { \ + instType.set("kInstructionTypeBranch"); \ + DECORATE1(target, "kOperandFlagTarget"); \ } -#define PUSH(source) { \ - instFlags.addEntry("kInstructionFlagPush"); \ - DECORATE1(source, "kOperandFlagSource"); \ +#define PUSH(source) { \ + instType.set("kInstructionTypePush"); \ + DECORATE1(source, "kOperandFlagSource"); \ } -#define POP(target) { \ - instFlags.addEntry("kInstructionFlagPop"); \ - DECORATE1(target, "kOperandFlagTarget"); \ +#define POP(target) { \ + instType.set("kInstructionTypePop"); \ + DECORATE1(target, "kOperandFlagTarget"); \ } -#define CALL(target) { \ - instFlags.addEntry("kInstructionFlagCall"); \ - DECORATE1(target, "kOperandFlagTarget"); \ +#define CALL(target) { \ + instType.set("kInstructionTypeCall"); \ + DECORATE1(target, "kOperandFlagTarget"); \ } -#define RETURN() { \ - instFlags.addEntry("kInstructionFlagReturn"); \ +#define RETURN() { \ + instType.set("kInstructionTypeReturn"); \ } /// X86ExtractSemantics - Performs various checks on the name of an X86 -/// instruction to determine what sort of an instruction it is and then adds +/// instruction to determine what sort of an instruction it is and then adds /// the appropriate flags to the instruction and its operands /// -/// @arg instFlags - A reference to the flags for the instruction as a whole +/// @arg instType - A reference to the type for the instruction as a whole /// @arg operandFlags - A reference to the array of operand flag object pointers /// @arg inst - A reference to the original instruction -static void X86ExtractSemantics(FlagsConstantEmitter &instFlags, - FlagsConstantEmitter *(&operandFlags)[MAX_OPERANDS], - const CodeGenInstruction &inst) { +static void X86ExtractSemantics( + LiteralConstantEmitter &instType, + FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS], + const CodeGenInstruction &inst) { const std::string &name = inst.TheDef->getName(); - + if (name.find("MOV") != name.npos) { if (name.find("MOV_V") != name.npos) { // ignore (this is a pseudoinstruction) - } - else if (name.find("MASK") != name.npos) { + } else if (name.find("MASK") != name.npos) { // ignore (this is a masking move) - } - else if (name.find("r0") != name.npos) { + } else if (name.find("r0") != name.npos) { // ignore (this is a pseudoinstruction) - } - else if (name.find("PS") != name.npos || + } else if (name.find("PS") != name.npos || name.find("PD") != name.npos) { // ignore (this is a shuffling move) - } - else if (name.find("MOVS") != name.npos) { + } else if (name.find("MOVS") != name.npos) { // ignore (this is a string move) - } - else if (name.find("_F") != name.npos) { + } else if (name.find("_F") != name.npos) { // TODO handle _F moves to ST(0) - } - else if (name.find("a") != name.npos) { + } else if (name.find("a") != name.npos) { // TODO handle moves to/from %ax - } - else if (name.find("CMOV") != name.npos) { + } else if (name.find("CMOV") != name.npos) { MOV("src2", "dst"); - } - else if (name.find("PC") != name.npos) { + } else if (name.find("PC") != name.npos) { MOV("label", "reg") - } - else { + } else { MOV("src", "dst"); } } - + if (name.find("JMP") != name.npos || name.find("J") == 0) { if (name.find("FAR") != name.npos && name.find("i") != name.npos) { BRANCH("off"); - } - else { + } else { BRANCH("dst"); } } - + if (name.find("PUSH") != name.npos) { - if (name.find("FS") != name.npos || - name.find("GS") != name.npos) { - instFlags.addEntry("kInstructionFlagPush"); + if (name.find("CS") != name.npos || + name.find("DS") != name.npos || + name.find("ES") != name.npos || + name.find("FS") != name.npos || + name.find("GS") != name.npos || + name.find("SS") != name.npos) { + instType.set("kInstructionTypePush"); // TODO add support for fixed operands - } - else if (name.find("F") != name.npos) { + } else if (name.find("F") != name.npos) { // ignore (this pushes onto the FP stack) - } - else if (name[name.length() - 1] == 'm') { + } else if (name.find("A") != name.npos) { + // ignore (pushes all GP registoers onto the stack) + } else if (name[name.length() - 1] == 'm') { PUSH("src"); - } - else if (name.find("i") != name.npos) { + } else if (name.find("i") != name.npos) { PUSH("imm"); - } - else { + } else { PUSH("reg"); } } - + if (name.find("POP") != name.npos) { if (name.find("POPCNT") != name.npos) { // ignore (not a real pop) - } - else if (name.find("FS") != name.npos || - name.find("GS") != name.npos) { - instFlags.addEntry("kInstructionFlagPop"); + } else if (name.find("CS") != name.npos || + name.find("DS") != name.npos || + name.find("ES") != name.npos || + name.find("FS") != name.npos || + name.find("GS") != name.npos || + name.find("SS") != name.npos) { + instType.set("kInstructionTypePop"); // TODO add support for fixed operands - } - else if (name.find("F") != name.npos) { + } else if (name.find("F") != name.npos) { // ignore (this pops from the FP stack) - } - else if (name[name.length() - 1] == 'm') { + } else if (name.find("A") != name.npos) { + // ignore (pushes all GP registoers onto the stack) + } else if (name[name.length() - 1] == 'm') { POP("dst"); - } - else { + } else { POP("reg"); } } - + if (name.find("CALL") != name.npos) { if (name.find("ADJ") != name.npos) { // ignore (not a call) - } - else if (name.find("SYSCALL") != name.npos) { + } else if (name.find("SYSCALL") != name.npos) { // ignore (doesn't go anywhere we know about) - } - else if (name.find("VMCALL") != name.npos) { + } else if (name.find("VMCALL") != name.npos) { // ignore (rather different semantics than a regular call) - } - else if (name.find("FAR") != name.npos && name.find("i") != name.npos) { + } else if (name.find("FAR") != name.npos && name.find("i") != name.npos) { CALL("off"); - } - else { + } else { CALL("dst"); } } - + if (name.find("RET") != name.npos) { RETURN(); } @@ -538,132 +535,386 @@ static void X86ExtractSemantics(FlagsConstantEmitter &instFlags, #undef CALL #undef RETURN -#undef COND_DECORATE_2 -#undef COND_DECORATE_1 -#undef DECORATE1 +///////////////////////////////////////////////////// +// Support functions for handling ARM instructions // +///////////////////////////////////////////////////// + +#define SET(flag) { type->set(flag); return 0; } + +#define REG(str) if (name == str) SET("kOperandTypeRegister"); +#define IMM(str) if (name == str) SET("kOperandTypeImmediate"); + +#define MISC(str, type) if (name == str) SET(type); + +/// ARMFlagFromOpName - Processes the name of a single ARM operand (which is +/// actually its type) and translates it into an operand type +/// +/// @arg type - The type object to set +/// @arg name - The name of the operand +static int ARMFlagFromOpName(LiteralConstantEmitter *type, + const std::string &name) { + REG("GPR"); + REG("rGPR"); + REG("tcGPR"); + REG("cc_out"); + REG("s_cc_out"); + REG("tGPR"); + REG("DPR"); + REG("DPR_VFP2"); + REG("DPR_8"); + REG("SPR"); + REG("QPR"); + REG("QQPR"); + REG("QQQQPR"); + + IMM("i32imm"); + IMM("i32imm_hilo16"); + IMM("bf_inv_mask_imm"); + IMM("lsb_pos_imm"); + IMM("width_imm"); + IMM("jtblock_operand"); + IMM("nohash_imm"); + IMM("p_imm"); + IMM("c_imm"); + IMM("imod_op"); + IMM("iflags_op"); + IMM("cpinst_operand"); + IMM("setend_op"); + IMM("cps_opt"); + IMM("vfp_f64imm"); + IMM("vfp_f32imm"); + IMM("memb_opt"); + IMM("msr_mask"); + IMM("neg_zero"); + IMM("imm0_31"); + IMM("imm0_31_m1"); + IMM("nModImm"); + IMM("imm0_4095"); + IMM("jt2block_operand"); + IMM("t_imm_s4"); + IMM("pclabel"); + IMM("adrlabel"); + IMM("t_adrlabel"); + IMM("t2adrlabel"); + IMM("shift_imm"); + IMM("neon_vcvt_imm32"); + IMM("shr_imm8"); + IMM("shr_imm16"); + IMM("shr_imm32"); + IMM("shr_imm64"); + + MISC("brtarget", "kOperandTypeARMBranchTarget"); // ? + MISC("uncondbrtarget", "kOperandTypeARMBranchTarget"); // ? + MISC("t_brtarget", "kOperandTypeARMBranchTarget"); // ? + MISC("t_bcctarget", "kOperandTypeARMBranchTarget"); // ? + MISC("t_cbtarget", "kOperandTypeARMBranchTarget"); // ? + MISC("bltarget", "kOperandTypeARMBranchTarget"); // ? + + MISC("br_target", "kOperandTypeARMBranchTarget"); // ? + MISC("bl_target", "kOperandTypeARMBranchTarget"); // ? + + MISC("t_bltarget", "kOperandTypeARMBranchTarget"); // ? + MISC("t_blxtarget", "kOperandTypeARMBranchTarget"); // ? + MISC("so_reg", "kOperandTypeARMSoReg"); // R, R, I + MISC("shift_so_reg", "kOperandTypeARMSoReg"); // R, R, I + MISC("t2_so_reg", "kOperandTypeThumb2SoReg"); // R, I + MISC("so_imm", "kOperandTypeARMSoImm"); // I + MISC("rot_imm", "kOperandTypeARMRotImm"); // I + MISC("t2_so_imm", "kOperandTypeThumb2SoImm"); // I + MISC("so_imm2part", "kOperandTypeARMSoImm2Part"); // I + MISC("pred", "kOperandTypeARMPredicate"); // I, R + MISC("it_pred", "kOperandTypeARMPredicate"); // I + MISC("addrmode_imm12", "kOperandTypeAddrModeImm12"); // R, I + MISC("ldst_so_reg", "kOperandTypeLdStSOReg"); // R, R, I + MISC("addrmode2", "kOperandTypeARMAddrMode2"); // R, R, I + MISC("am2offset", "kOperandTypeARMAddrMode2Offset"); // R, I + MISC("addrmode3", "kOperandTypeARMAddrMode3"); // R, R, I + MISC("am3offset", "kOperandTypeARMAddrMode3Offset"); // R, I + MISC("ldstm_mode", "kOperandTypeARMLdStmMode"); // I + MISC("addrmode5", "kOperandTypeARMAddrMode5"); // R, I + MISC("addrmode6", "kOperandTypeARMAddrMode6"); // R, R, I, I + MISC("am6offset", "kOperandTypeARMAddrMode6Offset"); // R, I, I + MISC("addrmode6dup", "kOperandTypeARMAddrMode6"); // R, R, I, I + MISC("addrmodepc", "kOperandTypeARMAddrModePC"); // R, I + MISC("reglist", "kOperandTypeARMRegisterList"); // I, R, ... + MISC("dpr_reglist", "kOperandTypeARMDPRRegisterList"); // I, R, ... + MISC("spr_reglist", "kOperandTypeARMSPRRegisterList"); // I, R, ... + MISC("it_mask", "kOperandTypeThumbITMask"); // I + MISC("t2addrmode_imm8", "kOperandTypeThumb2AddrModeImm8"); // R, I + MISC("t2am_imm8_offset", "kOperandTypeThumb2AddrModeImm8Offset");//I + MISC("t2addrmode_imm12", "kOperandTypeThumb2AddrModeImm12"); // R, I + MISC("t2addrmode_so_reg", "kOperandTypeThumb2AddrModeSoReg"); // R, R, I + MISC("t2addrmode_imm8s4", "kOperandTypeThumb2AddrModeImm8s4"); // R, I + MISC("t2am_imm8s4_offset", "kOperandTypeThumb2AddrModeImm8s4Offset"); + // R, I + MISC("tb_addrmode", "kOperandTypeARMTBAddrMode"); // I + MISC("t_addrmode_rrs1", "kOperandTypeThumbAddrModeRegS"); // R, R + MISC("t_addrmode_rrs2", "kOperandTypeThumbAddrModeRegS"); // R, R + MISC("t_addrmode_rrs4", "kOperandTypeThumbAddrModeRegS"); // R, R + MISC("t_addrmode_is1", "kOperandTypeThumbAddrModeImmS"); // R, I + MISC("t_addrmode_is2", "kOperandTypeThumbAddrModeImmS"); // R, I + MISC("t_addrmode_is4", "kOperandTypeThumbAddrModeImmS"); // R, I + MISC("t_addrmode_rr", "kOperandTypeThumbAddrModeRR"); // R, R + MISC("t_addrmode_sp", "kOperandTypeThumbAddrModeSP"); // R, I + MISC("t_addrmode_pc", "kOperandTypeThumbAddrModePC"); // R, I + + return 1; +} + +#undef SOREG +#undef SOIMM +#undef PRED +#undef REG +#undef MEM +#undef LEA +#undef IMM +#undef PCR + +#undef SET + +/// ARMPopulateOperands - Handles all the operands in an ARM instruction, adding +/// the appropriate flags to their descriptors +/// +/// @operandFlags - A reference the array of operand flag objects +/// @inst - The instruction to use as a source of information +static void ARMPopulateOperands( + LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS], + const CodeGenInstruction &inst) { + if (!inst.TheDef->isSubClassOf("InstARM") && + !inst.TheDef->isSubClassOf("InstThumb")) + return; + + unsigned int index; + unsigned int numOperands = inst.Operands.size(); + + if (numOperands > EDIS_MAX_OPERANDS) { + errs() << "numOperands == " << numOperands << " > " << + EDIS_MAX_OPERANDS << '\n'; + llvm_unreachable("Too many operands"); + } + + for (index = 0; index < numOperands; ++index) { + const CGIOperandList::OperandInfo &operandInfo = inst.Operands[index]; + Record &rec = *operandInfo.Rec; + + if (ARMFlagFromOpName(operandTypes[index], rec.getName())) { + errs() << "Operand type: " << rec.getName() << '\n'; + errs() << "Operand name: " << operandInfo.Name << '\n'; + errs() << "Instruction name: " << inst.TheDef->getName() << '\n'; + llvm_unreachable("Unhandled type"); + } + } +} + +#define BRANCH(target) { \ + instType.set("kInstructionTypeBranch"); \ + DECORATE1(target, "kOperandFlagTarget"); \ +} + +/// ARMExtractSemantics - Performs various checks on the name of an ARM +/// instruction to determine what sort of an instruction it is and then adds +/// the appropriate flags to the instruction and its operands +/// +/// @arg instType - A reference to the type for the instruction as a whole +/// @arg operandTypes - A reference to the array of operand type object pointers +/// @arg operandFlags - A reference to the array of operand flag object pointers +/// @arg inst - A reference to the original instruction +static void ARMExtractSemantics( + LiteralConstantEmitter &instType, + LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS], + FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS], + const CodeGenInstruction &inst) { + const std::string &name = inst.TheDef->getName(); -/// populateInstInfo - Fills an array of InstInfos with information about each + if (name == "tBcc" || + name == "tB" || + name == "t2Bcc" || + name == "Bcc" || + name == "tCBZ" || + name == "tCBNZ") { + BRANCH("target"); + } + + if (name == "tBLr9" || + name == "BLr9_pred" || + name == "tBLXi_r9" || + name == "tBLXr_r9" || + name == "BLXr9" || + name == "t2BXJ" || + name == "BXJ") { + BRANCH("func"); + + unsigned opIndex; + opIndex = inst.Operands.getOperandNamed("func"); + if (operandTypes[opIndex]->is("kOperandTypeImmediate")) + operandTypes[opIndex]->set("kOperandTypeARMBranchTarget"); + } +} + +#undef BRANCH + +/// populateInstInfo - Fills an array of InstInfos with information about each /// instruction in a target /// /// @arg infoArray - The array of InstInfo objects to populate /// @arg target - The CodeGenTarget to use as a source of instructions static void populateInstInfo(CompoundConstantEmitter &infoArray, CodeGenTarget &target) { - std::vector numberedInstructions; - target.getInstructionsByEnumValue(numberedInstructions); - + const std::vector &numberedInstructions = + target.getInstructionsByEnumValue(); + unsigned int index; unsigned int numInstructions = numberedInstructions.size(); - + for (index = 0; index < numInstructions; ++index) { const CodeGenInstruction& inst = *numberedInstructions[index]; - + CompoundConstantEmitter *infoStruct = new CompoundConstantEmitter; infoArray.addEntry(infoStruct); - - FlagsConstantEmitter *instFlags = new FlagsConstantEmitter; - infoStruct->addEntry(instFlags); - - LiteralConstantEmitter *numOperandsEmitter = - new LiteralConstantEmitter(inst.OperandList.size()); + + LiteralConstantEmitter *instType = new LiteralConstantEmitter; + infoStruct->addEntry(instType); + + LiteralConstantEmitter *numOperandsEmitter = + new LiteralConstantEmitter(inst.Operands.size()); infoStruct->addEntry(numOperandsEmitter); - + + CompoundConstantEmitter *operandTypeArray = new CompoundConstantEmitter; + infoStruct->addEntry(operandTypeArray); + + LiteralConstantEmitter *operandTypes[EDIS_MAX_OPERANDS]; + CompoundConstantEmitter *operandFlagArray = new CompoundConstantEmitter; infoStruct->addEntry(operandFlagArray); - - FlagsConstantEmitter *operandFlags[MAX_OPERANDS]; - - for (unsigned operandIndex = 0; operandIndex < MAX_OPERANDS; ++operandIndex) { + + FlagsConstantEmitter *operandFlags[EDIS_MAX_OPERANDS]; + + for (unsigned operandIndex = 0; + operandIndex < EDIS_MAX_OPERANDS; + ++operandIndex) { + operandTypes[operandIndex] = new LiteralConstantEmitter; + operandTypeArray->addEntry(operandTypes[operandIndex]); + operandFlags[operandIndex] = new FlagsConstantEmitter; operandFlagArray->addEntry(operandFlags[operandIndex]); } - + unsigned numSyntaxes = 0; - + if (target.getName() == "X86") { - X86PopulateOperands(operandFlags, inst); - X86ExtractSemantics(*instFlags, operandFlags, inst); + X86PopulateOperands(operandTypes, inst); + X86ExtractSemantics(*instType, operandFlags, inst); numSyntaxes = 2; } - + else if (target.getName() == "ARM") { + ARMPopulateOperands(operandTypes, inst); + ARMExtractSemantics(*instType, operandTypes, operandFlags, inst); + numSyntaxes = 1; + } + CompoundConstantEmitter *operandOrderArray = new CompoundConstantEmitter; + infoStruct->addEntry(operandOrderArray); - - for (unsigned syntaxIndex = 0; syntaxIndex < MAX_SYNTAXES; ++syntaxIndex) { - CompoundConstantEmitter *operandOrder = new CompoundConstantEmitter; + + for (unsigned syntaxIndex = 0; + syntaxIndex < EDIS_MAX_SYNTAXES; + ++syntaxIndex) { + CompoundConstantEmitter *operandOrder = + new CompoundConstantEmitter(EDIS_MAX_OPERANDS); + operandOrderArray->addEntry(operandOrder); - + if (syntaxIndex < numSyntaxes) { populateOperandOrder(operandOrder, inst, syntaxIndex); } - else { - for (unsigned operandIndex = 0; - operandIndex < MAX_OPERANDS; - ++operandIndex) { - operandOrder->addEntry(new LiteralConstantEmitter("-1")); - } - } } + + infoStruct = NULL; } } -void EDEmitter::run(raw_ostream &o) { - unsigned int i = 0; - - CompoundConstantEmitter infoArray; - CodeGenTarget target; - - populateInstInfo(infoArray, target); - - o << "InstInfo instInfo" << target.getName().c_str() << "[] = "; - infoArray.emit(o, i); - o << ";" << "\n"; -} +static void emitCommonEnums(raw_ostream &o, unsigned int &i) { + EnumEmitter operandTypes("OperandTypes"); + operandTypes.addEntry("kOperandTypeNone"); + operandTypes.addEntry("kOperandTypeImmediate"); + operandTypes.addEntry("kOperandTypeRegister"); + operandTypes.addEntry("kOperandTypeX86Memory"); + operandTypes.addEntry("kOperandTypeX86EffectiveAddress"); + operandTypes.addEntry("kOperandTypeX86PCRelative"); + operandTypes.addEntry("kOperandTypeARMBranchTarget"); + operandTypes.addEntry("kOperandTypeARMSoReg"); + operandTypes.addEntry("kOperandTypeARMSoImm"); + operandTypes.addEntry("kOperandTypeARMRotImm"); + operandTypes.addEntry("kOperandTypeARMSoImm2Part"); + operandTypes.addEntry("kOperandTypeARMPredicate"); + operandTypes.addEntry("kOperandTypeAddrModeImm12"); + operandTypes.addEntry("kOperandTypeLdStSOReg"); + operandTypes.addEntry("kOperandTypeARMAddrMode2"); + operandTypes.addEntry("kOperandTypeARMAddrMode2Offset"); + operandTypes.addEntry("kOperandTypeARMAddrMode3"); + operandTypes.addEntry("kOperandTypeARMAddrMode3Offset"); + operandTypes.addEntry("kOperandTypeARMLdStmMode"); + operandTypes.addEntry("kOperandTypeARMAddrMode5"); + operandTypes.addEntry("kOperandTypeARMAddrMode6"); + operandTypes.addEntry("kOperandTypeARMAddrMode6Offset"); + operandTypes.addEntry("kOperandTypeARMAddrModePC"); + operandTypes.addEntry("kOperandTypeARMRegisterList"); + operandTypes.addEntry("kOperandTypeARMDPRRegisterList"); + operandTypes.addEntry("kOperandTypeARMSPRRegisterList"); + operandTypes.addEntry("kOperandTypeARMTBAddrMode"); + operandTypes.addEntry("kOperandTypeThumbITMask"); + operandTypes.addEntry("kOperandTypeThumbAddrModeRegS"); + operandTypes.addEntry("kOperandTypeThumbAddrModeImmS"); + operandTypes.addEntry("kOperandTypeThumbAddrModeRR"); + operandTypes.addEntry("kOperandTypeThumbAddrModeSP"); + operandTypes.addEntry("kOperandTypeThumbAddrModePC"); + operandTypes.addEntry("kOperandTypeThumb2SoReg"); + operandTypes.addEntry("kOperandTypeThumb2SoImm"); + operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8"); + operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8Offset"); + operandTypes.addEntry("kOperandTypeThumb2AddrModeImm12"); + operandTypes.addEntry("kOperandTypeThumb2AddrModeSoReg"); + operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8s4"); + operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8s4Offset"); + operandTypes.emit(o, i); -void EDEmitter::runHeader(raw_ostream &o) { - EmitSourceFileHeader("Enhanced Disassembly Info Header", o); - - o << "#ifndef EDInfo_" << "\n"; - o << "#define EDInfo_" << "\n"; - o << "\n"; - o << "#include " << "\n"; - o << "\n"; - o << "#define MAX_OPERANDS " << format("%d", MAX_OPERANDS) << "\n"; - o << "#define MAX_SYNTAXES " << format("%d", MAX_SYNTAXES) << "\n"; o << "\n"; - - unsigned int i = 0; - + EnumEmitter operandFlags("OperandFlags"); - operandFlags.addEntry("kOperandFlagImmediate"); - operandFlags.addEntry("kOperandFlagRegister"); - operandFlags.addEntry("kOperandFlagMemory"); - operandFlags.addEntry("kOperandFlagEffectiveAddress"); - operandFlags.addEntry("kOperandFlagPCRelative"); operandFlags.addEntry("kOperandFlagSource"); operandFlags.addEntry("kOperandFlagTarget"); operandFlags.emitAsFlags(o, i); - - o << "\n"; - - EnumEmitter instructionFlags("InstructionFlags"); - instructionFlags.addEntry("kInstructionFlagMove"); - instructionFlags.addEntry("kInstructionFlagBranch"); - instructionFlags.addEntry("kInstructionFlagPush"); - instructionFlags.addEntry("kInstructionFlagPop"); - instructionFlags.addEntry("kInstructionFlagCall"); - instructionFlags.addEntry("kInstructionFlagReturn"); - instructionFlags.emitAsFlags(o, i); - + o << "\n"; - - StructEmitter instInfo("InstInfo"); - instInfo.addMember("uint32_t", "instructionFlags"); - instInfo.addMember("uint8_t", "numOperands"); - instInfo.addMember("uint8_t", "operandFlags[MAX_OPERANDS]"); - instInfo.addMember("const char", "operandOrders[MAX_SYNTAXES][MAX_OPERANDS]"); - instInfo.emit(o, i); - + + EnumEmitter instructionTypes("InstructionTypes"); + instructionTypes.addEntry("kInstructionTypeNone"); + instructionTypes.addEntry("kInstructionTypeMove"); + instructionTypes.addEntry("kInstructionTypeBranch"); + instructionTypes.addEntry("kInstructionTypePush"); + instructionTypes.addEntry("kInstructionTypePop"); + instructionTypes.addEntry("kInstructionTypeCall"); + instructionTypes.addEntry("kInstructionTypeReturn"); + instructionTypes.emit(o, i); + o << "\n"; - o << "#endif" << "\n"; +} + +void EDEmitter::run(raw_ostream &o) { + unsigned int i = 0; + + CompoundConstantEmitter infoArray; + CodeGenTarget target(Records); + + populateInstInfo(infoArray, target); + + emitCommonEnums(o, i); + + o << "namespace {\n"; + + o << "llvm::EDInstInfo instInfo" << target.getName().c_str() << "[] = "; + infoArray.emit(o, i); + o << ";" << "\n"; + + o << "}\n"; }