+/////////////////////////////////////////////////////
+// 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();
+
+ 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