diff --git a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp --- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -1590,9 +1590,11 @@ if (getParser().parseExpression(Expr)) return MatchOperand_NoMatch; - auto isOutOfRangeConstant = [&](const MCExpr *E) -> bool { + auto isOutOfRangeConstant = [&](const MCExpr *E, bool Negate) -> bool { if (auto *CE = dyn_cast(E)) { int64_t Value = CE->getValue(); + if (Negate) + Value = -Value; if ((Value & 1) || Value < MinVal || Value > MaxVal) return true; } @@ -1606,7 +1608,7 @@ Error(StartLoc, "Expected PC-relative expression"); return MatchOperand_ParseFail; } - if (isOutOfRangeConstant(CE)) { + if (isOutOfRangeConstant(CE, false)) { Error(StartLoc, "offset out of range"); return MatchOperand_ParseFail; } @@ -1621,8 +1623,9 @@ // 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(Expr)) - if (isOutOfRangeConstant(BE->getLHS()) || - isOutOfRangeConstant(BE->getRHS())) { + if (isOutOfRangeConstant(BE->getLHS(), false) || + isOutOfRangeConstant(BE->getRHS(), + BE->getOpcode() == MCBinaryExpr::Sub)) { Error(StartLoc, "offset out of range"); return MatchOperand_ParseFail; } diff --git a/llvm/test/MC/SystemZ/insn-bad.s b/llvm/test/MC/SystemZ/insn-bad.s --- a/llvm/test/MC/SystemZ/insn-bad.s +++ b/llvm/test/MC/SystemZ/insn-bad.s @@ -512,6 +512,8 @@ #CHECK: error: offset out of range #CHECK: brasl %r0, -0x1000000002 #CHECK: error: offset out of range +#CHECK: brasl %r0, .-0x1000000002 +#CHECK: error: offset out of range #CHECK: brasl %r0, -1 #CHECK: error: offset out of range #CHECK: brasl %r0, 1 @@ -520,6 +522,8 @@ #CHECK: error: offset out of range #CHECK: jasl %r0, -0x1000000002 #CHECK: error: offset out of range +#CHECK: jasl %r0, .-0x1000000002 +#CHECK: error: offset out of range #CHECK: jasl %r0, -1 #CHECK: error: offset out of range #CHECK: jasl %r0, 1 @@ -527,10 +531,12 @@ #CHECK: jasl %r0, 0x100000000 brasl %r0, -0x1000000002 + brasl %r0, .-0x1000000002 brasl %r0, -1 brasl %r0, 1 brasl %r0, 0x100000000 jasl %r0, -0x1000000002 + jasl %r0, .-0x1000000002 jasl %r0, -1 jasl %r0, 1 jasl %r0, 0x100000000 diff --git a/llvm/test/MC/SystemZ/insn-good.s b/llvm/test/MC/SystemZ/insn-good.s --- a/llvm/test/MC/SystemZ/insn-good.s +++ b/llvm/test/MC/SystemZ/insn-good.s @@ -1263,6 +1263,12 @@ #CHECK: fixup A - offset: 2, value: (.[[LAB]]-4294967296)+2, kind: FK_390_PC32DBL brasl %r0, -0x100000000 jasl %r0, -0x100000000 +#CHECK: brasl %r0, .[[LAB:L.*]]-4294967296 # encoding: [0xc0,0x05,A,A,A,A] +#CHECK: fixup A - offset: 2, value: (.[[LAB]]-4294967296)+2, kind: FK_390_PC32DBL +#CHECK: brasl %r0, .[[LAB:L.*]]-4294967296 # encoding: [0xc0,0x05,A,A,A,A] +#CHECK: fixup A - offset: 2, value: (.[[LAB]]-4294967296)+2, kind: FK_390_PC32DBL + brasl %r0, .-0x100000000 + jasl %r0, .-0x100000000 #CHECK: brasl %r0, .[[LAB:L.*]]-2 # encoding: [0xc0,0x05,A,A,A,A] #CHECK: fixup A - offset: 2, value: (.[[LAB]]-2)+2, kind: FK_390_PC32DBL #CHECK: brasl %r0, .[[LAB:L.*]]-2 # encoding: [0xc0,0x05,A,A,A,A]