Merge "update new build.config.constants rather than build.config.common"
diff --git a/cherrypick_cl.py b/cherrypick_cl.py
index 555d41f..96ceacb 100755
--- a/cherrypick_cl.py
+++ b/cherrypick_cl.py
@@ -59,20 +59,22 @@
 
 @dataclass
 class PatchItem:
-    comment: str
-    rel_patch_path: str
-    bugs_tests: Optional[List(str)]
-    start_version: int
     end_version: Optional[int]
+    metadata: Dict[str, Any]
+        # info: Optional[List[str]]
+        # title: str
+    platforms: List[str]
+    rel_patch_path: str
+    start_version: int
 
     @classmethod
     def from_dict(cls, d: Dict[str, Any]) -> PatchItem:
         return PatchItem(
-            comment=d['comment'],
+            end_version=d['end_version'],
+            metadata=d['metadata'],
+            platforms=d['platforms'],
             rel_patch_path=d['rel_patch_path'],
-            bugs_tests=d['bugs_tests'],
-            start_version=d['start_version'],
-            end_version=d['end_version'])
+            start_version=d['start_version'])
 
     def to_dict(self) -> Dict[str, Any]:
         return dataclasses.asdict(self, dict_factory=collections.OrderedDict)
@@ -114,7 +116,8 @@
     def save_to_file(self):
         array = [patch.to_dict() for patch in self]
         with open(self.JSON_FILE_PATH, 'w') as fh:
-            json.dump(array, fh, indent=4)
+            json.dump(array, fh, indent=4, separators=(',', ': '), sort_keys=True)
+            fh.write('\n')
 
 
 def generate_patch_files(sha_list: List[str], start_version: int) -> PatchList:
@@ -133,11 +136,13 @@
 
         commit_subject = check_output(
             f'git log -n1 --format=%s {sha}', shell=True, cwd=upstream_dir)
-        comment = '[UPSTREAM] ' + commit_subject.strip()
+        info: Optional[List[str]] = []
+        title = '[UPSTREAM] ' + commit_subject.strip()
         rel_patch_path = f'cherry/{sha}.patch'
         end_version = sha_to_revision(sha)
-        bugs_tests = None
-        result.append(PatchItem(comment, rel_patch_path, bugs_tests, start_version, end_version))
+        metadata = { 'info': info, 'title': title }
+        platforms = ['android']
+        result.append(PatchItem(end_version, metadata, platforms, rel_patch_path, start_version))
     return result
 
 
@@ -162,7 +167,7 @@
             commit_lines += [f'Bug: {bug}', '']
     for patch in new_patches:
         sha = patch.sha[:11]
-        subject = patch.comment
+        subject = patch.metadata['title']
         if subject.startswith('[UPSTREAM] '):
             subject = subject[len('[UPSTREAM] '):]
         commit_lines.append(sha + ' ' + subject)
diff --git a/constants.py b/constants.py
index 8662247..470fe2e 100644
--- a/constants.py
+++ b/constants.py
@@ -21,7 +21,7 @@
 MAC_MIN_VERSION: str = '10.14'
 
 # This is the baseline stable version of Clang to start our stage-1 build.
-CLANG_PREBUILT_VERSION: str = 'clang-r437112'
+CLANG_PREBUILT_VERSION: str = 'clang-r437112b'
 
 # This is the ndk version used to build runtimes.
 NDK_VERSION: str = 'r23'
