summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp15
-rw-r--r--lib/Target/AArch64/AArch64ISelDAGToDAG.cpp5
-rw-r--r--lib/Target/AArch64/AArch64InstrInfo.td19
-rw-r--r--test/CodeGen/AArch64/movw-shift-encoding.ll14
4 files changed, 36 insertions, 17 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index 722ed10f73..cb3b5129f2 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -334,8 +334,8 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section,
*TargetPtr &= 0xff80001fU;
// Immediate goes in bits 20:5 of MOVZ/MOVK instruction
*TargetPtr |= Result >> (48 - 5);
- // Shift is "lsl #48", in bits 22:21
- *TargetPtr |= 3 << 21;
+ // Shift must be "lsl #48", in bits 22:21
+ assert((*TargetPtr >> 21 & 0x3) == 3 && "invalid shift for relocation");
break;
}
case ELF::R_AARCH64_MOVW_UABS_G2_NC: {
@@ -347,8 +347,8 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section,
*TargetPtr &= 0xff80001fU;
// Immediate goes in bits 20:5 of MOVZ/MOVK instruction
*TargetPtr |= ((Result & 0xffff00000000ULL) >> (32 - 5));
- // Shift is "lsl #32", in bits 22:21
- *TargetPtr |= 2 << 21;
+ // Shift must be "lsl #32", in bits 22:21
+ assert((*TargetPtr >> 21 & 0x3) == 2 && "invalid shift for relocation");
break;
}
case ELF::R_AARCH64_MOVW_UABS_G1_NC: {
@@ -359,8 +359,8 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section,
*TargetPtr &= 0xff80001fU;
// Immediate goes in bits 20:5 of MOVZ/MOVK instruction
*TargetPtr |= ((Result & 0xffff0000U) >> (16 - 5));
- // Shift is "lsl #16", in bits 22:21
- *TargetPtr |= 1 << 21;
+ // Shift must be "lsl #16", in bits 22:2
+ assert((*TargetPtr >> 21 & 0x3) == 1 && "invalid shift for relocation");
break;
}
case ELF::R_AARCH64_MOVW_UABS_G0_NC: {
@@ -371,7 +371,8 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section,
*TargetPtr &= 0xff80001fU;
// Immediate goes in bits 20:5 of MOVZ/MOVK instruction
*TargetPtr |= ((Result & 0xffffU) << 5);
- // Shift is "lsl #0", in bits 22:21. No action needed.
+ // Shift must be "lsl #0", in bits 22:21.
+ assert((*TargetPtr >> 21 & 0x3) == 0 && "invalid shift for relocation");
break;
}
}
diff --git a/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 2e37cb41f9..f258a96694 100644
--- a/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -70,10 +70,11 @@ public:
/// Used for pre-lowered address-reference nodes, so we already know
/// the fields match. This operand's job is simply to add an
- /// appropriate shift operand (i.e. 0) to the MOVZ/MOVK instruction.
+ /// appropriate shift operand to the MOVZ/MOVK instruction.
+ template<unsigned LogShift>
bool SelectMOVWAddressRef(SDValue N, SDValue &Imm, SDValue &Shift) {
Imm = N;
- Shift = CurDAG->getTargetConstant(0, MVT::i32);
+ Shift = CurDAG->getTargetConstant(LogShift, MVT::i32);
return true;
}
diff --git a/lib/Target/AArch64/AArch64InstrInfo.td b/lib/Target/AArch64/AArch64InstrInfo.td
index d2cfc7db22..725a12164b 100644
--- a/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/lib/Target/AArch64/AArch64InstrInfo.td
@@ -3974,14 +3974,17 @@ def : movalias<MOVZxii, GPR64, movz64_movimm>;
def : movalias<MOVNwii, GPR32, movn32_movimm>;
def : movalias<MOVNxii, GPR64, movn64_movimm>;
-def movw_addressref : ComplexPattern<i64, 2, "SelectMOVWAddressRef">;
-
-def : Pat<(A64WrapperLarge movw_addressref:$G3, movw_addressref:$G2,
- movw_addressref:$G1, movw_addressref:$G0),
- (MOVKxii (MOVKxii (MOVKxii (MOVZxii movw_addressref:$G3),
- movw_addressref:$G2),
- movw_addressref:$G1),
- movw_addressref:$G0)>;
+def movw_addressref_g0 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<0>">;
+def movw_addressref_g1 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<1>">;
+def movw_addressref_g2 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<2>">;
+def movw_addressref_g3 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<3>">;
+
+def : Pat<(A64WrapperLarge movw_addressref_g3:$G3, movw_addressref_g2:$G2,
+ movw_addressref_g1:$G1, movw_addressref_g0:$G0),
+ (MOVKxii (MOVKxii (MOVKxii (MOVZxii movw_addressref_g3:$G3),
+ movw_addressref_g2:$G2),
+ movw_addressref_g1:$G1),
+ movw_addressref_g0:$G0)>;
//===----------------------------------------------------------------------===//
// PC-relative addressing instructions
diff --git a/test/CodeGen/AArch64/movw-shift-encoding.ll b/test/CodeGen/AArch64/movw-shift-encoding.ll
new file mode 100644
index 0000000000..ec133bd706
--- /dev/null
+++ b/test/CodeGen/AArch64/movw-shift-encoding.ll
@@ -0,0 +1,14 @@
+; RUN: llc -mtriple=aarch64-linux-gnu < %s -show-mc-encoding -code-model=large | FileCheck %s
+
+@var = global i32 0
+
+; CodeGen should ensure that the correct shift bits are set, because the linker
+; isn't going to!
+
+define i32* @get_var() {
+ ret i32* @var
+; CHECK: movz x0, #:abs_g3:var // encoding: [A,A,0xe0'A',0xd2'A']
+; CHECK: movk x0, #:abs_g2_nc:var // encoding: [A,A,0xc0'A',0xf2'A']
+; CHECK: movk x0, #:abs_g1_nc:var // encoding: [A,A,0xa0'A',0xf2'A']
+; CHECK: movk x0, #:abs_g0_nc:var // encoding: [A,A,0x80'A',0xf2'A']
+}