diff --git a/llvm/lib/Target/ARC/ARCInstrFormats.td b/llvm/lib/Target/ARC/ARCInstrFormats.td --- a/llvm/lib/Target/ARC/ARCInstrFormats.td +++ b/llvm/lib/Target/ARC/ARCInstrFormats.td @@ -261,6 +261,31 @@ let Inst{5-0} = subop; } +// Single Operand Immediate Instructions. +// 1-register, unsigned 6-bit immediate Single Operand instruction. +// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0| +// |B[2-0] | 1| 1| subop| F|B[5-3] |U6 |1|cc | +class F32_SOP_CC_RU6 major, bits<6> subop, bit F, dag outs, dag ins, + string asmstr, list pattern> : + InstARC<4, outs, ins, asmstr, pattern> { + + bits<5> cc; + bits<6> U6; + bits<6> B; + + let Inst{31-27} = major; + let Inst{26-24} = B{2-0}; + let Inst{23-22} = 0b11; + let Inst{21-16} = subop; + let Inst{15} = F; + let Inst{14-12} = B{5-3}; + let Inst{11-6} = U6; + let Inst{5} = 1; + let Inst{4-0} = cc; + + let DecoderMethod = "DecodeCCRU6Instruction"; +} + // Dual Operand Instructions. Inst[21-16] specifies the specific operation // for this format. diff --git a/llvm/lib/Target/ARC/ARCInstrInfo.td b/llvm/lib/Target/ARC/ARCInstrInfo.td --- a/llvm/lib/Target/ARC/ARCInstrInfo.td +++ b/llvm/lib/Target/ARC/ARCInstrInfo.td @@ -12,6 +12,24 @@ include "ARCInstrFormats.td" +//===----------------------------------------------------------------------===// +// Operand Pattern Stuff. +//===----------------------------------------------------------------------===// + +// Operand for printing out a condition code. +let PrintMethod = "printCCOperand" in + def CCOp : PredicateOperand; + +// The "u6" operand of a RRU6-type instruction +let PrintMethod = "printU6" in { + def u6 : Operand, ImmLeaf(Imm); + }]>; + def wide_u6 : Operand, ImmLeaf(Imm); + }]>; +} + // --------------------------------------------------------------------------- // Selection DAG Nodes. // --------------------------------------------------------------------------- @@ -299,14 +317,24 @@ def cmov : PatFrag<(ops node:$op1, node:$op2, node:$cc), (ARCcmov $op1, $op2, $cc)>; let Uses = [STATUS32] in { -def MOVcc : F32_DOP_CC_RR<0b00100, 0b001010, 0, - (outs GPR32:$B), - (ins GPR32:$C, GPR32:$fval, cmovpred:$cc), - !strconcat("mov.", "$cc\t$B, $C"), - [(set GPR32:$B, (cmov i32:$C, i32:$fval, cmovpred:$cc))]> { - let Constraints = "$B = $fval"; -} + def MOVcc : F32_DOP_CC_RR<0b00100, 0b001010, 0, + (outs GPR32:$B), + (ins GPR32:$C, GPR32:$fval, cmovpred:$cc), + !strconcat("mov.", "$cc\t$B, $C"), + [(set GPR32:$B, (cmov i32:$C, i32:$fval, cmovpred:$cc))]> { + let Constraints = "$B = $fval"; + } + + def MOVcc_ru6 : F32_SOP_CC_RU6<0b00100, 0b001010, 0, + (outs GPR32:$b), (ins u6:$c, CCOp:$cc, GPR32:$b2), + "mov.$cc\t$b, $c", []> { + let isAsCheapAsAMove=0; + let isPredicable=1; + let isReMaterializable=0; + let Constraints="$b2 = $b"; + } } + def : Pat<(ARCGAWrapper tglobaladdr:$addr), (MOV_rlimm tglobaladdr:$addr)>; diff --git a/llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp b/llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp --- a/llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp +++ b/llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp @@ -107,6 +107,9 @@ static DecodeStatus DecodeLdRLImmInstruction(MCInst &, uint64_t, uint64_t, const void *); +static DecodeStatus DecodeCCRU6Instruction(MCInst &, uint64_t, uint64_t, + const void *); + static DecodeStatus DecodeMoveHRegInstruction(MCInst &Inst, uint64_t, uint64_t, const void *); @@ -167,19 +170,19 @@ static bool DecodeSymbolicOperand(MCInst &Inst, uint64_t Address, uint64_t Value, const void *Decoder) { - static const uint64_t atLeast = 2; + static const uint64_t AtLeast = 2; // TODO: Try to force emitter to use MCDisassembler* instead of void*. auto Disassembler = static_cast(Decoder); return (nullptr != Disassembler && Disassembler->tryAddingSymbolicOperand(Inst, Value, Address, true, 0, - atLeast)); + AtLeast)); } static void DecodeSymbolicOperandOff(MCInst &Inst, uint64_t Address, uint64_t Offset, const void *Decoder) { - uint64_t nextAddress = Address + Offset; + uint64_t NextAddress = Address + Offset; - if (!DecodeSymbolicOperand(Inst, Address, nextAddress, Decoder)) + if (!DecodeSymbolicOperand(Inst, Address, NextAddress, Decoder)) Inst.addOperand(MCOperand::createImm(Offset)); } @@ -272,9 +275,9 @@ const void *Decoder) { LLVM_DEBUG(dbgs() << "Decoding MOV_S h-register\n"); using Field = decltype(Insn); - Field h = fieldFromInstruction(Insn, 5, 3) | + Field H = fieldFromInstruction(Insn, 5, 3) | (fieldFromInstruction(Insn, 0, 2) << 3); - Field g = fieldFromInstruction(Insn, 8, 3) | + Field G = fieldFromInstruction(Insn, 8, 3) | (fieldFromInstruction(Insn, 3, 2) << 3); auto DecodeRegisterOrImm = [&Inst, Address, Decoder](Field RegNum, @@ -287,10 +290,25 @@ return DecodeGPR32RegisterClass(Inst, RegNum, Address, Decoder); }; - if (MCDisassembler::Success != DecodeRegisterOrImm(g, 0)) + if (MCDisassembler::Success != DecodeRegisterOrImm(G, 0)) return MCDisassembler::Fail; - return DecodeRegisterOrImm(h, Insn >> 16u); + return DecodeRegisterOrImm(H, Insn >> 16u); +} + +static DecodeStatus DecodeCCRU6Instruction(MCInst &Inst, uint64_t Insn, + uint64_t Address, + const void *Decoder) { + unsigned DstB; + LLVM_DEBUG(dbgs() << "Decoding CCRU6 instruction:\n"); + DstB = decodeBField(Insn); + DecodeGPR32RegisterClass(Inst, DstB, Address, Decoder); + using Field = decltype(Insn); + Field U6Field = fieldFromInstruction(Insn, 6, 11); + Inst.addOperand(MCOperand::createImm(U6Field)); + Field CCField = fieldFromInstruction(Insn, 0, 4); + Inst.addOperand(MCOperand::createImm(CCField)); + return MCDisassembler::Success; } DecodeStatus ARCDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, diff --git a/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.h b/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.h --- a/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.h +++ b/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.h @@ -33,6 +33,8 @@ void printRegName(raw_ostream &OS, unsigned RegNo) const override; void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, const MCSubtargetInfo &STI, raw_ostream &O) override; + void printCCOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printU6(const MCInst *MI, int OpNum, raw_ostream &O); private: void printMemOperandRI(const MCInst *MI, unsigned OpNum, raw_ostream &O); @@ -44,6 +46,8 @@ void printPredicateOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printBRCCPredicateOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + void printU6ShiftedBy(unsigned ShiftBy, const MCInst *MI, int OpNum, + raw_ostream &O); }; } // end namespace llvm diff --git a/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.cpp b/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.cpp --- a/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.cpp +++ b/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.cpp @@ -178,3 +178,30 @@ assert(Op.isImm() && "Predicate operand is immediate."); O << ARCBRCondCodeToString((ARCCC::BRCondCode)Op.getImm()); } + +void ARCInstPrinter::printCCOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + O << ARCCondCodeToString((ARCCC::CondCode)MI->getOperand(OpNum).getImm()); +} + +void ARCInstPrinter::printU6ShiftedBy(unsigned ShiftBy, const MCInst *MI, + int OpNum, raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNum); + if (MO.isImm()) { + unsigned Value = MO.getImm(); + unsigned Value2 = Value >> ShiftBy; + if (Value2 > 0x3F || (Value2 << ShiftBy != Value)) { + errs() << "!!! Instruction has out-of-range U6 immediate operand:\n" + << " Opcode is " << MI->getOpcode() << "; operand value is " + << Value; + if (ShiftBy) + errs() << " scaled by " << (1 << ShiftBy) << "\n"; + assert(false && "instruction has wrong format"); + } + } + printOperand(MI, OpNum, O); +} + +void ARCInstPrinter::printU6(const MCInst *MI, int OpNum, raw_ostream &O) { + printU6ShiftedBy(0, MI, OpNum, O); +}