diff --git a/patches/PATCHES.json b/patches/PATCHES.json
index 977fac5..acdd19b 100644
--- a/patches/PATCHES.json
+++ b/patches/PATCHES.json
@@ -112,6 +112,18 @@
         "start_version": 437112
     },
     {
+        "end_version": 442024,
+        "metadata": {
+            "info": [],
+            "title": "[UPSTREAM] [ARM] Use hardware TLS register in Thumb2 mode when -mtp=cp15 is passed"
+        },
+        "platforms": [
+            "android"
+        ],
+        "rel_patch_path": "cherry/d7e089f2d6a5cd5f283a90ab29241d20d4fc3ed1.patch",
+        "start_version": 437112
+    },
+    {
         "end_version": 442582,
         "metadata": {
             "info": [],
@@ -148,6 +160,18 @@
         "start_version": 437112
     },
     {
+        "end_version": 444762,
+        "metadata": {
+            "info": [],
+            "title": "[UPSTREAM] [ARM] implement support for ALU/LDR PC-relative group relocations"
+        },
+        "platforms": [
+            "android"
+        ],
+        "rel_patch_path": "cherry/da66263b6e505a4c605efbe8d68c3b09ad3606a4.patch",
+        "start_version": 437112
+    },
+    {
         "end_version": null,
         "metadata": {
             "info": [],
diff --git a/patches/cherry/d7e089f2d6a5cd5f283a90ab29241d20d4fc3ed1.patch b/patches/cherry/d7e089f2d6a5cd5f283a90ab29241d20d4fc3ed1.patch
new file mode 100644
index 0000000..7d04dcb
--- /dev/null
+++ b/patches/cherry/d7e089f2d6a5cd5f283a90ab29241d20d4fc3ed1.patch
@@ -0,0 +1,84 @@
+From d7e089f2d6a5cd5f283a90ab29241d20d4fc3ed1 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@google.com>
+Date: Wed, 27 Oct 2021 16:27:00 -0700
+Subject: [PATCH] [ARM] Use hardware TLS register in Thumb2 mode when -mtp=cp15
+ is passed
+
+In ARM mode, passing -mtp=cp15 forces the use of an inline MRC system register read to move the thread pointer value into a register.
+
+Currently, in Thumb2 mode, -mtp=cp15 is ignored, and a call to the __aeabi_read_tp helper is emitted instead.
+
+This is inconsistent, and breaks the Linux/ARM build for Thumb2 targets, as the Linux kernel does not provide an implementation of __aeabi_read_tp,.
+
+Reviewed By: nickdesaulniers, peter.smith
+
+Differential Revision: https://reviews.llvm.org/D112600
+---
+ llvm/lib/Target/ARM/ARMInstrThumb.td    | 1 +
+ llvm/lib/Target/ARM/ARMInstrThumb2.td   | 3 +++
+ llvm/test/CodeGen/ARM/readtp.ll         | 2 ++
+ llvm/test/CodeGen/ARM/thread_pointer.ll | 8 ++++++--
+ 4 files changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/llvm/lib/Target/ARM/ARMInstrThumb.td b/llvm/lib/Target/ARM/ARMInstrThumb.td
+index 0305d13c61c5..bf717a4056e9 100644
+--- a/llvm/lib/Target/ARM/ARMInstrThumb.td
++++ b/llvm/lib/Target/ARM/ARMInstrThumb.td
+@@ -1520,6 +1520,7 @@ def tTBH_JT : tPseudoInst<(outs),
+ let isCall = 1, Defs = [R0, R12, LR, CPSR], Uses = [SP] in
+ def tTPsoft : tPseudoInst<(outs), (ins), 4, IIC_Br,
+                           [(set R0, ARMthread_pointer)]>,
++                          Requires<[IsThumb, IsReadTPSoft]>,
+                           Sched<[WriteBr]>;
+ 
+ //===----------------------------------------------------------------------===//
+diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td
+index 0cb58b8318bd..783db9dde17f 100644
+--- a/llvm/lib/Target/ARM/ARMInstrThumb2.td
++++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td
+@@ -4671,6 +4671,9 @@ def t2CDP2 : T2Cop<0b1111, (outs), (ins p_imm:$cop, imm0_15:$opc1,
+ }
+ 
+ 
++// Reading thread pointer from coprocessor register
++def : T2Pat<(ARMthread_pointer), (t2MRC 15, 0, 13, 0, 3)>,
++      Requires<[IsThumb2, IsReadTPHard]>;
+ 
+ //===----------------------------------------------------------------------===//
+ // ARMv8.1 Privilege Access Never extension
+diff --git a/llvm/test/CodeGen/ARM/readtp.ll b/llvm/test/CodeGen/ARM/readtp.ll
+index 190768076351..0a97bfcd3b4b 100644
+--- a/llvm/test/CodeGen/ARM/readtp.ll
++++ b/llvm/test/CodeGen/ARM/readtp.ll
+@@ -1,5 +1,7 @@
+ ; RUN: llc -mtriple=armeb-linux-gnueabihf -O2 -mattr=+read-tp-hard %s -o - | FileCheck %s -check-prefix=CHECK-HARD
+ ; RUN: llc -mtriple=armeb-linux-gnueabihf -O2 %s -o - | FileCheck %s -check-prefix=CHECK-SOFT
++; RUN: llc -mtriple=thumbv7-linux-gnueabihf -O2 -mattr=+read-tp-hard %s -o - | FileCheck %s -check-prefix=CHECK-HARD
++; RUN: llc -mtriple=thumbv7-linux-gnueabihf -O2 %s -o - | FileCheck %s -check-prefix=CHECK-SOFT
+ 
+ 
+ ; __thread int counter;
+diff --git a/llvm/test/CodeGen/ARM/thread_pointer.ll b/llvm/test/CodeGen/ARM/thread_pointer.ll
+index c6318a58277c..f1ef2ddac2d0 100644
+--- a/llvm/test/CodeGen/ARM/thread_pointer.ll
++++ b/llvm/test/CodeGen/ARM/thread_pointer.ll
+@@ -1,4 +1,7 @@
+-; RUN: llc -mtriple arm-linux-gnueabi -filetype asm -o - %s | FileCheck %s
++; RUN: llc -mtriple arm-linux-gnueabi -o - %s | FileCheck %s -check-prefix=CHECK-SOFT
++; RUN: llc -mtriple arm-linux-gnueabi -mattr=+read-tp-hard -o - %s | FileCheck %s -check-prefix=CHECK-HARD
++; RUN: llc -mtriple thumbv7-linux-gnueabi -o - %s | FileCheck %s -check-prefix=CHECK-SOFT
++; RUN: llc -mtriple thumbv7-linux-gnueabi -mattr=+read-tp-hard -o - %s | FileCheck %s -check-prefix=CHECK-HARD
+ 
+ declare i8* @llvm.thread.pointer()
+ 
+@@ -8,5 +11,6 @@ entry:
+   ret i8* %tmp1
+ }
+ 
+-; CHECK: bl __aeabi_read_tp
++; CHECK-SOFT: bl __aeabi_read_tp
++; CHECK-HARD: mrc p15, #0, {{r[0-9]+}}, c13, c0, #3
+ 
+-- 
+2.34.1.448.ga2b2bfdf31-goog
+
diff --git a/patches/cherry/da66263b6e505a4c605efbe8d68c3b09ad3606a4.patch b/patches/cherry/da66263b6e505a4c605efbe8d68c3b09ad3606a4.patch
new file mode 100644
index 0000000..43c8d0b
--- /dev/null
+++ b/patches/cherry/da66263b6e505a4c605efbe8d68c3b09ad3606a4.patch
@@ -0,0 +1,522 @@
+From da66263b6e505a4c605efbe8d68c3b09ad3606a4 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Sat, 27 Nov 2021 10:26:37 +0100
+Subject: [PATCH] [ARM] implement support for ALU/LDR PC-relative group
+ relocations
+
+Currently, LLD does not support the complete set of ARM group relocations.
+Given that I intend to start using these in the Linux kernel [0], let's add
+support for these.
+
+This implements the group processing as documented in the ELF psABI. Notably,
+this means support is dropped for very far symbol references that also carry a
+small component, where the immediate is rotated in such a way that only part of
+it wraps to the other end of the 32-bit word. To me, it seems unlikely that
+this is something anyone could be relying on, but of course I could be wrong.
+
+[0] https://lore.kernel.org/r/20211122092816.2865873-8-ardb@kernel.org/
+
+Reviewed By: peter.smith, MaskRay
+
+Differential Revision: https://reviews.llvm.org/D114172
+---
+ lld/ELF/Arch/ARM.cpp            | 202 ++++++++++++++++++++------------
+ lld/test/ELF/arm-adr-err-long.s |  57 +++++++++
+ lld/test/ELF/arm-adr-err.s      |   6 +
+ lld/test/ELF/arm-adr-long.s     | 111 ++++++++++++++----
+ lld/test/ELF/arm-adr.s          |   4 +-
+ 5 files changed, 275 insertions(+), 105 deletions(-)
+ create mode 100644 lld/test/ELF/arm-adr-err-long.s
+
+diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp
+index f2e4a2a14ad6..b7c2eb74757c 100644
+--- a/lld/ELF/Arch/ARM.cpp
++++ b/lld/ELF/Arch/ARM.cpp
+@@ -140,7 +140,16 @@ RelExpr ARM::getRelExpr(RelType type, const Symbol &s,
+   case R_ARM_THM_MOVT_PREL:
+     return R_PC;
+   case R_ARM_ALU_PC_G0:
++  case R_ARM_ALU_PC_G0_NC:
++  case R_ARM_ALU_PC_G1:
++  case R_ARM_ALU_PC_G1_NC:
++  case R_ARM_ALU_PC_G2:
+   case R_ARM_LDR_PC_G0:
++  case R_ARM_LDR_PC_G1:
++  case R_ARM_LDR_PC_G2:
++  case R_ARM_LDRS_PC_G0:
++  case R_ARM_LDRS_PC_G1:
++  case R_ARM_LDRS_PC_G2:
+   case R_ARM_THM_ALU_PREL_11_0:
+   case R_ARM_THM_PC8:
+   case R_ARM_THM_PC12:
+@@ -411,56 +420,83 @@ static void stateChangeWarning(uint8_t *loc, RelType relt, const Symbol &s) {
+   }
+ }
+ 
+-// Utility functions taken from ARMAddressingModes.h, only changes are LLD
+-// coding style.
+-
+ // Rotate a 32-bit unsigned value right by a specified amt of bits.
+ static uint32_t rotr32(uint32_t val, uint32_t amt) {
+   assert(amt < 32 && "Invalid rotate amount");
+   return (val >> amt) | (val << ((32 - amt) & 31));
+ }
+ 
+-// Rotate a 32-bit unsigned value left by a specified amt of bits.
+-static uint32_t rotl32(uint32_t val, uint32_t amt) {
+-  assert(amt < 32 && "Invalid rotate amount");
+-  return (val << amt) | (val >> ((32 - amt) & 31));
++static std::pair<uint32_t, uint32_t> getRemAndLZForGroup(unsigned group,
++                                                         uint32_t val) {
++  uint32_t rem, lz;
++  do {
++    lz = llvm::countLeadingZeros(val) & ~1;
++    rem = val;
++    if (lz == 32) // implies rem == 0
++      break;
++    val &= 0xffffff >> lz;
++  } while (group--);
++  return {rem, lz};
+ }
+ 
+-// Try to encode a 32-bit unsigned immediate imm with an immediate shifter
+-// operand, this form is an 8-bit immediate rotated right by an even number of
+-// bits. We compute the rotate amount to use.  If this immediate value cannot be
+-// handled with a single shifter-op, determine a good rotate amount that will
+-// take a maximal chunk of bits out of the immediate.
+-static uint32_t getSOImmValRotate(uint32_t imm) {
+-  // 8-bit (or less) immediates are trivially shifter_operands with a rotate
+-  // of zero.
+-  if ((imm & ~255U) == 0)
+-    return 0;
+-
+-  // Use CTZ to compute the rotate amount.
+-  unsigned tz = llvm::countTrailingZeros(imm);
+-
+-  // Rotate amount must be even.  Something like 0x200 must be rotated 8 bits,
+-  // not 9.
+-  unsigned rotAmt = tz & ~1;
+-
+-  // If we can handle this spread, return it.
+-  if ((rotr32(imm, rotAmt) & ~255U) == 0)
+-    return (32 - rotAmt) & 31; // HW rotates right, not left.
++static void encodeAluGroup(uint8_t *loc, const Relocation &rel, uint64_t val,
++                           int group, bool check) {
++  // ADD/SUB (immediate) add = bit23, sub = bit22
++  // immediate field carries is a 12-bit modified immediate, made up of a 4-bit
++  // even rotate right and an 8-bit immediate.
++  uint32_t opcode = 0x00800000;
++  if (val >> 63) {
++    opcode = 0x00400000;
++    val = -val;
++  }
++  uint32_t imm, lz;
++  std::tie(imm, lz) = getRemAndLZForGroup(group, val);
++  uint32_t rot = 0;
++  if (lz < 24) {
++    imm = rotr32(imm, 24 - lz);
++    rot = (lz + 8) << 7;
++  }
++  if (check && imm > 0xff)
++    error(getErrorLocation(loc) + "unencodeable immediate " + Twine(val).str() +
++          " for relocation " + toString(rel.type));
++  write32le(loc, (read32le(loc) & 0xff3ff000) | opcode | rot | (imm & 0xff));
++}
+ 
+-  // For values like 0xF000000F, we should ignore the low 6 bits, then
+-  // retry the hunt.
+-  if (imm & 63U) {
+-    unsigned tz2 = countTrailingZeros(imm & ~63U);
+-    unsigned rotAmt2 = tz2 & ~1;
+-    if ((rotr32(imm, rotAmt2) & ~255U) == 0)
+-      return (32 - rotAmt2) & 31; // HW rotates right, not left.
++static void encodeLdrGroup(uint8_t *loc, const Relocation &rel, uint64_t val,
++                           int group) {
++  // R_ARM_LDR_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a
++  // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear
++  // bottom bit to recover S + A - P.
++  if (rel.sym->isFunc())
++    val &= ~0x1;
++  // LDR (literal) u = bit23
++  uint32_t opcode = 0x00800000;
++  if (val >> 63) {
++    opcode = 0x0;
++    val = -val;
+   }
++  uint32_t imm = getRemAndLZForGroup(group, val).first;
++  checkUInt(loc, imm, 12, rel);
++  write32le(loc, (read32le(loc) & 0xff7ff000) | opcode | imm);
++}
+ 
+-  // Otherwise, we have no way to cover this span of bits with a single
+-  // shifter_op immediate.  Return a chunk of bits that will be useful to
+-  // handle.
+-  return (32 - rotAmt) & 31; // HW rotates right, not left.
++static void encodeLdrsGroup(uint8_t *loc, const Relocation &rel, uint64_t val,
++                            int group) {
++  // R_ARM_LDRS_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a
++  // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear
++  // bottom bit to recover S + A - P.
++  if (rel.sym->isFunc())
++    val &= ~0x1;
++  // LDRD/LDRH/LDRSB/LDRSH (literal) u = bit23
++  uint32_t opcode = 0x00800000;
++  if (val >> 63) {
++    opcode = 0x0;
++    val = -val;
++  }
++  uint32_t imm = getRemAndLZForGroup(group, val).first;
++  checkUInt(loc, imm, 8, rel);
++  write32le(loc, (read32le(loc) & 0xff7ff0f0) | opcode | ((imm & 0xf0) << 4) |
++                     (imm & 0xf));
+ }
+ 
+ void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
+@@ -633,45 +669,39 @@ void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
+                   ((val << 4) & 0x7000) |    // imm3
+                   (val & 0x00ff));           // imm8
+     break;
+-  case R_ARM_ALU_PC_G0: {
+-    // ADR (literal) add = bit23, sub = bit22
+-    // literal is a 12-bit modified immediate, made up of a 4-bit even rotate
+-    // right and an 8-bit immediate. The code-sequence here is derived from
+-    // ARMAddressingModes.h in llvm/Target/ARM/MCTargetDesc. In our case we
+-    // want to give an error if we cannot encode the constant.
+-    uint32_t opcode = 0x00800000;
+-    if (val >> 63) {
+-      opcode = 0x00400000;
+-      val = ~val + 1;
+-    }
+-    if ((val & ~255U) != 0) {
+-      uint32_t rotAmt = getSOImmValRotate(val);
+-      // Error if we cannot encode this with a single shift
+-      if (rotr32(~255U, rotAmt) & val)
+-        error(getErrorLocation(loc) + "unencodeable immediate " +
+-              Twine(val).str() + " for relocation " + toString(rel.type));
+-      val = rotl32(val, rotAmt) | ((rotAmt >> 1) << 8);
+-    }
+-    write32le(loc, (read32le(loc) & 0xff0ff000) | opcode | val);
++  case R_ARM_ALU_PC_G0:
++    encodeAluGroup(loc, rel, val, 0, true);
+     break;
+-  }
+-  case R_ARM_LDR_PC_G0: {
+-    // R_ARM_LDR_PC_G0 is S + A - P, we have ((S + A) | T) - P, if S is a
+-    // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear
+-    // bottom bit to recover S + A - P.
+-    if (rel.sym->isFunc())
+-      val &= ~0x1;
+-    // LDR (literal) u = bit23
+-    int64_t imm = val;
+-    uint32_t u = 0x00800000;
+-    if (imm < 0) {
+-      imm = -imm;
+-      u = 0;
+-    }
+-    checkUInt(loc, imm, 12, rel);
+-    write32le(loc, (read32le(loc) & 0xff7ff000) | u | imm);
++  case R_ARM_ALU_PC_G0_NC:
++    encodeAluGroup(loc, rel, val, 0, false);
++    break;
++  case R_ARM_ALU_PC_G1:
++    encodeAluGroup(loc, rel, val, 1, true);
++    break;
++  case R_ARM_ALU_PC_G1_NC:
++    encodeAluGroup(loc, rel, val, 1, false);
++    break;
++  case R_ARM_ALU_PC_G2:
++    encodeAluGroup(loc, rel, val, 2, true);
++    break;
++  case R_ARM_LDR_PC_G0:
++    encodeLdrGroup(loc, rel, val, 0);
++    break;
++  case R_ARM_LDR_PC_G1:
++    encodeLdrGroup(loc, rel, val, 1);
++    break;
++  case R_ARM_LDR_PC_G2:
++    encodeLdrGroup(loc, rel, val, 2);
++    break;
++  case R_ARM_LDRS_PC_G0:
++    encodeLdrsGroup(loc, rel, val, 0);
++    break;
++  case R_ARM_LDRS_PC_G1:
++    encodeLdrsGroup(loc, rel, val, 1);
++    break;
++  case R_ARM_LDRS_PC_G2:
++    encodeLdrsGroup(loc, rel, val, 2);
+     break;
+-  }
+   case R_ARM_THM_ALU_PREL_11_0: {
+     // ADR encoding T2 (sub), T3 (add) i:imm3:imm8
+     int64_t imm = val;
+@@ -816,7 +846,11 @@ int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const {
+                             ((lo & 0x7000) >> 4) |  // imm3
+                             (lo & 0x00ff));         // imm8
+   }
+-  case R_ARM_ALU_PC_G0: {
++  case R_ARM_ALU_PC_G0:
++  case R_ARM_ALU_PC_G0_NC:
++  case R_ARM_ALU_PC_G1:
++  case R_ARM_ALU_PC_G1_NC:
++  case R_ARM_ALU_PC_G2: {
+     // 12-bit immediate is a modified immediate made up of a 4-bit even
+     // right rotation and 8-bit constant. After the rotation the value
+     // is zero-extended. When bit 23 is set the instruction is an add, when
+@@ -825,13 +859,25 @@ int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const {
+     uint32_t val = rotr32(instr & 0xff, ((instr & 0xf00) >> 8) * 2);
+     return (instr & 0x00400000) ? -val : val;
+   }
+-  case R_ARM_LDR_PC_G0: {
++  case R_ARM_LDR_PC_G0:
++  case R_ARM_LDR_PC_G1:
++  case R_ARM_LDR_PC_G2: {
+     // ADR (literal) add = bit23, sub = bit22
+     // LDR (literal) u = bit23 unsigned imm12
+     bool u = read32le(buf) & 0x00800000;
+     uint32_t imm12 = read32le(buf) & 0xfff;
+     return u ? imm12 : -imm12;
+   }
++  case R_ARM_LDRS_PC_G0:
++  case R_ARM_LDRS_PC_G1:
++  case R_ARM_LDRS_PC_G2: {
++    // LDRD/LDRH/LDRSB/LDRSH (literal) u = bit23 unsigned imm8
++    uint32_t opcode = read32le(buf);
++    bool u = opcode & 0x00800000;
++    uint32_t imm4l = opcode & 0xf;
++    uint32_t imm4h = (opcode & 0xf00) >> 4;
++    return u ? (imm4h | imm4l) : -(imm4h | imm4l);
++  }
+   case R_ARM_THM_ALU_PREL_11_0: {
+     // Thumb2 ADR, which is an alias for a sub or add instruction with an
+     // unsigned immediate.
+diff --git a/lld/test/ELF/arm-adr-err-long.s b/lld/test/ELF/arm-adr-err-long.s
+new file mode 100644
+index 000000000000..a4aa86b6eb96
+--- /dev/null
++++ b/lld/test/ELF/arm-adr-err-long.s
+@@ -0,0 +1,57 @@
++// REQUIRES: arm
++// RUN: split-file %s %t
++// RUN: llvm-mc --triple=armv7a-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %t/asm
++// RUN: not ld.lld --script %t/lds %t.o -o /dev/null 2>&1 | FileCheck %s
++
++//--- lds
++SECTIONS {
++    .text.0 0x0100000 : AT(0x0100000) { *(.text.0) }
++    .text.1 0x0800000 : AT(0x0800000) { *(.text.1) }
++    .text.2 0xf0f0000 : AT(0xf0f0000) { *(.text.2) }
++}
++
++//--- asm
++/// This is a variant of arm-adr-long.s with some _NC relocs changed into their
++/// checking counterparts, to verify that out-of-range references are caught.
++
++ .section .text.0, "ax", %progbits
++dat1:
++ .word 0
++
++ .section .text.1, "ax", %progbits
++ .global _start
++ .type _start, %function
++_start:
++ .inst 0xe24f0008 // sub r0, pc, #8
++ .inst 0xe2400004 // sub r0, r0, #4
++ .reloc 0, R_ARM_ALU_PC_G0, dat1
++// CHECK: {{.*}}.s.tmp.o:(.text.1+0x0): unencodeable immediate 7340040 for relocation R_ARM_ALU_PC_G0
++ .reloc 4, R_ARM_ALU_PC_G1, dat1
++
++ .inst 0xe24f1008 // sub r1, pc, #8
++ .inst 0xe2411004 // sub r1, r1, #4
++ .inst 0xe2411000 // sub r1, r1, #0
++ .reloc 8, R_ARM_ALU_PC_G0_NC, dat2
++ .reloc 12, R_ARM_ALU_PC_G1, dat2
++// CHECK: {{.*}}.s.tmp.o:(.text.1+0xc): unencodeable immediate 244252656 for relocation R_ARM_ALU_PC_G1
++ .reloc 16, R_ARM_ALU_PC_G2, dat2
++
++ .inst 0xe24f0008 // sub r0, pc, #8
++ .inst 0xe2400004 // sub r0, r0, #4
++ .inst 0xe2400000 // sub r0, r0, #0
++ .reloc 20, R_ARM_ALU_PC_G0, dat1
++// CHECK: {{.*}}.s.tmp.o:(.text.1+0x14): unencodeable immediate 7340060 for relocation R_ARM_ALU_PC_G0
++ .reloc 24, R_ARM_ALU_PC_G1, dat1
++ .reloc 28, R_ARM_ALU_PC_G2, dat1
++
++ .inst 0xe24f0008 // sub r0, pc, #8
++ .inst 0xe2400004 // sub r0, r0, #4
++ .inst 0xe1c000d0 // ldrd r0, r1, [r0, #0]
++ .reloc 32, R_ARM_ALU_PC_G0_NC, dat2
++ .reloc 36, R_ARM_ALU_PC_G1_NC, dat2
++// CHECK: {{.*}}.s.tmp.o:(.text.1+0x28): relocation R_ARM_LDRS_PC_G2 out of range: 4056 is not in [0, 255]
++ .reloc 40, R_ARM_LDRS_PC_G2, dat2
++
++ .section .text.2, "ax", %progbits
++dat2:
++ .word 0
+diff --git a/lld/test/ELF/arm-adr-err.s b/lld/test/ELF/arm-adr-err.s
+index cd60cc6b845b..be1305e7b010 100644
+--- a/lld/test/ELF/arm-adr-err.s
++++ b/lld/test/ELF/arm-adr-err.s
+@@ -23,6 +23,12 @@ _start:
+  .inst 0xe24f1008
+  .reloc 4, R_ARM_ALU_PC_G0, unaligned
+ 
++ .balign 512
++/// ldrd r0, r1, _start
++// CHECK: {{.*}}.s.tmp.o:(.os1+0x200): relocation R_ARM_LDRS_PC_G0 out of range: 512 is not in [0, 255]; references _start
++ .reloc ., R_ARM_LDRS_PC_G0, _start
++ .inst 0xe14f00d0
++
+  .section .os2, "ax", %progbits
+  .balign 1024
+  .thumb_func
+diff --git a/lld/test/ELF/arm-adr-long.s b/lld/test/ELF/arm-adr-long.s
+index 9ce7fea3f8ec..60ef789cf7b7 100644
+--- a/lld/test/ELF/arm-adr-long.s
++++ b/lld/test/ELF/arm-adr-long.s
+@@ -1,15 +1,20 @@
+ // REQUIRES: arm
+-// RUN: llvm-mc --triple=armv7a-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %s
+-// RUN: echo "SECTIONS { \
+-// RUN:                 .text.0 0x10000000 : AT(0x10000000) { *(.text.0) } \
+-// RUN:                 .text.1 0x80000000 : AT(0x80000000) { *(.text.1) } \
+-// RUN:                 .text.2 0xf0000010 : AT(0xf0000010) { *(.text.2) } \
+-// RUN:               } " > %t.script
+-// RUN: ld.lld --script %t.script %t.o -o %t
+-// RUN: llvm-objdump -d --no-show-raw-insn --triple=armv7a-none-eabi %t | FileCheck %s
+-
+-/// Test the long range encoding of R_ARM_ALU_PC_G0. We can encode an 8-bit
++// RUN: split-file %s %t
++// RUN: llvm-mc --triple=armv7a-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %t/asm
++// RUN: ld.lld --script %t/lds %t.o -o %t2
++// RUN: llvm-objdump -d --no-show-raw-insn --triple=armv7a-none-eabi %t2 | FileCheck %s
++
++/// Test the long range encoding of R_ARM_ALU_PC_Gx sequences. We can encode an 8-bit
+ /// immediate rotated right by an even 4-bit field.
++
++//--- lds
++SECTIONS {
++    .text.0 0x0100000 : AT(0x0100000) { *(.text.0) }
++    .text.1 0x0800000 : AT(0x0800000) { *(.text.1) }
++    .text.2 0xf0f0000 : AT(0xf0f0000) { *(.text.2) }
++}
++
++//--- asm
+  .section .text.0, "ax", %progbits
+ dat1:
+  .word 0
+@@ -18,25 +23,81 @@ dat1:
+  .global _start
+  .type _start, %function
+ _start:
+-/// adr.w r0, dat1
+- .inst 0xe24f0008
+- .reloc 0, R_ARM_ALU_PC_G0, dat1
+-/// adr.w r1, dat2
+- .inst 0xe24f1008
+- .reloc 4, R_ARM_ALU_PC_G0, dat2
++ .inst 0xe24f0008 // sub r0, pc, #8
++ .inst 0xe2400004 // sub r0, r0, #4
++ .reloc 0, R_ARM_ALU_PC_G0_NC, dat1
++ .reloc 4, R_ARM_ALU_PC_G1, dat1
++
++ .inst 0xe24f1008 // sub r1, pc, #8
++ .inst 0xe2411004 // sub r1, r1, #4
++ .inst 0xe2411000 // sub r1, r1, #0
++ .reloc 8, R_ARM_ALU_PC_G0_NC, dat2
++ .reloc 12, R_ARM_ALU_PC_G1_NC, dat2
++ .reloc 16, R_ARM_ALU_PC_G2, dat2
++
++ .inst 0xe24f0008 // sub r0, pc, #8
++ .inst 0xe2400004 // sub r0, r0, #4
++ .inst 0xe2400000 // sub r0, r0, #0
++ .reloc 20, R_ARM_ALU_PC_G0_NC, dat1
++ .reloc 24, R_ARM_ALU_PC_G1_NC, dat1
++ .reloc 28, R_ARM_ALU_PC_G2, dat1
++
++ .inst 0xe24f0008 // sub r0, pc, #8
++ .inst 0xe2400004 // sub r0, r0, #4
++ .inst 0xe5900000 // ldr r0, [r0, #0]
++ .reloc 32, R_ARM_ALU_PC_G0_NC, dat2
++ .reloc 36, R_ARM_ALU_PC_G1_NC, dat2
++ .reloc 40, R_ARM_LDR_PC_G2, dat2
++
++ .inst 0xe24f0008 // sub r0, pc, #8
++ .inst 0xe5100004 // ldr r0, [r0, #-4]
++ .reloc 44, R_ARM_ALU_PC_G0_NC, dat1
++ .reloc 48, R_ARM_LDR_PC_G1, dat1
++
++ .inst 0xe24f0008 // sub r0, pc, #8
++ .inst 0xe2400004 // sub r0, r0, #4
++ .inst 0xe5900000 // ldr r0, [r0, #0]
++ .reloc 52, R_ARM_ALU_PC_G0_NC, dat1
++ .reloc 56, R_ARM_ALU_PC_G1_NC, dat1
++ .reloc 60, R_ARM_LDR_PC_G2, dat1
++
++ .inst 0xe24f0008 // sub r0, pc, #8
++ .inst 0xe14000d4 // ldrd r0, [r0, #-4]
++ .reloc 64, R_ARM_ALU_PC_G0_NC, dat1
++ .reloc 68, R_ARM_LDRS_PC_G1, dat1
+ 
+  .section .text.2, "ax", %progbits
+ dat2:
+  .word 0
+ 
+-// CHECK:      10000000 <dat1>:
+-// CHECK-NEXT: 10000000: andeq   r0, r0, r0
++// CHECK:      00100000 <dat1>:
++// CHECK-NEXT:   100000: andeq   r0, r0, r0
++
++// CHECK:      00800000 <_start>:
++// CHECK-NEXT:   800000: sub     r0, pc, #112, #16
++// CHECK-NEXT:   800004: sub     r0, r0, #8
++
++// CHECK-NEXT:   800008: add     r1, pc, #232, #12
++// CHECK-NEXT:   80000c: add     r1, r1, #978944
++// CHECK-NEXT:   800010: add     r1, r1, #4080
++
++// CHECK-NEXT:   800014: sub     r0, pc, #112, #16
++// CHECK-NEXT:   800018: sub     r0, r0, #28
++// CHECK-NEXT:   80001c: sub     r0, r0, #0
++
++// CHECK-NEXT:   800020: add     r0, pc, #232, #12
++// CHECK-NEXT:   800024: add     r0, r0, #978944
++// CHECK-NEXT:   800028: ldr     r0, [r0, #4056]
++
++// CHECK-NEXT:   80002c: sub     r0, pc, #112, #16
++// CHECK-NEXT:   800030: ldr     r0, [r0, #-52]
++
++// CHECK-NEXT:   800034: sub     r0, pc, #112, #16
++// CHECK-NEXT:   800038: sub     r0, r0, #60
++// CHECK-NEXT:   80003c: ldr     r0, [r0, #-0]
+ 
+-// CHECK:      80000000 <_start>:
+-/// 0x80000000 + 0x8 - 0x70000008 = 0x10000000
+-// CHECK-NEXT: 80000000: sub     r0, pc, #1879048200
+-/// 0x80000004 + 0x8 + 0x70000004 = 0xf0000010
+-// CHECK-NEXT: 80000004: add     r1, pc, #1879048196
++// CHECK-NEXT:   800040: sub     r0, pc, #112, #16
++// CHECK-NEXT:   800044: ldrd    r0, r1, [r0, #-72]
+ 
+-// CHECK:      f0000010 <dat2>:
+-// CHECK-NEXT: f0000010: andeq   r0, r0, r0
++// CHECK:      0f0f0000 <dat2>:
++// CHECK-NEXT:  f0f0000: andeq   r0, r0, r0
+diff --git a/lld/test/ELF/arm-adr.s b/lld/test/ELF/arm-adr.s
+index 1fb8505f71f5..05e8cc2f92db 100644
+--- a/lld/test/ELF/arm-adr.s
++++ b/lld/test/ELF/arm-adr.s
+@@ -87,9 +87,9 @@ afunc:
+ /// 0x20804 + 0x8 - 0x3f8 = 0x11414 = dat2
+ // CHECK-NEXT: 20804: sub     r0, pc, #1016
+ /// 0x20808 + 0x8 + 0x400 = 0x11c10 = dat3
+-// CHECK-NEXT: 20808: add     r0, pc, #1024
++// CHECK-NEXT: 20808: add     r0, pc, #64, #28
+ /// 0x2080c + 0x8 + 0x400 = 0x11c14 = dat4
+-// CHECK-NEXT: 2080c: add     r0, pc, #1024
++// CHECK-NEXT: 2080c: add     r0, pc, #64, #28
+ 
+ // CHECK:      00020c10 <dat3>:
+ // CHECK-NEXT: 20c10: andeq   r0, r0, r0
+-- 
+2.34.1
+