Skip to content

[ARM64EC] Warn on using disallowed registers in assembly src. #93618

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 4 commits into from
Jun 3, 2024

Conversation

namikukr
Copy link
Contributor

ARM64EC designates a set of disallowed registers, because a mapping does not exist from them to x64. The MSVC assembler (armasm64) has a warning for this.

A test is also included as part of the patch.

See the list of disallowed registers below:
https://learn.microsoft.com/en-us/cpp/build/arm64ec-windows-abi-conventions?view=msvc-170#register-mapping

ARM64EC designates a set of disallowed registers, because
a mapping does not exist from them to x64. The MSVC assembler
(armasm64) has a warning for this.

A test is also included as part of the patch.

See the list of disallowed registers below:
https://learn.microsoft.com/en-us/cpp/build/arm64ec-windows-abi-conventions?view=msvc-170#register-mapping
Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be
notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write
permissions for the repository. In which case you can instead tag reviewers by
name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review
by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate
is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added backend:AArch64 mc Machine (object) code labels May 28, 2024
@llvmbot
Copy link
Member

llvmbot commented May 28, 2024

@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-mc

Author: Namish Kukreja (namikukr)

Changes

ARM64EC designates a set of disallowed registers, because a mapping does not exist from them to x64. The MSVC assembler (armasm64) has a warning for this.

A test is also included as part of the patch.

See the list of disallowed registers below:
https://learn.microsoft.com/en-us/cpp/build/arm64ec-windows-abi-conventions?view=msvc-170#register-mapping


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

2 Files Affected:

  • (modified) llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp (+27)
  • (added) llvm/test/MC/AArch64/arm64ec-disallowed-regs.s (+75)
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 13a68b7dcf984..ea329dd71e398 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -294,11 +294,13 @@ class AArch64AsmParser : public MCTargetAsmParser {
 #include "AArch64GenAsmMatcher.inc"
   };
   bool IsILP32;
+  bool IsWindowsArm64EC;
 
   AArch64AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
                    const MCInstrInfo &MII, const MCTargetOptions &Options)
     : MCTargetAsmParser(Options, STI, MII) {
     IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
+    IsWindowsArm64EC = STI.getTargetTriple().isWindowsArm64EC();
     MCAsmParserExtension::Initialize(Parser);
     MCStreamer &S = getParser().getStreamer();
     if (S.getTargetStreamer() == nullptr)
@@ -5315,6 +5317,31 @@ bool AArch64AsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc,
     }
   }
 
+  // On ARM64EC, only valid registers may be used. Warn against using
+  // explicitly disallowed registers.
+  if (IsWindowsArm64EC) {
+    for (unsigned i = 0; i < Inst.getNumOperands(); ++i) {
+      if (Inst.getOperand(i).isReg()) {
+        unsigned Reg = Inst.getOperand(i).getReg();
+        // At this point, vector registers are matched to their
+        // appropriately sized alias.
+        if ((Reg == AArch64::W13 || Reg == AArch64::X13) ||
+            (Reg == AArch64::W14 || Reg == AArch64::X14) ||
+            (Reg == AArch64::W23 || Reg == AArch64::X23) ||
+            (Reg == AArch64::W24 || Reg == AArch64::X24) ||
+            (Reg == AArch64::W28 || Reg == AArch64::X28) ||
+            (Reg >= AArch64::Q16 && Reg <= AArch64::Q31) ||
+            (Reg >= AArch64::D16 && Reg <= AArch64::D31) ||
+            (Reg >= AArch64::S16 && Reg <= AArch64::S31) ||
+            (Reg >= AArch64::H16 && Reg <= AArch64::H31) ||
+            (Reg >= AArch64::B16 && Reg <= AArch64::B31)) {
+          Warning(IDLoc, "this instruction uses disallowed registers.");
+          break;
+        }
+      }
+    }
+  }
+
   // Check for indexed addressing modes w/ the base register being the
   // same as a destination/source register or pair load where
   // the Rt == Rt2. All of those are undefined behaviour.
diff --git a/llvm/test/MC/AArch64/arm64ec-disallowed-regs.s b/llvm/test/MC/AArch64/arm64ec-disallowed-regs.s
new file mode 100644
index 0000000000000..8061987a51998
--- /dev/null
+++ b/llvm/test/MC/AArch64/arm64ec-disallowed-regs.s
@@ -0,0 +1,75 @@
+// RUN: llvm-mc -triple arm64ec-pc-windows-msvc < %s 2> %t.log
+// RUN: FileCheck %s --check-prefix=CHECK-ERR < %t.log
+
+
+// ---- disallowed x registers ----
+orr x13, x0, x1             // x13
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orr x14, x2, x3             // x14
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orr x4, x23, x5             // x23
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orr x6, x7, x24             // x24
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orr x28, x8, x9             // x28
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+
+// ---- disallowed w registers ----
+orr w0, w13, w1             // w13
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orr w14, w2, w3             // w14
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orr w4, w23, w5             // w23
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orr w6, w7, w24             // w24
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orr w28, w8, w9             // w28
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+
+// ---- disallowed vector registers ----
+orn v1.8b, v16.8b, v2.8b        // v16
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v2.16b, v17.16b, v3.16b     // v17
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v3.8b, v18.8b, v4.8b        // v18
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v4.16b, v19.16b, v5.16b     // v19
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v5.8b, v20.8b, v6.8b        // v20
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v21.8b, v6.8b, v7.8b        // v21
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v7.16b, v8.16b, v22.16b     // v22
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v23.8b, v8.8b, v9.8b        // v23
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v9.16b, v24.16b, v10.16b    // v24
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v10.8b, v25.8b, v11.8b      // v25
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v11.8b, v12.8b, v26.8b      // v26
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v12.8b, v27.8b, v13.8b      // v27
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v13.16b, v28.16b, v14.16b   // v28
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v14.8b, v29.8b, v15.8b      // v29
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v15.8b, v30.8b, v15.8b      // v30
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+orn v1.16b, v31.16b, v1.16b     // v31
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+
+// ---- random tests on h, b, d, s registers ----
+orn.16b v1, v16, v2
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+mov.4h v17, v8
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+fmul.2s v2, v18, v11
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+clz.8h v3, v19
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+add.4s v0, v20, v1
+// CHECK-ERR: warning: this instruction uses disallowed registers.
+add.2d v0, v20, v1
+// CHECK-ERR: warning: this instruction uses disallowed registers.
\ No newline at end of file

