[llvm] [SPARC] Implement L and H inline asm argument modifiers (PR #87259)

via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 2 09:01:37 PDT 2024


https://github.com/koachan updated https://github.com/llvm/llvm-project/pull/87259

>From 65ed4a79d9bd810b19ba86423e3ea656fffa6610 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Sat, 30 Mar 2024 13:01:19 +0700
Subject: [PATCH 1/2] [SPARC] Implement L and H inline asm argument modifiers

This adds support for using the L and H argument modifiers for twinword
operands in inline asm code, which is used by the Linux kernel.
---
 llvm/docs/LangRef.rst                     |  2 ++
 llvm/lib/Target/Sparc/SparcAsmPrinter.cpp | 42 +++++++++++++++++++++++
 llvm/test/CodeGen/SPARC/inlineasm.ll      |  9 +++++
 3 files changed, 53 insertions(+)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 8bc1cab01bf0a6..3f8f4c01201a6c 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -5557,6 +5557,8 @@ RISC-V:
 
 Sparc:
 
+- ``L``: Print the low-order register of a two-register operand.
+- ``H``: Print the high-order register of a two-register operand.
 - ``r``: No effect.
 
 SystemZ:
diff --git a/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp b/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
index 215a8ea8319046..35daf84a351239 100644
--- a/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
+++ b/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -434,6 +434,48 @@ bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
     default:
       // See if this is a generic print operand
       return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
+    case 'L': // Low order register of a twin word register operand
+    case 'H': // High order register of a twin word register operand
+    {
+      if (OpNo == 0)
+        return true;
+
+      const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>();
+      const MachineOperand &MO = MI->getOperand(OpNo);
+      const Register MOReg = MO.getReg();
+
+      Register HiReg, LoReg;
+      if (SP::IntPairRegClass.contains(MOReg)) {
+        // If we're given a register pair, decompose it
+        // to its constituents and use them as-is.
+        const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo();
+        HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even);
+        LoReg = RegisterInfo->getSubReg(MOReg, SP::sub_odd);
+      } else {
+        // Otherwise we should be given an even-numbered register,
+        // which will become the Hi part of the pair.
+        HiReg = MOReg;
+        LoReg = MOReg + 1;
+
+        // FIXME this really should not be an assert check, but
+        // I have no good idea on how to raise an error with explainations.
+        assert(((HiReg - SP::G0) % 2 == 0) &&
+               "Hi part of pair should point to an even-numbered register!");
+      }
+
+      Register Reg;
+      switch (ExtraCode[0]) {
+      case 'L':
+        Reg = LoReg;
+        break;
+      case 'H':
+        Reg = HiReg;
+        break;
+      }
+
+      O << '%' << SparcInstPrinter::getRegisterName(Reg);
+      return false;
+    }
     case 'f':
     case 'r':
      break;
diff --git a/llvm/test/CodeGen/SPARC/inlineasm.ll b/llvm/test/CodeGen/SPARC/inlineasm.ll
index ec27598e5e83b7..cfb44817fb54a8 100644
--- a/llvm/test/CodeGen/SPARC/inlineasm.ll
+++ b/llvm/test/CodeGen/SPARC/inlineasm.ll
@@ -143,3 +143,12 @@ entry:
   %1 = call double asm sideeffect "faddd $1, $2, $0", "=f,f,e"(i64 0, i64 0)
   ret void
 }
+
+; CHECK-label:test_twinword
+; CHECK: rd  %asr5, %i1
+; CHECK: srlx %i1, 32, %i0
+
+define i64 @test_twinword(){
+  %1 = tail call i64 asm sideeffect "rd %asr5, ${0:L} \0A\09 srlx ${0:L}, 32, ${0:H}", "=r"()
+  ret i64 %1
+}

>From 619665f05f61e6d3be91951a1589feb2254e4b5c Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Tue, 2 Apr 2024 23:00:39 +0700
Subject: [PATCH 2/2] Add tests and apply suggested changes.

---
 llvm/lib/Target/Sparc/SparcAsmPrinter.cpp | 40 +++++++++++++----------
 llvm/test/CodeGen/SPARC/inlineasm-bad.ll  |  9 +++++
 llvm/test/CodeGen/SPARC/inlineasm.ll      |  2 +-
 3 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp b/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
