diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td index 5825f9bedef..9163629da14 100644 --- a/lib/Target/ARM/ARMInstrThumb.td +++ b/lib/Target/ARM/ARMInstrThumb.td @@ -1049,10 +1049,20 @@ def tMOVSr : T1I<(outs tGPR:$Rd), (ins tGPR:$Rm), IIC_iMOVr, // Multiply register let isCommutable = 1 in def tMUL : // A8.6.105 T1 - T1sItDPEncode<0b1101, (outs tGPR:$Rdn), (ins tGPR:$Rn, tGPR:$Rm), - IIC_iMUL32, - "mul", "\t$Rdn, $Rm, $Rdn", - [(set tGPR:$Rdn, (mul tGPR:$Rn, tGPR:$Rm))]>; + Thumb1sI<(outs tGPR:$Rd), (ins tGPR:$Rn, tGPR:$Rm), AddrModeNone, 2, + IIC_iMUL32, "mul", "\t$Rd, $Rn, $Rm", "$Rm = $Rd", + [(set tGPR:$Rd, (mul tGPR:$Rn, tGPR:$Rm))]>, + T1DataProcessing<0b1101> { + bits<3> Rd; + bits<3> Rn; + let Inst{5-3} = Rn; + let Inst{2-0} = Rd; + let AsmMatchConverter = "cvtThumbMultiply"; +} + +def : InstAlias<"mul${s}${p} $Rdm, $Rn", (tMUL tGPR:$Rdm, s_cc_out:$s, tGPR:$Rn, + pred:$p)>, + Requires<[IsThumb]>; // Move inverse register def tMVN : // A8.6.107 diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 33399ec14f8..34951368249 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -145,6 +145,8 @@ class ARMAsmParser : public MCTargetAsmParser { const SmallVectorImpl &); bool cvtLdWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode, const SmallVectorImpl &); + bool cvtThumbMultiply(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); bool validateInstruction(MCInst &Inst, const SmallVectorImpl &Ops); @@ -2371,6 +2373,29 @@ cvtLdWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode, return true; } +/// cvtThumbMultiple- Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtThumbMultiply(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // The second source operand must be the same register as the destination + // operand. + if (Operands.size() == 6 && + ((ARMOperand*)Operands[3])->getReg() != + ((ARMOperand*)Operands[5])->getReg()) { + Error(Operands[3]->getStartLoc(), + "destination register must match second source register"); + return false; + } + ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[1])->addCCOutOperands(Inst, 1); + ((ARMOperand*)Operands[4])->addRegOperands(Inst, 1); + Inst.addOperand(Inst.getOperand(0)); + ((ARMOperand*)Operands[2])->addCondCodeOperands(Inst, 2); + + return true; +} /// Parse an ARM memory expression, return false if successful else return true /// or an error. The first token must be a '[' when called. @@ -3220,7 +3245,8 @@ MatchAndEmitInstruction(SMLoc IDLoc, case Match_MnemonicFail: return Error(IDLoc, "invalid instruction"); case Match_ConversionFail: - return Error(IDLoc, "unable to convert operands to instruction"); + // The converter function will have already emited a diagnostic. + return true; case Match_RequiresITBlock: return Error(IDLoc, "instruction only valid inside IT block"); case Match_RequiresV6: diff --git a/test/MC/ARM/basic-thumb-instructions.s b/test/MC/ARM/basic-thumb-instructions.s index dcd2cad40cc..04823ae7479 100644 --- a/test/MC/ARM/basic-thumb-instructions.s +++ b/test/MC/ARM/basic-thumb-instructions.s @@ -321,3 +321,13 @@ _func: @ CHECK: mov r3, r4 @ encoding: [0x23,0x46] @ CHECK: movs r1, r3 @ encoding: [0x19,0x00] + + +@------------------------------------------------------------------------------ +@ MUL +@------------------------------------------------------------------------------ + muls r1, r2, r1 + muls r3, r4 + +@ CHECK: muls r1, r2, r1 @ encoding: [0x51,0x43] +@ CHECK: muls r3, r4, r3 @ encoding: [0x63,0x43] diff --git a/test/MC/ARM/thumb-diagnostics.s b/test/MC/ARM/thumb-diagnostics.s index 6deccacfbd2..f7297d959e5 100644 --- a/test/MC/ARM/thumb-diagnostics.s +++ b/test/MC/ARM/thumb-diagnostics.s @@ -62,3 +62,9 @@ error: invalid operand for instruction @ CHECK-ERRORS: error: invalid operand for instruction @ CHECK-ERRORS: lsls r4, r5, #32 @ CHECK-ERRORS: ^ + +@ Mismatched source/destination operands for MUL instruction. + muls r1, r2, r3 +@ CHECK-ERRORS: error: destination register must match second source register +@ CHECK-ERRORS: muls r1, r2, r3 +@ CHECK-ERRORS: ^