This is an archive of the discontinued LLVM Phabricator instance.

[SystemZ] Add range checks for PC-relative fixups
ClosedPublic

Authored by jonpa on Nov 18 2021, 1:45 PM.

Details

Summary

The AsmParser checks for the range of a pc-relative immediate operand, but when that operand is a specified label there was previously no such check performed.

This patch adds checks for these operands in applyFixup(), at which point the actual offset is known.

Diff Detail

Event Timeline

jonpa created this revision.Nov 18 2021, 1:45 PM
jonpa requested review of this revision.Nov 18 2021, 1:45 PM
Herald added a project: Restricted Project. · View Herald TranscriptNov 18 2021, 1:45 PM
jonpa added a comment.Nov 18 2021, 1:46 PM

Not sure what to do with the testing: should we do something similar as a 'Large' folder as is already done for the branch relaxation tests?

So far only one test - for the 12-bit fixup.

Not sure what to do with the testing: should we do something similar as a 'Large' folder as is already done for the branch relaxation tests?

The 'Large' folder is only separate because files in there take a long time to build, and therefore shouldn't be executed in each normal "make check".

I think it should be straightforward to create tests with large distances between symbols (e.g. using .rep) that don't take any longer than usual unit tests, so they don't need to be treated specially.

jonpa updated this revision to Diff 389064.Nov 22 2021, 4:23 PM

I ran into a bit of problems trying to test the 32-bit PCRel range. Since this is encoded as halfwords, 32 bits will actually overflow, and unfortunately common-code has currently some 32-bit types for offsets. I could for now make the test pass with some common-code changes, but the (SmallVector) Contents vector should probably also be fixed then to have a 64-bit template type. This is the vector that holds the encoded bytes.

The 32-bit PCRel test kind of exploded in compile time (~10 mins). It seems the main part of this is in the table-generated SystemZAsmParser::MatchInstructionImp. The 24-bit test takes 2-3 seconds.

Not sure if/how we should proceed with the 32-bit case...

GAS is faster, but seems to print broken diagnostics with the big test case ('between 0 and -2' is weird):

time as ./llvm/test/MC/SystemZ/fixups-out-of-range-02.s -o out.o -march=zEC12
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s: Assembler messages:
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s:15: Error: operand out of range (4096 not between -4096 and 4094)
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s:22: Error: operand out of range (-4098 not between -4096 and 4094)
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s:31: Error: operand out of range (16777220 not between -16777216 and 16777214)
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s:38: Error: operand out of range (-16777222 not between -16777216 and 16777214)
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s:47: Error: operand out of range (65540 not between -65536 and 65534)
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s:54: Error: operand out of range (-65542 not between -65536 and 65534)
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s:63: Error: operand out of range (4294967300 not between 0 and -2)
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s:63: Error: value of 4294967300 too large for field of 4 bytes at 16846898
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s:70: Error: operand out of range (-4294967302 not between 0 and -2)
./llvm/test/MC/SystemZ/fixups-out-of-range-02.s:70: Error: value of -4294967302 too large for field of 4 bytes at 4311814206

real	2m32.105s
user	2m23.702s
sys	0m8.365s
jonpa updated this revision to Diff 389289.Nov 23 2021, 1:05 PM

.space directive works better - compile time issue eliminated :-)

handlePCRelFixupValue(32) still in the patch, but the test for it removed in fixups-out-of-range-02.s. I think it will catch some positive out-of-range values, but not any negative ones (out of range). In the future if 64-bit offsets become supported, this should then work as expected, hopefully.

I have now made sure the SMLoc is passed to all created MCFixups in SystemZMCCodeEmitter.cpp. This improves the diagnostic message (line number and instruction printed).

I copied the diagnostic message from GAS in fixups-out-of-range-02.s, but have not done so for the displacements (fixups-out-of-range-01.s). I am not quite sure what is best: should the displacements also get the fuller diagnostic, or is it better with a simplistic message?

The code changes LGTM.

I copied the diagnostic message from GAS in fixups-out-of-range-02.s, but have not done so for the displacements (fixups-out-of-range-01.s). I am not quite sure what is best: should the displacements also get the fuller diagnostic, or is it better with a simplistic message?

I think it's better to be explicit, so the message for displacements should mirror the one here.

As to the test, I don't really like the checking for explicit line:column numbers - this will make those test awkward to change in the future. Isn't it enough to identify a particular line by the label number used in it (assuming you make label uses unique, which can be easily done by sometimes putting two labels on the same location).

jonpa updated this revision to Diff 392207.Dec 6 2021, 3:27 PM

Updated per review.

I think it's better to be explicit, so the message for displacements should mirror the one here.

ok - updated patch and tests for this.

As to the test, I don't really like the checking for explicit line:column numbers - this will make those test awkward to change in the future. Isn't it enough to identify a particular line by the label number used in it (assuming you make label uses unique, which can be easily done by sometimes putting two labels on the same location).

Removed line numbers - I think that should work ok with the CHECK-NEXT:s and the final 'CHECK-NOT'...

One final comment inline, otherwise this LGTM. Thanks!

llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
43

Hmm, this scenario could be triggered by wrong assembler input (e.g. something simple like j .+1), so I don't think this should result in an assert (internal compiler error).

GCC/binutils currently seems to simply ignore that case (and round down), which also isn't ideal.

I think this really should be a user-level error message, not an assert.

This revision was not accepted when it landed; it landed in state Needs Review.Dec 7 2021, 10:14 AM
This revision was automatically updated to reflect the committed changes.
jonpa marked an inline comment as done.
jonpa added inline comments.Dec 7 2021, 10:14 AM
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
43

Changed this like:

   auto handlePCRelFixupValue = [&](unsigned W) -> uint64_t {
-    assert(Value % 2 == 0 && "Non-even PC relative offset.");
+    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;