[llvm] r208605 - AArch64/ARM64: implement "mov $Rd, $Imm" aliases in TableGen.
Tim Northover
tnorthover at apple.com
Mon May 12 11:03:36 PDT 2014
Author: tnorthover
Date: Mon May 12 13:03:36 2014
New Revision: 208605
URL: http://llvm.org/viewvc/llvm-project?rev=208605&view=rev
Log:
AArch64/ARM64: implement "mov $Rd, $Imm" aliases in TableGen.
This is a slightly different approach to AArch64 (the base instruction
definitions aren't quite right for that to work), but achieves the
same thing and reduces C++ hackery in AsmParser.
Modified:
llvm/trunk/lib/Target/ARM64/ARM64InstrFormats.td
llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.td
llvm/trunk/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp
Modified: llvm/trunk/lib/Target/ARM64/ARM64InstrFormats.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64InstrFormats.td?rev=208605&r1=208604&r2=208605&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/ARM64InstrFormats.td (original)
+++ llvm/trunk/lib/Target/ARM64/ARM64InstrFormats.td Mon May 12 13:03:36 2014
@@ -1322,6 +1322,7 @@ def movimm64_shift : Operand<i32> {
let PrintMethod = "printShifter";
let ParserMatchClass = MovImm64ShifterOperand;
}
+
let mayLoad = 0, mayStore = 0, hasSideEffects = 0 in
class BaseMoveImmediate<bits<2> opc, RegisterClass regtype, Operand shifter,
string asm>
Modified: llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.td?rev=208605&r1=208604&r2=208605&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.td (original)
+++ llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.td Mon May 12 13:03:36 2014
@@ -365,6 +365,7 @@ defm MOVN : MoveImmediate<0b00, "movn">;
let PostEncoderMethod = "fixMOVZ" in
defm MOVZ : MoveImmediate<0b10, "movz">;
+// First group of aliases covers an implicit "lsl #0".
def : InstAlias<"movk $dst, $imm", (MOVKWi GPR32:$dst, imm0_65535:$imm, 0)>;
def : InstAlias<"movk $dst, $imm", (MOVKXi GPR64:$dst, imm0_65535:$imm, 0)>;
def : InstAlias<"movn $dst, $imm", (MOVNWi GPR32:$dst, imm0_65535:$imm, 0)>;
@@ -372,6 +373,7 @@ def : InstAlias<"movn $dst, $imm", (MOVN
def : InstAlias<"movz $dst, $imm", (MOVZWi GPR32:$dst, imm0_65535:$imm, 0)>;
def : InstAlias<"movz $dst, $imm", (MOVZXi GPR64:$dst, imm0_65535:$imm, 0)>;
+// Next, we have various ELF relocations with the ":XYZ_g0:sym" syntax.
def : InstAlias<"movz $Rd, $sym", (MOVZXi GPR64:$Rd, movz_symbol_g3:$sym, 48)>;
def : InstAlias<"movz $Rd, $sym", (MOVZXi GPR64:$Rd, movz_symbol_g2:$sym, 32)>;
def : InstAlias<"movz $Rd, $sym", (MOVZXi GPR64:$Rd, movz_symbol_g1:$sym, 16)>;
@@ -396,6 +398,40 @@ def : InstAlias<"movn $Rd, $sym", (MOVNW
def : InstAlias<"movk $Rd, $sym", (MOVKWi GPR32:$Rd, movk_symbol_g1:$sym, 16)>;
def : InstAlias<"movk $Rd, $sym", (MOVKWi GPR32:$Rd, movk_symbol_g0:$sym, 0)>;
+// Final group of aliases covers true "mov $Rd, $imm" cases.
+multiclass movw_mov_alias<string basename,Instruction INST, RegisterClass GPR,
+ int width, int shift> {
+ def _asmoperand : AsmOperandClass {
+ let Name = basename # width # "_lsl" # shift # "MovAlias";
+ let PredicateMethod = "is" # basename # "MovAlias<" # width # ", "
+ # shift # ">";
+ let RenderMethod = "add" # basename # "MovAliasOperands<" # shift # ">";
+ }
+
+ def _movimm : Operand<i32> {
+ let ParserMatchClass = !cast<AsmOperandClass>(NAME # "_asmoperand");
+ }
+
+ def : InstAlias<"mov $Rd, $imm",
+ (INST GPR:$Rd, !cast<Operand>(NAME # "_movimm"):$imm, shift)>;
+}
+
+defm : movw_mov_alias<"MOVZ", MOVZWi, GPR32, 32, 0>;
+defm : movw_mov_alias<"MOVZ", MOVZWi, GPR32, 32, 16>;
+
+defm : movw_mov_alias<"MOVZ", MOVZXi, GPR64, 64, 0>;
+defm : movw_mov_alias<"MOVZ", MOVZXi, GPR64, 64, 16>;
+defm : movw_mov_alias<"MOVZ", MOVZXi, GPR64, 64, 32>;
+defm : movw_mov_alias<"MOVZ", MOVZXi, GPR64, 64, 48>;
+
+defm : movw_mov_alias<"MOVN", MOVNWi, GPR32, 32, 0>;
+defm : movw_mov_alias<"MOVN", MOVNWi, GPR32, 32, 16>;
+
+defm : movw_mov_alias<"MOVN", MOVNXi, GPR64, 64, 0>;
+defm : movw_mov_alias<"MOVN", MOVNXi, GPR64, 64, 16>;
+defm : movw_mov_alias<"MOVN", MOVNXi, GPR64, 64, 32>;
+defm : movw_mov_alias<"MOVN", MOVNXi, GPR64, 64, 48>;
+
let isReMaterializable = 1, isCodeGenOnly = 1, isMoveImm = 1,
isAsCheapAsAMove = 1 in {
// FIXME: The following pseudo instructions are only needed because remat
Modified: llvm/trunk/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp?rev=208605&r1=208604&r2=208605&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp (original)
+++ llvm/trunk/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp Mon May 12 13:03:36 2014
@@ -724,6 +724,44 @@ public:
return isMovWSymbol(Variants);
}
+ template<int RegWidth, int Shift>
+ bool isMOVZMovAlias() const {
+ if (!isImm()) return false;
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ 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;
+ }
+
+ template<int RegWidth, int Shift>
+ bool isMOVNMovAlias() const {
+ if (!isImm()) return false;
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ 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;
+ }
+
bool isFPImm() const { return Kind == k_FPImm; }
bool isBarrier() const { return Kind == k_Barrier; }
bool isSysReg() const { return Kind == k_SysReg; }
@@ -1473,6 +1511,24 @@ public:
Inst.addOperand(MCOperand::CreateImm(Imm));
}
+ template<int Shift>
+ void addMOVZMovAliasOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+
+ const MCConstantExpr *CE = cast<MCConstantExpr>(getImm());
+ uint64_t Value = CE->getValue();
+ Inst.addOperand(MCOperand::CreateImm((Value >> Shift) & 0xffff));
+ }
+
+ template<int Shift>
+ void addMOVNMovAliasOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+
+ const MCConstantExpr *CE = cast<MCConstantExpr>(getImm());
+ uint64_t Value = CE->getValue();
+ Inst.addOperand(MCOperand::CreateImm((~Value >> Shift) & 0xffff));
+ }
+
void addMemoryRegisterOffsetOperands(MCInst &Inst, unsigned N, bool DoShift) {
assert(N == 3 && "Invalid number of operands!");
@@ -3723,63 +3779,7 @@ bool ARM64AsmParser::MatchAndEmitInstruc
StringRef Tok = Op->getToken();
unsigned NumOperands = Operands.size();
- if (Tok == "mov" && NumOperands == 3) {
- // The MOV mnemomic is aliased to movn/movz, depending on the value of
- // the immediate being instantiated.
- // FIXME: Catching this here is a total hack, and we should use tblgen
- // support to implement this instead as soon as it is available.
-
- ARM64Operand *Op2 = static_cast<ARM64Operand *>(Operands[2]);
- if (Op2->isImm()) {
- if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op2->getImm())) {
- uint64_t Val = CE->getValue();
- uint64_t NVal = ~Val;
-
- // If this is a 32-bit register and the value has none of the upper
- // set, clear the complemented upper 32-bits so the logic below works
- // for 32-bit registers too.
- ARM64Operand *Op1 = static_cast<ARM64Operand *>(Operands[1]);
- if (Op1->isReg() &&
- ARM64MCRegisterClasses[ARM64::GPR32allRegClassID].contains(
- Op1->getReg()) &&
- (Val & 0xFFFFFFFFULL) == Val)
- NVal &= 0x00000000FFFFFFFFULL;
-
- // MOVK Rd, imm << 0
- if ((Val & 0xFFFF) == Val)
- rewriteMOVI(Operands, "movz", Val, 0, getContext());
-
- // MOVK Rd, imm << 16
- else if ((Val & 0xFFFF0000ULL) == Val)
- rewriteMOVI(Operands, "movz", Val, 16, getContext());
-
- // MOVK Rd, imm << 32
- else if ((Val & 0xFFFF00000000ULL) == Val)
- rewriteMOVI(Operands, "movz", Val, 32, getContext());
-
- // MOVK Rd, imm << 48
- else if ((Val & 0xFFFF000000000000ULL) == Val)
- rewriteMOVI(Operands, "movz", Val, 48, getContext());
-
- // MOVN Rd, (~imm << 0)
- else if ((NVal & 0xFFFFULL) == NVal)
- rewriteMOVI(Operands, "movn", NVal, 0, getContext());
-
- // MOVN Rd, ~(imm << 16)
- else if ((NVal & 0xFFFF0000ULL) == NVal)
- rewriteMOVI(Operands, "movn", NVal, 16, getContext());
-
- // MOVN Rd, ~(imm << 32)
- else if ((NVal & 0xFFFF00000000ULL) == NVal)
- rewriteMOVI(Operands, "movn", NVal, 32, getContext());
-
- // MOVN Rd, ~(imm << 48)
- else if ((NVal & 0xFFFF000000000000ULL) == NVal)
- rewriteMOVI(Operands, "movn", NVal, 48, getContext());
- }
- }
- } else if (NumOperands == 4) {
- if (NumOperands == 4 && Tok == "lsl") {
+ if (NumOperands == 4 && Tok == "lsl") {
ARM64Operand *Op2 = static_cast<ARM64Operand *>(Operands[2]);
ARM64Operand *Op3 = static_cast<ARM64Operand *>(Operands[3]);
if (Op2->isReg() && Op3->isImm()) {
@@ -3812,7 +3812,6 @@ bool ARM64AsmParser::MatchAndEmitInstruc
delete Op;
}
}
-
// FIXME: Horrible hack to handle the optional LSL shift for vector
// instructions.
} else if (NumOperands == 4 && (Tok == "bic" || Tok == "orr")) {
More information about the llvm-commits
mailing list