Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[SystemZ] Implement .machine (push|pop) directives #137302

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 30, 2025

Conversation

dominik-steenken
Copy link
Contributor

@dominik-steenken dominik-steenken commented Apr 25, 2025

The .machine push and .machine pop directives were missing from the SystemZ Backend Asm Parser. This PR adds them, and expands the corresponding test to test proper operation.

Internally, this is modeled as a simple stack implemented on a SmallVector<StringRef>.

@llvmbot llvmbot added backend:SystemZ mc Machine (object) code labels Apr 25, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 25, 2025

@llvm/pr-subscribers-mc

@llvm/pr-subscribers-backend-systemz

Author: Dominik Steenken (dominik-steenken)

Changes

The .machine push and .machine pop directives were missing from the SystemZ Backend Asm Parser. This PR adds them, and expands the corresponding test to test proper operation.

Internally, this is modeled as a simple stack implemented on a SmallVector&lt;StringRef&gt;.

This implementation makes the assumption that, without any .machine directive, the "current" machine is undefined, rather than trying to derive it based on the host machine. Thus, in this implementation, any .machine push must be preceded by at least one .machine &lt;cpu&gt;. Otherwise, a parsing error is recognized.


Full diff: https://github.com/llvm/llvm-project/pull/137302.diff

3 Files Affected:

  • (modified) llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp (+32-6)
  • (modified) llvm/test/MC/SystemZ/machine-directive-invalid.s (+10-3)
  • (modified) llvm/test/MC/SystemZ/machine-directive.s (+2-1)
