diff options
Diffstat (limited to 'llvm/lib')
3 files changed, 93 insertions, 18 deletions
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index e43fc2cc784..432c7217c13 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -868,14 +868,7 @@ public: if (!CE) return false; uint64_t Value = CE->getValue(); - if (RegWidth == 32) - Value &= 0xffffffffULL; - - // "lsl #0" takes precedence: in practice this only affects "#0, lsl #0". - if (Value == 0 && Shift != 0) - return false; - - return (Value & ~(0xffffULL << Shift)) == 0; + return AArch64_AM::isMOVZMovAlias(Value, Shift, RegWidth); } template<int RegWidth, int Shift> @@ -886,16 +879,7 @@ public: if (!CE) return false; uint64_t Value = CE->getValue(); - // MOVZ takes precedence over MOVN. - for (int MOVZShift = 0; MOVZShift <= 48; MOVZShift += 16) - if ((Value & ~(0xffffULL << MOVZShift)) == 0) - return false; - - Value = ~Value; - if (RegWidth == 32) - Value &= 0xffffffffULL; - - return (Value & ~(0xffffULL << Shift)) == 0; + return AArch64_AM::isMOVNMovAlias(Value, Shift, RegWidth); } bool isFPImm() const { return Kind == k_FPImm; } diff --git a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp index 06883712e7a..a3669cf18e7 100644 --- a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp +++ b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp @@ -219,6 +219,54 @@ void AArch64InstPrinter::printInst(const MCInst *MI, raw_ostream &O, return; } + // MOVZ, MOVN and "ORR wzr, #imm" instructions are aliases for MOV, but their + // domains overlap so they need to be prioritized. The chain is "MOVZ lsl #0 > + // MOVZ lsl #N > MOVN lsl #0 > MOVN lsl #N > ORR". The highest instruction + // that can represent the move is the MOV alias, and the rest get printed + // normally. + if ((Opcode == AArch64::MOVZXi || Opcode == AArch64::MOVZWi) && + MI->getOperand(1).isImm() && MI->getOperand(2).isImm()) { + int RegWidth = Opcode == AArch64::MOVZXi ? 64 : 32; + int Shift = MI->getOperand(2).getImm(); + uint64_t Value = (uint64_t)MI->getOperand(1).getImm() << Shift; + + if (AArch64_AM::isMOVZMovAlias(Value, Shift, + Opcode == AArch64::MOVZXi ? 64 : 32)) { + O << "\tmov\t" << getRegisterName(MI->getOperand(0).getReg()) << ", #" + << formatImm(SignExtend64(Value, RegWidth)); + return; + } + } + + if ((Opcode == AArch64::MOVNXi || Opcode == AArch64::MOVNWi) && + MI->getOperand(1).isImm() && MI->getOperand(2).isImm()) { + int RegWidth = Opcode == AArch64::MOVNXi ? 64 : 32; + int Shift = MI->getOperand(2).getImm(); + uint64_t Value = ~((uint64_t)MI->getOperand(1).getImm() << Shift); + if (RegWidth == 32) + Value = Value & 0xffffffff; + + if (AArch64_AM::isMOVNMovAlias(Value, Shift, RegWidth)) { + O << "\tmov\t" << getRegisterName(MI->getOperand(0).getReg()) << ", #" + << formatImm(SignExtend64(Value, RegWidth)); + return; + } + } + + if ((Opcode == AArch64::ORRXri || Opcode == AArch64::ORRWri) && + (MI->getOperand(1).getReg() == AArch64::XZR || + MI->getOperand(1).getReg() == AArch64::WZR) && + MI->getOperand(2).isImm()) { + int RegWidth = Opcode == AArch64::ORRXri ? 64 : 32; + uint64_t Value = AArch64_AM::decodeLogicalImmediate( + MI->getOperand(2).getImm(), RegWidth); + if (!AArch64_AM::isAnyMOVWMovAlias(Value, RegWidth)) { + O << "\tmov\t" << getRegisterName(MI->getOperand(0).getReg()) << ", #" + << formatImm(SignExtend64(Value, RegWidth)); + return; + } + } + if (!printAliasInstr(MI, STI, O)) printInstruction(MI, STI, O); diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h index 648b1dfc8c5..3e5ef4df470 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h @@ -753,6 +753,49 @@ static inline uint64_t decodeAdvSIMDModImmType12(uint8_t Imm) { return (EncVal << 32) | EncVal; } +inline static bool isAnyMOVZMovAlias(uint64_t Value, int RegWidth) { + for (int Shift = 0; Shift <= RegWidth - 16; Shift += 16) + if ((Value & ~(0xffffULL << Shift)) == 0) + return true; + + return false; +} + +inline static bool isMOVZMovAlias(uint64_t Value, int Shift, int RegWidth) { + if (RegWidth == 32) + Value &= 0xffffffffULL; + + // "lsl #0" takes precedence: in practice this only affects "#0, lsl #0". + if (Value == 0 && Shift != 0) + return false; + + return (Value & ~(0xffffULL << Shift)) == 0; +} + +inline static bool isMOVNMovAlias(uint64_t Value, int Shift, int RegWidth) { + // MOVZ takes precedence over MOVN. + if (isAnyMOVZMovAlias(Value, RegWidth)) + return false; + + Value = ~Value; + if (RegWidth == 32) + Value &= 0xffffffffULL; + + return isMOVZMovAlias(Value, Shift, RegWidth); +} + +inline static bool isAnyMOVWMovAlias(uint64_t Value, int RegWidth) { + if (isAnyMOVZMovAlias(Value, RegWidth)) + return true; + + // It's not a MOVZ, but it might be a MOVN. + Value = ~Value; + if (RegWidth == 32) + Value &= 0xffffffffULL; + + return isAnyMOVZMovAlias(Value, RegWidth); +} + } // end namespace AArch64_AM } // end namespace llvm |