[llvm] 5bf4f2a - [SystemZ] Add range checks for PC-relative fixups.

Jonas Paulsson via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 7 10:14:44 PST 2021


Author: Jonas Paulsson
Date: 2021-12-07T12:13:03-06:00
New Revision: 5bf4f2acb8d658904304460a937f24a071d9c9a7

URL: https://github.com/llvm/llvm-project/commit/5bf4f2acb8d658904304460a937f24a071d9c9a7
DIFF: https://github.com/llvm/llvm-project/commit/5bf4f2acb8d658904304460a937f24a071d9c9a7.diff

LOG: [SystemZ] Add range checks for PC-relative fixups.

The AsmParser checks the range of a PC-relative operand, but only if it is
immediate.

This patch adds range checks for operands in applyFixup(), at which point the
offset to a label is known.

The diagnostic message for an operand that is out of range is explicit (with
given value and min/max limits). This is now also done for displacement
fixups.

Review: Ulrich Weigand

Differential Revision: https://reviews.llvm.org/D114194

Added: 
    llvm/test/MC/SystemZ/fixups-out-of-range-01.s
    llvm/test/MC/SystemZ/fixups-out-of-range-02.s

Modified: 
    llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
    llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp

Removed: 
    llvm/test/MC/SystemZ/fixups-out-of-range.s


################################################################################
diff  --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
index 0f5e0b9672a97..538380263c3cb 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
@@ -28,25 +28,43 @@ static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value,
   if (Kind < FirstTargetFixupKind)
     return Value;
 
+  auto checkFixupInRange = [&](int64_t Min, int64_t Max) -> bool {
+    int64_t SVal = int64_t(Value);
+    if (SVal < Min || SVal > Max) {
+      Ctx.reportError(Fixup.getLoc(), "operand out of range (" + Twine(SVal) +
+                                          " not between " + Twine(Min) +
+                                          " and " + Twine(Max) + ")");
+      return false;
+    }
+    return true;
+  };
+
+  auto handlePCRelFixupValue = [&](unsigned W) -> uint64_t {
+    if (Value % 2 != 0)
+      Ctx.reportError(Fixup.getLoc(), "Non-even PC relative offset.");
+    if (!checkFixupInRange(minIntN(W) * 2, maxIntN(W) * 2))
+      return 0;
+    return (int64_t)Value / 2;
+  };
+
   switch (unsigned(Kind)) {
   case SystemZ::FK_390_PC12DBL:
+    return handlePCRelFixupValue(12);
   case SystemZ::FK_390_PC16DBL:
+    return handlePCRelFixupValue(16);
   case SystemZ::FK_390_PC24DBL:
+    return handlePCRelFixupValue(24);
   case SystemZ::FK_390_PC32DBL:
-    return (int64_t)Value / 2;
+    return handlePCRelFixupValue(32);
 
   case SystemZ::FK_390_12:
-    if (!isUInt<12>(Value)) {
-      Ctx.reportError(Fixup.getLoc(), "displacement exceeds uint12");
+    if (!checkFixupInRange(0, maxUIntN(12)))
       return 0;
-    }
     return Value;
 
   case SystemZ::FK_390_20: {
-    if (!isInt<20>(Value)) {
-      Ctx.reportError(Fixup.getLoc(), "displacement exceeds int20");
+    if (!checkFixupInRange(minIntN(20), maxIntN(20)))
       return 0;
-    }
     // The high byte of a 20 bit displacement value comes first.
     uint64_t DLo = Value & 0xfff;
     uint64_t DHi = (Value >> 12) & 0xff;

diff  --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp
index e280e4aaf3d82..c83796b8579b9 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp
@@ -197,7 +197,8 @@ getDispOpValue(const MCInst &MI, unsigned OpNum,
     // All instructions follow the pattern where the first displacement has a
     // 2 bytes offset, and the second one 4 bytes.
     unsigned ByteOffs = Fixups.size() == 0 ? 2 : 4;
-    Fixups.push_back(MCFixup::create(ByteOffs, MO.getExpr(), (MCFixupKind)Kind));
+    Fixups.push_back(MCFixup::create(ByteOffs, MO.getExpr(), (MCFixupKind)Kind,
+                                     MI.getLoc()));
     assert(Fixups.size() <= 2 && "More than two memory operands in MI?");
     return 0;
   }
@@ -296,6 +297,7 @@ SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned OpNum,
                                        SmallVectorImpl<MCFixup> &Fixups,
                                        unsigned Kind, int64_t Offset,
                                        bool AllowTLS) const {
+  SMLoc Loc = MI.getLoc();
   const MCOperand &MO = MI.getOperand(OpNum);
   const MCExpr *Expr;
   if (MO.isImm())
@@ -311,13 +313,13 @@ SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned OpNum,
       Expr = MCBinaryExpr::createAdd(Expr, OffsetExpr, Ctx);
     }
   }
-  Fixups.push_back(MCFixup::create(Offset, Expr, (MCFixupKind)Kind));
+  Fixups.push_back(MCFixup::create(Offset, Expr, (MCFixupKind)Kind, Loc));
 
   // Output the fixup for the TLS marker if present.
   if (AllowTLS && OpNum + 1 < MI.getNumOperands()) {
     const MCOperand &MOTLS = MI.getOperand(OpNum + 1);
-    Fixups.push_back(MCFixup::create(0, MOTLS.getExpr(),
-                                     (MCFixupKind)SystemZ::FK_390_TLS_CALL));
+    Fixups.push_back(MCFixup::create(
+        0, MOTLS.getExpr(), (MCFixupKind)SystemZ::FK_390_TLS_CALL, Loc));
   }
   return 0;
 }

diff  --git a/llvm/test/MC/SystemZ/fixups-out-of-range.s b/llvm/test/MC/SystemZ/fixups-out-of-range-01.s
similarity index 56%
rename from llvm/test/MC/SystemZ/fixups-out-of-range.s
rename to llvm/test/MC/SystemZ/fixups-out-of-range-01.s
index 7715da2e4736d..8c189b0a3e7d1 100644
--- a/llvm/test/MC/SystemZ/fixups-out-of-range.s
+++ b/llvm/test/MC/SystemZ/fixups-out-of-range-01.s
@@ -2,10 +2,14 @@
 
 	.text
 
-# CHECK: error: displacement exceeds uint12
+# CHECK:      error: operand out of range (4096 not between 0 and 4095)
+# CHECK-NEXT:        la %r1, b-a(%r1)
+# CHECK-NEXT:        ^
 	la    %r1, b-a(%r1)
 
-# CHECK: error: displacement exceeds int20
+# CHECK-NEXT: error: operand out of range (524288 not between -524288 and 524287)
+# CHECK-NEXT:        lay   %r1, d-c(%r1)
+# CHECK-NEXT:        ^
         lay   %r1, d-c(%r1)
 
 # CHECK-NOT: error

diff  --git a/llvm/test/MC/SystemZ/fixups-out-of-range-02.s b/llvm/test/MC/SystemZ/fixups-out-of-range-02.s
new file mode 100644
index 0000000000000..648f06dbf8130
--- /dev/null
+++ b/llvm/test/MC/SystemZ/fixups-out-of-range-02.s
@@ -0,0 +1,60 @@
+# RUN: not llvm-mc -triple s390x-unknown-unknown -filetype=obj -mcpu=zEC12 \
+# RUN:   -o /dev/null %s 2>&1 | FileCheck %s
+
+	.text
+
+# Test fixup ranges, which are encoded as half-words.
+
+# 12-bit
+# CHECK:      error: operand out of range (4096 not between -4096 and 4094)
+# CHECK-NEXT:        bprp 0, .Lab1, 0
+# CHECK-NEXT:        ^
+# CHECK-NEXT: error: operand out of range (-4098 not between -4096 and 4094)
+# CHECK-NEXT:        bprp 0, .Lab0, 0
+# CHECK-NEXT:        ^
+        bprp 0, .Lab1, 0
+.Lab0:
+        bprp 0, .Lab1, 0
+        .space 4084
+.Lab1:
+	nopr
+        bprp 0, .Lab0, 0
+        bprp 0, .Lab0, 0
+
+# 24-bit
+# CHECK-NEXT: error: operand out of range (16777220 not between -16777216 and 16777214)
+# CHECK-NEXT:        bprp 0, 0, .Lab3
+# CHECK-NEXT:        ^
+# CHECK-NEXT: error: operand out of range (-16777222 not between -16777216 and 16777214)
+# CHECK-NEXT:        bprp 0, 0, .Lab2
+# CHECK-NEXT:        ^
+        bprp 0, 0, .Lab3
+.Lab2:
+        bprp 0, 0, .Lab3
+        .space 16777208
+.Lab3:
+	nopr
+        bprp 0, 0, .Lab2
+        bprp 0, 0, .Lab2
+
+# 16-bit
+# CHECK-NEXT: error: operand out of range (65540 not between -65536 and 65534)
+# CHECK-NEXT:        cij %r1, 0, 0, .Lab5
+# CHECK-NEXT:        ^
+# CHECK-NEXT: error: operand out of range (-65542 not between -65536 and 65534)
+# CHECK-NEXT:        cij %r1, 0, 0, .Lab4
+# CHECK-NEXT:        ^
+        cij %r1, 0, 0, .Lab5
+.Lab4:
+        cij %r1, 0, 0, .Lab5
+        .space 65528
+.Lab5:
+	nopr
+        cij %r1, 0, 0, .Lab4
+        cij %r1, 0, 0, .Lab4
+
+# 32-bit
+# Unfortunately there is no support for offsets greater than 32 bits, so we have
+# to for now assume they are in range.
+
+# CHECK-NOT: error


        


More information about the llvm-commits mailing list