From 4946802c5f406b050cbb1524d0fd03cf3fd7b0dc Mon Sep 17 00:00:00 2001 From: Simon Wallis Date: Mon, 14 Sep 2020 08:52:59 +0100 Subject: [PATCH] [ARM] Fix so immediates and pc relative checks Treating an SoImm offset as a multiple of 4 between -1020 and 1020 mis-handles the second of a pair of 16-bit constants where the offset is a multiple of 2 but not a multiple of 4, leading to an LLVM ERROR: out of range pc-relative fixup value For 32-bit and larger (64-bit) constants, continue to treat an SoImm offset as a multiple of 4 between -1020 and 1020. For smaller (16-bit) constants, treat an SoImm offset as a multiple of 1 between -255 and 255. Reviewed By: efriedma Differential Revision: https://reviews.llvm.org/D86949 --- llvm/lib/Target/ARM/ARMConstantIslandPass.cpp | 28 ++++++---- .../CodeGen/ARM/constant-island-SOImm-limit16.mir | 62 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 llvm/test/CodeGen/ARM/constant-island-SOImm-limit16.mir diff --git a/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp b/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp index 204e57f..86da5a2 100644 --- a/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp +++ b/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp @@ -775,15 +775,25 @@ initializeFunctionInfo(const std::vector &CPEMIs) { // Taking the address of a CP entry. case ARM::LEApcrel: - case ARM::LEApcrelJT: - // This takes a SoImm, which is 8 bit immediate rotated. We'll - // pretend the maximum offset is 255 * 4. Since each instruction - // 4 byte wide, this is always correct. We'll check for other - // displacements that fits in a SoImm as well. - Bits = 8; - Scale = 4; - NegOk = true; - IsSoImm = true; + case ARM::LEApcrelJT: { + // This takes a SoImm, which is 8 bit immediate rotated. We'll + // pretend the maximum offset is 255 * 4. Since each instruction + // 4 byte wide, this is always correct. We'll check for other + // displacements that fits in a SoImm as well. + Bits = 8; + NegOk = true; + IsSoImm = true; + unsigned CPI = I.getOperand(op).getIndex(); + MachineInstr *CPEMI = CPEMIs[CPI]; + const Align CPEAlign = getCPEAlign(CPEMI); + const unsigned LogCPEAlign = Log2(CPEAlign); + if (LogCPEAlign >= 2) + Scale = 4; + else + // For constants with less than 4-byte alignment, + // we'll pretend the maximum offset is 255 * 1. + Scale = 1; + } break; case ARM::t2LEApcrel: case ARM::t2LEApcrelJT: diff --git a/llvm/test/CodeGen/ARM/constant-island-SOImm-limit16.mir b/llvm/test/CodeGen/ARM/constant-island-SOImm-limit16.mir new file mode 100644 index 0000000..223a3b0 --- /dev/null +++ b/llvm/test/CodeGen/ARM/constant-island-SOImm-limit16.mir @@ -0,0 +1,62 @@ +# RUN: sed -e "s/SPACEBYTES/100/g" %s | sed -e "s/OFFSET/116/g" > %t.mir +# RUN: llc %t.mir --filetype=obj -start-before=arm-cp-islands -o - | \ +# RUN: llvm-objdump --arch=armv8a --disassemble - | FileCheck %t.mir + +# RUN: sed -e "s/SPACEBYTES/400/g" %s | sed -e "s/OFFSET/12/g" > %t.mir +# RUN: llc %t.mir --filetype=obj -start-before=arm-cp-islands -o - | \ +# RUN: llvm-objdump --arch=armv8a --disassemble - | FileCheck %t.mir + +# RUN: sed -e "s/SPACEBYTES/800/g" %s | sed -e "s/OFFSET/12/g" > %t.mir +# RUN: llc %t.mir --filetype=obj -start-before=arm-cp-islands -o - | \ +# RUN: llvm-objdump --arch=armv8a --disassemble - | FileCheck %t.mir + +--- | + target triple = "armv8.2a-arm-none-eabi" + + define dso_local i32 @main() #0 { ret i32 0 } + + attributes #0 = { "frame-pointer"="all" } !4 = !{i32 210} + +... +--- + +name: main +alignment: 4 +tracksRegLiveness: true +constants: + +- + id: 0 + value: half 0xH5440 + alignment: 2 +- + id: 1 + value: half 0xH5441 + alignment: 2 + +machineFunctionInfo: {} +body: | + + bb.0 (%ir-block.0): + liveins: $lr + + $sp = frame-setup STMDB_UPD $sp, 14, $noreg, killed $r11, killed $lr + $r11 = frame-setup MOVr killed $sp, 14, $noreg, $noreg + $sp = frame-setup SUBri killed $sp, 80, 14, $noreg, $noreg + + ; Test handling of 16-bit constant pool entries. + ; 2 consecutive entries: 1 is 4-byte aligned, 1 is not 4-byte aligned. + + renamable $r1 = LEApcrel %const.0, 14, $noreg + renamable $r1 = LDRH killed renamable $r1, $noreg, 0, 14, $noreg :: (load 2 from constant-pool) + renamable $r1 = LEApcrel %const.1, 14, $noreg + renamable $r1 = LDRH killed renamable $r1, $noreg, 0, 14, $noreg :: (load 2 from constant-pool) + + renamable $r0 = SPACE SPACEBYTES, undef renamable $r0 + + $sp = frame-destroy MOVr $r11, 14, $noreg, $noreg + $sp = frame-destroy LDMIA_RET $sp, 14, $noreg, def $r11, def $pc, implicit killed $r0 + + # CHECK: add r1, pc, #OFFSET +--- +... -- 2.7.4