Copy link
Member

@mstorsjo mstorsjo left a comment

Choose a reason for hiding this comment

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

Thanks, this looks very valuable!

Can you mention how to enable this warning when using armasm64? (Or I guess it probably gets enabled automatically if assembling with some flag to switch to arm64ec mode - what's the armasm64 flag for that?)

add.4s v0, v20, v1
// CHECK-ERR: warning: this instruction uses disallowed registers.
add.2d v0, v20, v1
// CHECK-ERR: warning: this instruction uses disallowed registers.
Copy link
Member

Choose a reason for hiding this comment

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

Nit: The file seems to be lacking a trailing end of line character

@namikukr
Copy link
Contributor Author

Thanks, this looks very valuable!

Can you mention how to enable this warning when using armasm64? (Or I guess it probably gets enabled automatically if assembling with some flag to switch to arm64ec mode - what's the armasm64 flag for that?)

When assembling with cl on Windows, the flag is -arm64EC. It's mirrored similarly by clang-cl. I'll include that in the commit message.

@mstorsjo
Copy link
Member

Thanks, this looks very valuable!
Can you mention how to enable this warning when using armasm64? (Or I guess it probably gets enabled automatically if assembling with some flag to switch to arm64ec mode - what's the armasm64 flag for that?)

When assembling with cl on Windows, the flag is -arm64EC. It's mirrored similarly by clang-cl. I'll include that in the commit message.

But you mentioned armasm64 - one doesn't build assembly with cl. But I looked it up and tested myself - to assemble arm64ec object files with armasm64, one passes the flags -machine arm64ec, and then it does automatically warn about use of forbidden registers.

@namikukr
Copy link
Contributor Author

But you mentioned armasm64 - one doesn't build assembly with cl. But I looked it up and tested myself - to assemble arm64ec object files with armasm64, one passes the flags -machine arm64ec, and then it does automatically warn about use of forbidden registers.

I apologize - I'm a bit new to this so I'm just getting familiar.

That seems accurate. I'm working on making the changes that were suggested and will be back with an update as soon as I have one.

@zhaoshiz
Copy link
Contributor

Thanks, this looks very valuable!
Can you mention how to enable this warning when using armasm64? (Or I guess it probably gets enabled automatically if assembling with some flag to switch to arm64ec mode - what's the armasm64 flag for that?)

When assembling with cl on Windows, the flag is -arm64EC. It's mirrored similarly by clang-cl. I'll include that in the commit message.

But you mentioned armasm64 - one doesn't build assembly with cl. But I looked it up and tested myself - to assemble arm64ec object files with armasm64, one passes the flags -machine arm64ec, and then it does automatically warn about use of forbidden registers.

yes, armasm64 automatically enables this warning when target ARM64EC, the flag is -machine arm64ec

// CHECK-ERR: warning: register Q20 is disallowed on ARM64EC.
add.2d v0, v20, v1
// CHECK-ERR: warning: register Q20 is disallowed on ARM64EC.

Copy link
Contributor

Choose a reason for hiding this comment

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

you may want to try data width less than DoubleWord (D, 64-bit), e.g. 4b, 2h, s and see if the warning msg still uses Dx register name or S/H/B names.

Also worth to try some instructions like fadd s0, s1, s16 and see what reg names is emmitted with the warning msg.

(Reg >= AArch64::H16 && Reg <= AArch64::H31) ||
(Reg >= AArch64::B16 && Reg <= AArch64::B31)) {
Warning(IDLoc, "register " + Twine(RI->getName(Reg)) +
" is disallowed on ARM64EC.");
Copy link
Contributor

Choose a reason for hiding this comment

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

now it warns on each disallowed register, you can add an orr v1, v16, v17 to the tests and check that two warnings are issued for this instruction

// ---- random tests on h, b, d, s registers ----
orn.16b v1, v16, v2
// CHECK-ERR: warning: register Q16 is disallowed on ARM64EC.
mov.4h v17, v8
Copy link
Member

Choose a reason for hiding this comment

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

Instead of using these nonstandard(?) assembler forms with mov.4h, can't we use instructions that natively use the form d17? E.g. str d17, [x0]?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just pushed a patch that hopefully fixes this, let me know if you have more concerns!

@mstorsjo
Copy link
Member

No further comments from me here, this looks good now, but I'll wait for others who also have commented, before approving.

Copy link
Contributor

@zhaoshiz zhaoshiz left a comment

Choose a reason for hiding this comment

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

LGTM, give it some time so others can comment/approve.

@namikukr
Copy link
Contributor Author

namikukr commented Jun 3, 2024

gentle ping...

@dpaoliello dpaoliello merged commit 43847c1 into llvm:main Jun 3, 2024
7 checks passed
Copy link

github-actions bot commented Jun 3, 2024

@namikukr Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested
by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as
the builds can include changes from many authors. It is not uncommon for your
change to be included in a build that fails due to someone else's changes, or
infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself.
This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants