[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