[llvm] [JITlink][AArch32] Implement ELF::R_ARM_MOVT_ABS and R_ARM_MOVW_ABS_NC (PR #66219)
Eymen Ünay via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 13 11:12:36 PDT 2023
https://github.com/eymay updated https://github.com/llvm/llvm-project/pull/66219:
>From c4d4b403adb0ac3c6daeb0d62cf2ec780b41492b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eymen=20=C3=9Cnay?= <eymenunay at outlook.com>
Date: Wed, 13 Sep 2023 16:51:52 +0300
Subject: [PATCH 1/4] [JITlink][AArch32] Implement ELF::R_ARM_MOVT_ABS and
R_ARM_MOVW_ABS_NC
---
.../llvm/ExecutionEngine/JITLink/aarch32.h | 19 +++++-
.../ExecutionEngine/JITLink/ELF_aarch32.cpp | 8 +++
llvm/lib/ExecutionEngine/JITLink/aarch32.cpp | 67 ++++++++++++++++++-
.../JITLink/AArch32/ELF_static_arm_reloc.s | 30 +++++++++
.../ExecutionEngine/JITLink/AArch32Tests.cpp | 42 ++++++++++++
5 files changed, 164 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 05391baecb9a59b..3f36b53d6684a79 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -59,7 +59,13 @@ enum EdgeKind_aarch32 : Edge::Kind {
/// interworking stub.
Arm_Jump24,
- LastArmRelocation = Arm_Jump24,
+ /// Write immediate value to the lower halfword of the destination register
+ Arm_MovwAbsNC,
+
+ /// Write immediate value to the top halfword of the destination register
+ Arm_MovtAbs,
+
+ LastArmRelocation = Arm_MovtAbs,
///
/// Relocations of class Thumb16 and Thumb32 (covers Thumb instruction subset)
@@ -174,6 +180,17 @@ template <> struct FixupInfo<Arm_Call> : public FixupInfo<Arm_Jump24> {
static constexpr uint32_t BitBlx = 0x10000000;
};
+template <> struct FixupInfo<Arm_MovtAbs> {
+ static constexpr uint32_t Opcode = 0x03400000;
+ static constexpr uint32_t OpcodeMask = 0x0ff00000;
+ static constexpr uint32_t ImmMask = 0x000f0fff;
+ static constexpr uint32_t RegMask = 0x0000f000;
+};
+
+template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfo<Arm_MovtAbs> {
+ static constexpr uint32_t Opcode = 0x03000000;
+};
+
template <> struct FixupInfo<Thumb_Jump24> {
static constexpr HalfWords Opcode{0xf000, 0x8000};
static constexpr HalfWords OpcodeMask{0xf800, 0x8000};
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
index 17eba673eb4fa06..4d2dc6846297ded 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
@@ -42,6 +42,10 @@ Expected<aarch32::EdgeKind_aarch32> getJITLinkEdgeKind(uint32_t ELFType) {
return aarch32::Arm_Call;
case ELF::R_ARM_JUMP24:
return aarch32::Arm_Jump24;
+ case ELF::R_ARM_MOVW_ABS_NC:
+ return aarch32::Arm_MovwAbsNC;
+ case ELF::R_ARM_MOVT_ABS:
+ return aarch32::Arm_MovtAbs;
case ELF::R_ARM_THM_CALL:
return aarch32::Thumb_Call;
case ELF::R_ARM_THM_JUMP24:
@@ -68,6 +72,10 @@ Expected<uint32_t> getELFRelocationType(Edge::Kind Kind) {
return ELF::R_ARM_CALL;
case aarch32::Arm_Jump24:
return ELF::R_ARM_JUMP24;
+ case aarch32::Arm_MovwAbsNC:
+ return ELF::R_ARM_MOVW_ABS_NC;
+ case aarch32::Arm_MovtAbs:
+ return ELF::R_ARM_MOVT_ABS;
case aarch32::Thumb_Call:
return ELF::R_ARM_THM_CALL;
case aarch32::Thumb_Jump24:
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index 0e5aa77b8f4388e..f032de1642b6f5f 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -147,6 +147,48 @@ int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo) {
return Rd4;
}
+/// Encode 16-bit immediate value for move instruction formats MOVT A1 and
+/// MOVW A2.
+///
+/// Imm4:Imm12 -> 000000000000:Imm4:0000:Imm12
+///
+uint32_t encodeImmMovtA1MovwA2(uint16_t Value) {
+ uint32_t Imm4 = (Value >> 12) & 0x0f;
+ uint32_t Imm12 = Value & 0x0fff;
+ return (Imm4 << 16) | Imm12;
+}
+
+/// Decode 16-bit immediate value for move instruction formats MOVT A1 and
+/// MOVW A2.
+///
+/// 000000000000:Imm4:0000:Imm12 -> Imm4:Imm12
+///
+uint16_t decodeImmMovtA1MovwA2(uint64_t Value) {
+ uint32_t Imm4 = (Value >> 16) & 0x0f;
+ uint32_t Imm12 = Value & 0x0fff;
+ return (Imm4 << 12) | Imm12;
+}
+
+/// Encode register ID for instruction formats MOVT A1 and
+/// MOVW A2.
+///
+/// Rd4 -> 0000000000000000:Rd4:000000000000
+///
+uint32_t encodeRegMovtA1MovwA2(int64_t Value) {
+ uint32_t Rd4 = (Value & 0x00000f) << 12;
+ return Rd4;
+}
+
+/// Decode register ID for instruction formats MOVT A1 and
+/// MOVW A2.
+///
+/// 0000000000000000:Rd4:000000000000 -> Rd4
+///
+int64_t decodeRegMovtA1MovwA2(uint64_t Value) {
+ uint32_t Rd4 = (Value >> 12) & 0x00000f;
+ return Rd4;
+}
+
/// 32-bit Thumb instructions are stored as two little-endian halfwords.
/// An instruction at address A encodes bytes A+1, A in the first halfword (Hi),
/// followed by bytes A+3, A+2 in the second halfword (Lo).
@@ -297,6 +339,16 @@ Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, const Edge &E) {
return makeUnexpectedOpcodeError(G, R, Kind);
return decodeImmBA1BlA1BlxA2(R.Wd);
+ case Arm_MovwAbsNC:
+ if (!checkOpcode<Arm_MovwAbsNC>(R))
+ return makeUnexpectedOpcodeError(G, R, Kind);
+ return decodeImmMovtA1MovwA2(R.Wd);
+
+ case Arm_MovtAbs:
+ if (!checkOpcode<Arm_MovtAbs>(R))
+ return makeUnexpectedOpcodeError(G, R, Kind);
+ return decodeImmMovtA1MovwA2(R.Wd);
+
default:
return make_error<JITLinkError>(
"In graph " + G.getName() + ", section " + B.getSection().getName() +
@@ -450,7 +502,20 @@ Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) {
return Error::success();
}
-
+ case Arm_MovwAbsNC: {
+ if (!checkOpcode<Arm_MovwAbsNC>(R))
+ return makeUnexpectedOpcodeError(G, R, Kind);
+ uint16_t Value = (TargetAddress + Addend) & 0xffff;
+ writeImmediate<Arm_MovwAbsNC>(R, encodeImmMovtA1MovwA2(Value));
+ return Error::success();
+ }
+ case Arm_MovtAbs: {
+ if (!checkOpcode<Arm_MovtAbs>(R))
+ return makeUnexpectedOpcodeError(G, R, Kind);
+ uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff;
+ writeImmediate<Arm_MovtAbs>(R, encodeImmMovtA1MovwA2(Value));
+ return Error::success();
+ }
default:
return make_error<JITLinkError>(
"In graph " + G.getName() + ", section " + B.getSection().getName() +
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
index f91635f80f8b367..fb912f47d8b5a3b 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
@@ -50,6 +50,36 @@ jump24_target:
bx lr
.size jump24_target, .-jump24_target
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_MOVW_ABS_NC data_symbol
+# CHECK-INSTR: 00000010 <movw>:
+# CHECK-INSTR: 10: e3000000 movw r0, #0x0
+# jitlink-check: decode_operand(movw, 1) = (data_symbol&0x0000ffff)
+ .globl movw
+ .type movw,%function
+ .p2align 2
+movw:
+ movw r0, :lower16:data_symbol
+ .size movw, .-movw
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_MOVT_ABS data_symbol
+# CHECK-INSTR: 00000014 <movt>:
+# CHECK-INSTR: 14: e3400000 movt r0, #0x0
+# jitlink-check: decode_operand(movt, 2) = (data_symbol&0xffff0000>>16)
+ .globl movt
+ .type movt,%function
+ .p2align 2
+movt:
+ movt r0, :upper16:data_symbol
+ .size movt, .-movt
+
+ .data
+ .global data_symbol
+data_symbol:
+ .long 1073741822
+
+ .text
+
# Empty main function for jitlink to be happy
.globl main
.type main,%function
diff --git a/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp b/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp
index 15c00baebe8ce54..17011b8dfbd498a 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp
@@ -76,12 +76,16 @@ HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value);
uint32_t encodeImmBA1BlA1BlxA2(int64_t Value);
HalfWords encodeImmMovtT1MovwT3(uint16_t Value);
HalfWords encodeRegMovtT1MovwT3(int64_t Value);
+uint32_t encodeImmMovtA1MovwA2(uint16_t Value);
+uint32_t encodeRegMovtA1MovwA2(int64_t Value);
int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo);
int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo);
int64_t decodeImmBA1BlA1BlxA2(int64_t Value);
uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo);
int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo);
+uint16_t decodeImmMovtA1MovwA2(uint64_t Value);
+int64_t decodeRegMovtA1MovwA2(uint64_t Value);
} // namespace aarch32
} // namespace jitlink
@@ -242,3 +246,41 @@ TEST(AArch32_Relocations, Thumb_MovtAbs) {
}
}
}
+
+/// Write immediate value to the top halfword of the destination register
+TEST(AArch32_Relocations, Arm_MovtAbs) {
+ static_assert(isUInt<16>(65535), "Max value");
+ static_assert(!isUInt<16>(65536), "First overflow");
+
+ constexpr uint32_t ImmMask = FixupInfo<Arm_MovtAbs>::ImmMask;
+ constexpr uint32_t RegMask = FixupInfo<Arm_MovtAbs>::RegMask;
+
+ static std::array<uint8_t, 3> Registers{0, 5, 12};
+ static std::array<uint32_t, 3> MemPresets{
+ 0xfeeffff7, // common
+ 0x00000000, // zeros
+ 0xffffffff, // ones
+ };
+
+ auto EncodeDecode = [](uint64_t In, MutableWord &Mem) {
+ Mem.patch(encodeImmMovtA1MovwA2(In), ImmMask);
+ return decodeImmMovtA1MovwA2(Mem.Wd);
+ };
+
+ for (MutableWord Mem : MemPresets) {
+ for (uint8_t Reg : Registers) {
+ MutableWord UnaffectedBits(Mem.Wd & ~(ImmMask | RegMask));
+
+ Mem.patch(encodeRegMovtA1MovwA2(Reg), RegMask);
+ EXPECT_EQ(EncodeDecode(0x76bb, Mem), 0x76bb); // Common value
+ EXPECT_EQ(EncodeDecode(0, Mem), 0); // Minimum value
+ EXPECT_EQ(EncodeDecode(0xffff, Mem), 0xffff); // Maximum value
+ EXPECT_NE(EncodeDecode(0x10000, Mem), 0x10000); // First overflow
+
+ // Destination register as well as unaffacted bits should be intact
+ EXPECT_EQ(decodeRegMovtA1MovwA2(Mem.Wd), Reg);
+ EXPECT_TRUE(UnaffectedBits.Wd == (Mem.Wd & ~(ImmMask | RegMask)))
+ << "Diff outside immediate/register field";
+ }
+ }
+}
>From 13b556bff625d2c86aea928f569e58896d99187c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eymen=20=C3=9Cnay?= <eymenunay at outlook.com>
Date: Wed, 13 Sep 2023 20:51:25 +0300
Subject: [PATCH 2/4] fixup! [JITlink][AArch32] Implement ELF::R_ARM_MOVT_ABS
and R_ARM_MOVW_ABS_NC
---
.../JITLink/AArch32/ELF_static_arm_reloc.s | 8 +++++---
llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp | 6 +++---
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
index fb912f47d8b5a3b..6639e3258a72a33 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
@@ -65,6 +65,8 @@ movw:
# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_MOVT_ABS data_symbol
# CHECK-INSTR: 00000014 <movt>:
# CHECK-INSTR: 14: e3400000 movt r0, #0x0
+# We decode the operand with index 2, because movt generates two leading implicit
+# predicate operands that we have to skip in order to decode the data_symbol operand
# jitlink-check: decode_operand(movt, 2) = (data_symbol&0xffff0000>>16)
.globl movt
.type movt,%function
@@ -73,12 +75,12 @@ movt:
movt r0, :upper16:data_symbol
.size movt, .-movt
- .data
+ .data
.global data_symbol
data_symbol:
- .long 1073741822
+ .long 1073741822
- .text
+ .text
# Empty main function for jitlink to be happy
.globl main
diff --git a/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp b/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp
index 17011b8dfbd498a..3f581445a2d6295 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp
@@ -187,7 +187,7 @@ TEST(AArch32_Relocations, Arm_Call_Bare) {
0xffffffff, // ones
};
- auto EncodeDecode = [](int64_t In, MutableWord &Mem) {
+ auto EncodeDecode = [=](int64_t In, MutableWord &Mem) {
Mem.patch(encodeImmBA1BlA1BlxA2(In), ImmMask);
return decodeImmBA1BlA1BlxA2(Mem.Wd);
};
@@ -262,7 +262,7 @@ TEST(AArch32_Relocations, Arm_MovtAbs) {
0xffffffff, // ones
};
- auto EncodeDecode = [](uint64_t In, MutableWord &Mem) {
+ auto EncodeDecode = [=](uint64_t In, MutableWord &Mem) {
Mem.patch(encodeImmMovtA1MovwA2(In), ImmMask);
return decodeImmMovtA1MovwA2(Mem.Wd);
};
@@ -277,7 +277,7 @@ TEST(AArch32_Relocations, Arm_MovtAbs) {
EXPECT_EQ(EncodeDecode(0xffff, Mem), 0xffff); // Maximum value
EXPECT_NE(EncodeDecode(0x10000, Mem), 0x10000); // First overflow
- // Destination register as well as unaffacted bits should be intact
+ // Destination register as well as unaffected bits should be intact
EXPECT_EQ(decodeRegMovtA1MovwA2(Mem.Wd), Reg);
EXPECT_TRUE(UnaffectedBits.Wd == (Mem.Wd & ~(ImmMask | RegMask)))
<< "Diff outside immediate/register field";
>From e581636b08964be05b149eb8c7742ebcbc964a0a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eymen=20=C3=9Cnay?= <eymenunay at outlook.com>
Date: Wed, 13 Sep 2023 21:00:15 +0300
Subject: [PATCH 3/4] fixup! fixup! [JITlink][AArch32] Implement
ELF::R_ARM_MOVT_ABS and R_ARM_MOVW_ABS_NC
---
.../ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
index 6639e3258a72a33..e4615ace7a1a60c 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
@@ -65,8 +65,8 @@ movw:
# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_MOVT_ABS data_symbol
# CHECK-INSTR: 00000014 <movt>:
# CHECK-INSTR: 14: e3400000 movt r0, #0x0
-# We decode the operand with index 2, because movt generates two leading implicit
-# predicate operands that we have to skip in order to decode the data_symbol operand
+# We decode the operand with index 2, because movt generates two leading implicit
+# predicate operands that we have to skip in order to decode the data_symbol operand
# jitlink-check: decode_operand(movt, 2) = (data_symbol&0xffff0000>>16)
.globl movt
.type movt,%function
>From a569562355035321773bb3cce77179169669709b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eymen=20=C3=9Cnay?= <eymenunay at outlook.com>
Date: Wed, 13 Sep 2023 21:11:04 +0300
Subject: [PATCH 4/4] fixup! fixup! fixup! [JITlink][AArch32] Implement
ELF::R_ARM_MOVT_ABS and R_ARM_MOVW_ABS_NC
---
.../ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
index e4615ace7a1a60c..cc65193af736f3b 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_static_arm_reloc.s
@@ -65,8 +65,8 @@ movw:
# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_MOVT_ABS data_symbol
# CHECK-INSTR: 00000014 <movt>:
# CHECK-INSTR: 14: e3400000 movt r0, #0x0
-# We decode the operand with index 2, because movt generates two leading implicit
-# predicate operands that we have to skip in order to decode the data_symbol operand
+# We decode the operand with index 2, because movt generates one leading implicit
+# predicate operand that we have to skip in order to decode the data_symbol operand
# jitlink-check: decode_operand(movt, 2) = (data_symbol&0xffff0000>>16)
.globl movt
.type movt,%function
More information about the llvm-commits
mailing list