index 35daf84a351239..5beed8b342c072 100644
--- a/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
+++ b/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -442,27 +442,33 @@ bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
 
       const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>();
       const MachineOperand &MO = MI->getOperand(OpNo);
-      const Register MOReg = MO.getReg();
+      const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo();
+      Register MOReg = MO.getReg();
 
       Register HiReg, LoReg;
-      if (SP::IntPairRegClass.contains(MOReg)) {
-        // If we're given a register pair, decompose it
-        // to its constituents and use them as-is.
-        const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo();
-        HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even);
-        LoReg = RegisterInfo->getSubReg(MOReg, SP::sub_odd);
-      } else {
-        // Otherwise we should be given an even-numbered register,
-        // which will become the Hi part of the pair.
-        HiReg = MOReg;
-        LoReg = MOReg + 1;
-
-        // FIXME this really should not be an assert check, but
-        // I have no good idea on how to raise an error with explainations.
-        assert(((HiReg - SP::G0) % 2 == 0) &&
-               "Hi part of pair should point to an even-numbered register!");
+      if (!SP::IntPairRegClass.contains(MOReg)) {
+        // If we aren't given a register pair already, find out which pair it
+        // belongs to. Note that here, the specified register operand, which
+        // refers to the high part of the twinword, needs to be an even-numbered
+        // register.
+        if ((MOReg - SP::G0) % 2 != 0) {
+          SMLoc Loc = SMLoc();
+          OutContext.reportError(
+              Loc, "Hi part of pair should point to an even-numbered register");
+          OutContext.reportError(
+              Loc, "(note that in some cases it might be necessary to manually "
+                   "bind the input/output registers instead of relying on "
+                   "automatic allocation)");
+          return true;
+        }
+
+        MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even,
+                                                  &SP::IntPairRegClass);
       }
 
+      HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even);
+      LoReg = RegisterInfo->getSubReg(MOReg, SP::sub_odd);
+
       Register Reg;
       switch (ExtraCode[0]) {
       case 'L':
diff --git a/llvm/test/CodeGen/SPARC/inlineasm-bad.ll b/llvm/test/CodeGen/SPARC/inlineasm-bad.ll
index 5bf2adbeb75c95..07eb67df6e5f7e 100644
--- a/llvm/test/CodeGen/SPARC/inlineasm-bad.ll
+++ b/llvm/test/CodeGen/SPARC/inlineasm-bad.ll
@@ -11,3 +11,12 @@ entry:
   tail call void asm sideeffect "faddq $0,$1,$2", "{f38},{f0},{f0}"(fp128 0xL0, fp128 0xL0, fp128 0xL0)
   ret void
 }
+
+; CHECK-label:test_twinword_error
+; CHECK: error: Hi part of pair should point to an even-numbered register
+; CHECK: error: (note that in some cases it might be necessary to manually bind the input/output registers instead of relying on automatic allocation)
+
+define i64 @test_twinword_error(){
+  %1 = tail call i64 asm sideeffect "rd %asr5, ${0:L} \0A\09 srlx ${0:L}, 32, ${0:H}", "={i1}"()
+  ret i64 %1
+}
diff --git a/llvm/test/CodeGen/SPARC/inlineasm.ll b/llvm/test/CodeGen/SPARC/inlineasm.ll
index cfb44817fb54a8..9817d7c6971f5c 100644
--- a/llvm/test/CodeGen/SPARC/inlineasm.ll
+++ b/llvm/test/CodeGen/SPARC/inlineasm.ll
@@ -149,6 +149,6 @@ entry:
 ; CHECK: srlx %i1, 32, %i0
 
 define i64 @test_twinword(){
-  %1 = tail call i64 asm sideeffect "rd %asr5, ${0:L} \0A\09 srlx ${0:L}, 32, ${0:H}", "=r"()
+  %1 = tail call i64 asm sideeffect "rd %asr5, ${0:L} \0A\09 srlx ${0:L}, 32, ${0:H}", "={i0}"()
   ret i64 %1
 }



More information about the llvm-commits mailing list