aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Northover <tnorthover@apple.com>2013-07-01 19:23:10 +0000
committerTim Northover <tnorthover@apple.com>2013-07-01 19:23:10 +0000
commit6711fc28a41c05e1c8398393c7794c41b2ee0202 (patch)
treee1c42a6bd26aae3b40cf42926f328181c80278a9
parent1a84066b8c6e57d43309edc8cad2ca32acfbf836 (diff)
downloadexternal_llvm-6711fc28a41c05e1c8398393c7794c41b2ee0202.zip
external_llvm-6711fc28a41c05e1c8398393c7794c41b2ee0202.tar.gz
external_llvm-6711fc28a41c05e1c8398393c7794c41b2ee0202.tar.bz2
AArch64: correct CodeGen of MOVZ/MOVK combinations.
According to the AArch64 ELF specification (4.6.8), it's the assembler's responsibility to make sure the shift amount is correct in relocated MOVZ/MOVK instructions. This wasn't being obeyed by either the MCJIT CodeGen or RuntimeDyldELF (which happened to work out well for JIT tests). This commit should make us compliant in this area. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@185360 91177308-0d34-0410-b5e6-96231b3b80d8
-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 722ed10..cb3b512 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 2e37cb4..f258a96 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 d2cfc7d..725a121 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 0000000..ec133bd
--- /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']
+}