diff --git a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
index 6d9a7a73f72db..a7612ecfd954f 100644
--- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
+++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
@@ -410,6 +410,12 @@ class SystemZAsmParser : public MCTargetAsmParser {
 
 private:
   MCAsmParser &Parser;
+
+  // A vector to contain the stack of machine specs created by `.machine push`
+  SmallVector<StringRef> MachineStack;
+  // Specifies the current CPU
+  StringRef CurrentCPU = "";
+
   enum RegisterGroup {
     RegGR,
     RegFP,
@@ -1382,17 +1388,37 @@ bool SystemZAsmParser::parseDirectiveMachine(SMLoc L) {
       Parser.getTok().isNot(AsmToken::String))
     return TokError("unexpected token in '.machine' directive");
 
-  StringRef CPU = Parser.getTok().getIdentifier();
+  StringRef Id = Parser.getTok().getIdentifier();
+
+  // Parse push and pop directives first
+  StringRef CPU = "";
+  if (Id == "push") {
+    if (CurrentCPU.empty())
+      return TokError(
+          "push without preceding cpu spec in '.machine' directive");
+    MachineStack.push_back(CurrentCPU);
+  } else if (Id == "pop") {
+    if (MachineStack.empty())
+      return TokError("pop without corresponding push in '.machine' directive");
+    CPU = MachineStack.back();
+    MachineStack.pop_back();
+  } else {
+    CPU = Id;
+  }
+
   Parser.Lex();
   if (parseEOL())
     return true;
 
-  MCSubtargetInfo &STI = copySTI();
-  STI.setDefaultFeatures(CPU, /*TuneCPU*/ CPU, "");
-  setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
-
-  getTargetStreamer().emitMachine(CPU);
+  // check if we need to change cpu
+  if (!CPU.empty()) {
+    MCSubtargetInfo &STI = copySTI();
+    STI.setDefaultFeatures(CPU, /*TuneCPU*/ CPU, "");
+    setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+    CurrentCPU = CPU;
 
+    getTargetStreamer().emitMachine(CPU);
+  }
   return false;
 }
 
diff --git a/llvm/test/MC/SystemZ/machine-directive-invalid.s b/llvm/test/MC/SystemZ/machine-directive-invalid.s
index 8b3147ecc62d4..f9e6aea4f2604 100644
--- a/llvm/test/MC/SystemZ/machine-directive-invalid.s
+++ b/llvm/test/MC/SystemZ/machine-directive-invalid.s
@@ -1,10 +1,17 @@
+// NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py UTC_ARGS: --version 5
 # RUN: not llvm-mc -triple=s390x %s 2>&1 | FileCheck %s
 
-# CHECK: [[#@LINE+1]]:9: error: unexpected token in '.machine' directive
 .machine
+// CHECK: :[[@LINE-1]]:9: error: unexpected token in '.machine' directive
+
+.machine push
+// CHECK: :[[@LINE-1]]:10: error: push without preceding cpu spec in '.machine' directive
+
+.machine pop
+// CHECK: :[[@LINE-1]]:10: error: pop without corresponding push in '.machine' directive
 
-# CHECK: [[#@LINE+1]]:10: error: unexpected token in '.machine' directive
 .machine 42
+// CHECK: :[[@LINE-1]]:10: error: unexpected token in '.machine' directive
 
-# CHECK: [[#@LINE+1]]:13: error: expected newline
 .machine z13+
+// CHECK: :[[@LINE-1]]:13: error: expected newline
diff --git a/llvm/test/MC/SystemZ/machine-directive.s b/llvm/test/MC/SystemZ/machine-directive.s
index aa71c6aea5572..7861c56420cd3 100644
--- a/llvm/test/MC/SystemZ/machine-directive.s
+++ b/llvm/test/MC/SystemZ/machine-directive.s
@@ -12,9 +12,10 @@
 # CHECK: vgbm	%v0, 3
 
 .machine z13
+.machine push
 vgbm    %v0, 0
 .machine zEC12
 vgbm    %v0, 1
-.machine z13
+.machine pop
 vgbm    %v0, 3
 

@dominik-steenken
Copy link
Contributor Author

@uweigand FYI

@dominik-steenken
Copy link
Contributor Author

dominik-steenken commented Apr 25, 2025

investigating ci fail

@uweigand
Copy link
Member

This implementation makes the assumption that, without any .machine directive, the "current" machine is undefined, rather than trying to derive it based on the host machine. Thus, in this implementation, any .machine push must be preceded by at least one .machine <cpu>. Otherwise, a parsing error is recognized.

I don't think this matches GAS behavior. Why is this necessary? Can't we just push the feature bits instead of the name onto the stack? There's the default set of feature bits that's already detected (and used before any explicit machine directive); a first push would just push this; subsequent pops would restore whatever bits are set without having to re-compute them from a name.

@dominik-steenken dominik-steenken force-pushed the add-machine-push-pop branch 2 times, most recently from 35949c3 to 0834e7a Compare April 28, 2025 11:04
// it always reflects the current FeatureBitset used to determine which
// machine features are available, i.e. either the default or the result
// of the most reecent `.machine` directive.
FeatureBitset CurrentFeatures;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this copy? You should be able to just use STI.getAvailableFeatures() ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, i have removed the copy and use getAvailableFeatures() instead.

return TokError("pop without corresponding push in '.machine' directive");
CurrentFeatures = MachineStack.back();
MachineStack.pop_back();
setAvailableFeatures(CurrentFeatures);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be an inconsistency w.r.t. calling ComputeAvailableFeatures. This needs to be called somewhere, either before setting up CurrentFeatures or else when using it here. (If you do push STI.getAvailableFeatures() instead as mentioned above, this issue would go away as well.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, i was a bit confused as to what ComputeAvailableFeatures did since it takes and produces a FeatureBitset. Since i took your advice above, i think this is now addressed as well.

STI.setDefaultFeatures(Id, /*TuneCPU*/ Id, "");
CurrentFeatures = STI.getFeatureBits();
setAvailableFeatures(ComputeAvailableFeatures(CurrentFeatures));
getTargetStreamer().emitMachine(Id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit: looks like you do the same emitMachine call in all three branches, so it probably should be moved after the if.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, those were originally different but over the various edits they became the same. I've moved them as you suggested.

setAvailableFeatures(ComputeAvailableFeatures(CurrentFeatures));
getTargetStreamer().emitMachine(Id);
}

Parser.Lex();
if (parseEOL())
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to leave this error check before performing any action.

Copy link
Contributor Author

@dominik-steenken dominik-steenken Apr 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This introduced a minor compilcation where i had to separate the reporting of the TokError from the existing if block, but i think it is now in the right place. Thanks for the feedback :)

@dominik-steenken
Copy link
Contributor Author

This implementation makes the assumption that, without any .machine directive, the "current" machine is undefined, rather than trying to derive it based on the host machine. Thus, in this implementation, any .machine push must be preceded by at least one .machine <cpu>. Otherwise, a parsing error is recognized.

I don't think this matches GAS behavior. Why is this necessary? Can't we just push the feature bits instead of the name onto the stack? There's the default set of feature bits that's already detected (and used before any explicit machine directive); a first push would just push this; subsequent pops would restore whatever bits are set without having to re-compute them from a name.

Thanks, that was very helpful. I was somewhat unhappy with this solution as well. It originated from me having difficulties obtaining a string description of the CPU from the SubTargetInfo - it seemed no matter where i sourced this from, it would always be an empty string. But as you point out, it is also possible to just store the bits and restore them once the .machine stack is empty. I have updated the commit to provide an implementation that does this. .machine push without a prior .machine <cpu> is thus now legal and i have modified the tests accordingly. I have also tried to incorporate your additional feedback. I am now waiting for the CI to complete.

// Do error check before lexing the next token so that TokError
// points at the correct token.
if ((Id == "pop") && (MachineStack.empty()))
return TokError("pop without corresponding push in '.machine' directive");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. I do think it would be better to have the syntax check before the semantics check. E.g. if you do a .machine pop z15 or something, you should preferably see the error that there's an unexpected token at the end, over the error that there was no corresponding push.

To get the location correct, I think it would be better to use an Error with an explicit location (e.g. by calling Parser.getTok().getLoc() at the place where you do the getIdentifier call, and then using that location with Error further down).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense to me, i have reincorporated the check for the semantic error and added an additional line to the error test to check that the .machine pop <cpu> situation you outlined does in fact point at the syntax issue and not the semantic one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually hang on i used a push instead of a pop...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and it does report the semantic issue first :/
GIve me a second please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved. It works now, at least in my local testing.

@dominik-steenken dominik-steenken force-pushed the add-machine-push-pop branch 2 times, most recently from 4c94500 to 17df235 Compare April 28, 2025 13:00
Copy link
Member

@uweigand uweigand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now assuming CI passes.

@dominik-steenken
Copy link
Contributor Author

From what i can tell, this lldb check fail exists on main as well. Not sure what to do about this, for now i'll just rebase.

The `.machine push` and `.machine pop` directives were missing from
the SystemZ Backend Asm Parser. This commit adds them, and expands the
corresponding test to test proper operation.
@uweigand
Copy link
Member

Thanks. The Windows failure looks unrelated, so I think this is good to go now.

@uweigand uweigand merged commit c626ef9 into llvm:main Apr 30, 2025
9 of 11 checks passed
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
The `.machine push` and `.machine pop` directives were missing from the
SystemZ Backend Asm Parser. This PR adds them, and expands the
corresponding test to test proper operation.

Internally, this is modeled as a simple stack implemented on a
`SmallVector<StringRef>`.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
The `.machine push` and `.machine pop` directives were missing from the
SystemZ Backend Asm Parser. This PR adds them, and expands the
corresponding test to test proper operation.

Internally, this is modeled as a simple stack implemented on a
`SmallVector<StringRef>`.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
The `.machine push` and `.machine pop` directives were missing from the
SystemZ Backend Asm Parser. This PR adds them, and expands the
corresponding test to test proper operation.

Internally, this is modeled as a simple stack implemented on a
`SmallVector<StringRef>`.
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
The `.machine push` and `.machine pop` directives were missing from the
SystemZ Backend Asm Parser. This PR adds them, and expands the
corresponding test to test proper operation.

Internally, this is modeled as a simple stack implemented on a
`SmallVector<StringRef>`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:SystemZ mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants