[llvm] 580310f - [SystemZ] Improve handling of huge PC relative immediate offsets.

Jonas Paulsson via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 4 01:38:54 PST 2019


Author: Jonas Paulsson
Date: 2019-11-04T10:38:18+01:00
New Revision: 580310ff0c57a62edd0c07aacfa4969809649444

URL: https://github.com/llvm/llvm-project/commit/580310ff0c57a62edd0c07aacfa4969809649444
DIFF: https://github.com/llvm/llvm-project/commit/580310ff0c57a62edd0c07aacfa4969809649444.diff

LOG: [SystemZ]  Improve handling of huge PC relative immediate offsets.

Demand that an immediate offset to a PC relative address fits in 32 bits, or
else load it into a register and perform a separate add.

Verify in the assembler that such immediate offsets fit the bitwidth.

Even though the final address of a Load Address Relative Long may fit in 32
bits even with a >32 bit offset (depending on where the symbol lives relative
to PC), the GNU toolchain demands the offset by itself to be in range. This
patch adapts the same behavior for llvm.

Review: Ulrich Weigand
https://reviews.llvm.org/D69749

Added: 
    llvm/test/CodeGen/SystemZ/la-05.ll

Modified: 
    llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
    llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
    llvm/test/MC/SystemZ/insn-bad.s

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
index 93c4ce4b5ccc..b58d20fc49ba 100644
--- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
+++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
@@ -1304,14 +1304,23 @@ SystemZAsmParser::parsePCRel(OperandVector &Operands, int64_t MinVal,
   if (getParser().parseExpression(Expr))
     return MatchOperand_NoMatch;
 
+  auto isOutOfRangeConstant = [&](const MCExpr *E) -> bool {
+    if (auto *CE = dyn_cast<MCConstantExpr>(E)) {
+      int64_t Value = CE->getValue();
+      if ((Value & 1) || Value < MinVal || Value > MaxVal)
+        return true;
+    }
+    return false;
+  };
+
   // For consistency with the GNU assembler, treat immediates as offsets
   // from ".".
   if (auto *CE = dyn_cast<MCConstantExpr>(Expr)) {
-    int64_t Value = CE->getValue();
-    if ((Value & 1) || Value < MinVal || Value > MaxVal) {
+    if (isOutOfRangeConstant(CE)) {
       Error(StartLoc, "offset out of range");
       return MatchOperand_ParseFail;
     }
+    int64_t Value = CE->getValue();
     MCSymbol *Sym = Ctx.createTempSymbol();
     Out.EmitLabel(Sym);
     const MCExpr *Base = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None,
@@ -1319,6 +1328,15 @@ SystemZAsmParser::parsePCRel(OperandVector &Operands, int64_t MinVal,
     Expr = Value == 0 ? Base : MCBinaryExpr::createAdd(Base, Expr, Ctx);
   }
 
+  // For consistency with the GNU assembler, conservatively assume that a
+  // constant offset must by itself be within the given size range.
+  if (const auto *BE = dyn_cast<MCBinaryExpr>(Expr))
+    if (isOutOfRangeConstant(BE->getLHS()) ||
+        isOutOfRangeConstant(BE->getRHS())) {
+      Error(StartLoc, "offset out of range");
+      return MatchOperand_ParseFail;
+    }
+
   // Optionally match :tls_gdcall: or :tls_ldcall: followed by a TLS symbol.
   const MCExpr *Sym = nullptr;
   if (AllowTLS && getLexer().is(AsmToken::Colon)) {

diff  --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index e0ca9da93561..8e71d8342562 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -2828,17 +2828,26 @@ SDValue SystemZTargetLowering::lowerGlobalAddress(GlobalAddressSDNode *Node,
 
   SDValue Result;
   if (Subtarget.isPC32DBLSymbol(GV, CM)) {
-    // Assign anchors at 1<<12 byte boundaries.
-    uint64_t Anchor = Offset & ~uint64_t(0xfff);
-    Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, Anchor);
-    Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
-
-    // The offset can be folded into the address if it is aligned to a halfword.
-    Offset -= Anchor;
-    if (Offset != 0 && (Offset & 1) == 0) {
-      SDValue Full = DAG.getTargetGlobalAddress(GV, DL, PtrVT, Anchor + Offset);
-      Result = DAG.getNode(SystemZISD::PCREL_OFFSET, DL, PtrVT, Full, Result);
-      Offset = 0;
+    if (isInt<32>(Offset)) {
+      // Assign anchors at 1<<12 byte boundaries.
+      uint64_t Anchor = Offset & ~uint64_t(0xfff);
+      Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, Anchor);
+      Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
+
+      // The offset can be folded into the address if it is aligned to a
+      // halfword.
+      Offset -= Anchor;
+      if (Offset != 0 && (Offset & 1) == 0) {
+        SDValue Full =
+          DAG.getTargetGlobalAddress(GV, DL, PtrVT, Anchor + Offset);
+        Result = DAG.getNode(SystemZISD::PCREL_OFFSET, DL, PtrVT, Full, Result);
+        Offset = 0;
+      }
+    } else {
+      // Conservatively load a constant offset greater than 32 bits into a
+      // register below.
+      Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT);
+      Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
     }
   } else {
     Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, SystemZII::MO_GOT);

diff  --git a/llvm/test/CodeGen/SystemZ/la-05.ll b/llvm/test/CodeGen/SystemZ/la-05.ll
new file mode 100644
index 000000000000..27d7d91e6c8a
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/la-05.ll
@@ -0,0 +1,31 @@
+; Test that a huge address offset is loaded into a register and then added
+; separately.
+;
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+
+ at a = common dso_local global i32 0, align 4
+
+define i64 @f1() {
+; CHECK-LABEL: f1:
+; CHECK: llihl   %r0, 829
+; CHECK: oilf    %r0, 4294966308
+; CHECK: larl    %r2, a
+; CHECK: agr     %r2, %r0
+; CHECK: br      %r14
+  ret i64 add (i64 ptrtoint (i32* @a to i64), i64 3564822854692)
+}
+
+define signext i32 @f2() {
+; CHECK-LABEL: f2:
+; CHECK: llihl   %r0, 829
+; CHECK: oilf    %r0, 4294966308
+; CHECK: larl    %r1, a
+; CHECK: agr     %r1, %r0
+; CHECK: lgf     %r2, 0(%r1)
+; CHECK: br      %r14
+entry:
+  %0 = load i32, i32* inttoptr (i64 add (i64 ptrtoint (i32* @a to i64),
+                                i64 3564822854692) to i32*)
+  ret i32 %0
+}
+

diff  --git a/llvm/test/MC/SystemZ/insn-bad.s b/llvm/test/MC/SystemZ/insn-bad.s
index 57c69f60361b..7dfbba743b60 100644
--- a/llvm/test/MC/SystemZ/insn-bad.s
+++ b/llvm/test/MC/SystemZ/insn-bad.s
@@ -3104,11 +3104,14 @@
 #CHECK: larl	%r0, 1
 #CHECK: error: offset out of range
 #CHECK: larl	%r0, 0x100000000
+#CHECK: error: offset out of range
+#CHECK: larl	%r1, __unnamed_1+3564822854692
 
 	larl	%r0, -0x1000000002
 	larl	%r0, -1
 	larl	%r0, 1
 	larl	%r0, 0x100000000
+	larl	%r1, __unnamed_1+3564822854692
 
 #CHECK: error: invalid use of indexed addressing
 #CHECK: lasp	160(%r1,%r15),160(%r15)
@@ -3840,11 +3843,14 @@
 #CHECK: lrl	%r0, 1
 #CHECK: error: offset out of range
 #CHECK: lrl	%r0, 0x100000000
+#CHECK: error: offset out of range
+#CHECK: lrl	%r1, __unnamed_1+3564822854692
 
 	lrl	%r0, -0x1000000002
 	lrl	%r0, -1
 	lrl	%r0, 1
 	lrl	%r0, 0x100000000
+	lrl	%r1, __unnamed_1+3564822854692
 
 #CHECK: error: invalid operand
 #CHECK: lrv	%r0, -524289


        


More information about the llvm-commits mailing list