diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp index 12baca6242e..b09cd73176d 100644 --- a/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/ARMAsmPrinter.cpp @@ -120,8 +120,10 @@ namespace { void printAddrModePCOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, const char *Modifier = 0); - void printBitfieldInvMaskImmOperand (const MachineInstr *MI, int OpNum, - raw_ostream &O); + void printBitfieldInvMaskImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printSatShiftOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); void printThumbS4ImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); @@ -669,6 +671,25 @@ ARMAsmPrinter::printBitfieldInvMaskImmOperand(const MachineInstr *MI, int Op, O << "#" << lsb << ", #" << width; } +void ARMAsmPrinter::printSatShiftOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + unsigned ShiftOp = MI->getOperand(OpNum).getImm(); + ARM_AM::ShiftOpc Opc = ARM_AM::getSORegShOp(ShiftOp); + switch (Opc) { + case ARM_AM::no_shift: + return; + case ARM_AM::lsl: + O << ", lsl #"; + break; + case ARM_AM::asr: + O << ", asr #"; + break; + default: + assert(0 && "unexpected shift opcode for saturate shift operand"); + } + O << ARM_AM::getSORegOffset(ShiftOp); +} + //===--------------------------------------------------------------------===// void ARMAsmPrinter::printThumbS4ImmOperand(const MachineInstr *MI, int Op, diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index d323a32975a..5ccba1cedb9 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -1247,9 +1247,7 @@ void ARMCodeEmitter::emitSaturateInstruction(const MachineInstr &MI) { // Encode saturate bit position. unsigned Pos = MI.getOperand(1).getImm(); - if (TID.Opcode == ARM::SSATlsl || - TID.Opcode == ARM::SSATasr || - TID.Opcode == ARM::SSAT16) + if (TID.Opcode == ARM::SSAT || TID.Opcode == ARM::SSAT16) Pos -= 1; assert((Pos < 16 || (Pos < 32 && TID.Opcode != ARM::SSAT16 && @@ -1262,9 +1260,12 @@ void ARMCodeEmitter::emitSaturateInstruction(const MachineInstr &MI) { // Encode shift_imm. if (TID.getNumOperands() == 4) { + unsigned ShiftOp = MI.getOperand(3).getImm(); + ARM_AM::ShiftOpc Opc = ARM_AM::getSORegShOp(ShiftOp); + if (Opc == ARM_AM::asr) + Binary |= (1 << 6); unsigned ShiftAmt = MI.getOperand(3).getImm(); - if (ShiftAmt == 32 && - (TID.Opcode == ARM::SSATasr || TID.Opcode == ARM::USATasr)) + if (ShiftAmt == 32 && Opc == ARM_AM::asr) ShiftAmt = 0; assert(ShiftAmt < 32 && "shift_imm range is 0 to 31!"); Binary |= ShiftAmt << ARMII::ShiftShift; diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 4a47b8c9a97..827b743e10f 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -1810,20 +1810,15 @@ def USADA8 : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), // Signed/Unsigned saturate -- for disassembly only -def SSATlsl : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt), - SatFrm, NoItinerary, - "ssat", "\t$dst, $bit_pos, $a, lsl $shamt", - [/* For disassembly only; pattern left blank */]> { - let Inst{27-21} = 0b0110101; - let Inst{6-4} = 0b001; +def sat_shift : Operand { + let PrintMethod = "printSatShiftOperand"; } -def SSATasr : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt), - SatFrm, NoItinerary, - "ssat", "\t$dst, $bit_pos, $a, asr $shamt", - [/* For disassembly only; pattern left blank */]> { +def SSAT : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, sat_shift:$sh), + SatFrm, NoItinerary, "ssat", "\t$dst, $bit_pos, $a$sh", + [/* For disassembly only; pattern left blank */]> { let Inst{27-21} = 0b0110101; - let Inst{6-4} = 0b101; + let Inst{5-4} = 0b01; } def SSAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), SatFrm, @@ -1833,20 +1828,11 @@ def SSAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), SatFrm, let Inst{7-4} = 0b0011; } -def USATlsl : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt), - SatFrm, NoItinerary, - "usat", "\t$dst, $bit_pos, $a, lsl $shamt", - [/* For disassembly only; pattern left blank */]> { +def USAT : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, sat_shift:$sh), + SatFrm, NoItinerary, "usat", "\t$dst, $bit_pos, $a$sh", + [/* For disassembly only; pattern left blank */]> { let Inst{27-21} = 0b0110111; - let Inst{6-4} = 0b001; -} - -def USATasr : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt), - SatFrm, NoItinerary, - "usat", "\t$dst, $bit_pos, $a, asr $shamt", - [/* For disassembly only; pattern left blank */]> { - let Inst{27-21} = 0b0110111; - let Inst{6-4} = 0b101; + let Inst{5-4} = 0b01; } def USAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), SatFrm, @@ -1856,8 +1842,8 @@ def USAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), SatFrm, let Inst{7-4} = 0b0011; } -def : ARMV6Pat<(int_arm_ssat GPR:$a, imm:$pos), (SSATlsl imm:$pos, GPR:$a, 0)>; -def : ARMV6Pat<(int_arm_usat GPR:$a, imm:$pos), (USATlsl imm:$pos, GPR:$a, 0)>; +def : ARMV6Pat<(int_arm_ssat GPR:$a, imm:$pos), (SSAT imm:$pos, GPR:$a, 0)>; +def : ARMV6Pat<(int_arm_usat GPR:$a, imm:$pos), (USAT imm:$pos, GPR:$a, 0)>; //===----------------------------------------------------------------------===// // Bitwise Instructions. diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp index d1d28521610..f40da955041 100644 --- a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp @@ -461,9 +461,9 @@ void ARMInstPrinter::printAddrModePCOperand(const MCInst *MI, unsigned OpNum, assert(0 && "FIXME: Implement printAddrModePCOperand"); } -void ARMInstPrinter::printBitfieldInvMaskImmOperand (const MCInst *MI, - unsigned OpNum, - raw_ostream &O) { +void ARMInstPrinter::printBitfieldInvMaskImmOperand(const MCInst *MI, + unsigned OpNum, + raw_ostream &O) { const MCOperand &MO = MI->getOperand(OpNum); uint32_t v = ~MO.getImm(); int32_t lsb = CountTrailingZeros_32(v); @@ -472,6 +472,25 @@ void ARMInstPrinter::printBitfieldInvMaskImmOperand (const MCInst *MI, O << '#' << lsb << ", #" << width; } +void ARMInstPrinter::printSatShiftOperand(const MCInst *MI, unsigned OpNum, + raw_ostream &O) { + unsigned ShiftOp = MI->getOperand(OpNum).getImm(); + ARM_AM::ShiftOpc Opc = ARM_AM::getSORegShOp(ShiftOp); + switch (Opc) { + case ARM_AM::no_shift: + return; + case ARM_AM::lsl: + O << ", lsl #"; + break; + case ARM_AM::asr: + O << ", asr #"; + break; + default: + assert(0 && "unexpected shift opcode for saturate shift operand"); + } + O << ARM_AM::getSORegOffset(ShiftOp); +} + void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum, raw_ostream &O) { O << "{"; diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h index ddf5047793d..14d7ec93087 100644 --- a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h @@ -57,6 +57,7 @@ public: void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + void printSatShiftOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printThumbITMask(const MCInst *MI, unsigned OpNum, raw_ostream &O); diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 4de697e8bf6..f9eecb8acb2 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -106,7 +106,7 @@ static unsigned decodeARMInstruction(uint32_t &insn) { // Ditto for STRT, which is a super-instruction for A8.6.210 Encoding A1 & A2. // As a result, the decoder fails to deocode SSAT properly. if (slice(insn, 27, 21) == 0x35 && slice(insn, 5, 4) == 1) - return slice(insn, 6, 6) == 0 ? ARM::SSATlsl : ARM::SSATasr; + return ARM::SSAT; // Ditto for RSCrs, which is a super-instruction for A8.6.146 & A8.6.147. // As a result, the decoder fails to decode STRHT/LDRHT/LDRSHT/LDRSBT. diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp index 99d9f01c048..57dc3471b95 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp @@ -1466,9 +1466,7 @@ static bool DisassembleSatFrm(MCInst &MI, unsigned Opcode, uint32_t insn, decodeRd(insn)))); unsigned Pos = slice(insn, 20, 16); - if (Opcode == ARM::SSATlsl || - Opcode == ARM::SSATasr || - Opcode == ARM::SSAT16) + if (Opcode == ARM::SSAT || Opcode == ARM::SSAT16) Pos += 1; MI.addOperand(MCOperand::CreateImm(Pos)); @@ -1476,12 +1474,17 @@ static bool DisassembleSatFrm(MCInst &MI, unsigned Opcode, uint32_t insn, decodeRm(insn)))); if (NumOpsAdded == 4) { + ARM_AM::ShiftOpc Opc = (slice(insn, 6, 6) != 0 ? ARM_AM::asr : ARM_AM::lsl); // Inst{11-7} encodes the imm5 shift amount. unsigned ShAmt = slice(insn, 11, 7); - // A8.6.183. Possible ASR shift amount of 32... - if ((Opcode == ARM::SSATasr || Opcode == ARM::USATasr) && ShAmt == 0) - ShAmt = 32; - MI.addOperand(MCOperand::CreateImm(ShAmt)); + if (ShAmt == 0) { + // A8.6.183. Possible ASR shift amount of 32... + if (Opc == ARM_AM::asr) + ShAmt = 32; + else + Opc = ARM_AM::no_shift; + } + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(Opc, ShAmt))); } return true; } diff --git a/test/MC/Disassembler/arm-tests.txt b/test/MC/Disassembler/arm-tests.txt index 52161a6ec16..d6df56b8276 100644 --- a/test/MC/Disassembler/arm-tests.txt +++ b/test/MC/Disassembler/arm-tests.txt @@ -78,6 +78,10 @@ # CHECK: ssat r8, #1, r10, lsl #8 0x1a 0x84 0xa0 0xe6 +# CHECK-NOT: ssatmi r0, #17, r12, lsl #0 +# CHECK: ssatmi r0, #17, r12 +0x1c 0x00 0xb0 0x46 + # CHECK: stmdb r10!, {r4, r5, r6, r7, lr} 0xf0 0x40 0x2a 0xe9 diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp index 50ff9ea070a..a640a74d216 100644 --- a/utils/TableGen/EDEmitter.cpp +++ b/utils/TableGen/EDEmitter.cpp @@ -607,6 +607,7 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, IMM("jt2block_operand"); IMM("t_imm_s4"); IMM("pclabel"); + IMM("sat_shift"); MISC("brtarget", "kOperandTypeARMBranchTarget"); // ? MISC("so_reg", "kOperandTypeARMSoReg"); // R, R, I