From 65ed4a79d9bd810b19ba86423e3ea656fffa6610 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sat, 30 Mar 2024 13:01:19 +0700 Subject: [PATCH 1/4] [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 8bc1cab01bf0a..3f8f4c01201a6 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 215a8ea831904..35daf84a35123 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(); + 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 ec27598e5e83b..cfb44817fb54a 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 Date: Tue, 2 Apr 2024 23:00:39 +0700 Subject: [PATCH 2/4] 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 35daf84a35123..5beed8b342c07 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(); 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 5bf2adbeb75c9..07eb67df6e5f7 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 cfb44817fb54a..9817d7c6971f5 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 } From e8738774da13de25f1c6273c8b159c05a7ae5a71 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 3 Apr 2024 23:02:11 +0700 Subject: [PATCH 3/4] Remove unneded check and change register pairing check --- llvm/lib/Target/Sparc/SparcAsmPrinter.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp b/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp index 5beed8b342c07..ee9358e3cf83f 100644 --- a/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp +++ b/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp @@ -437,9 +437,6 @@ bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 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(); const MachineOperand &MO = MI->getOperand(OpNo); const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo(); @@ -451,7 +448,9 @@ bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, // 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) { + MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even, + &SP::IntPairRegClass); + if (!MOReg) { SMLoc Loc = SMLoc(); OutContext.reportError( Loc, "Hi part of pair should point to an even-numbered register"); @@ -461,9 +460,6 @@ bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, "automatic allocation)"); return true; } - - MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even, - &SP::IntPairRegClass); } HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even); From 6375b2a2baa67f5fb187896319dc3808b366e5b5 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 4 Apr 2024 21:52:43 +0700 Subject: [PATCH 4/4] Change SMLoc declaration --- llvm/lib/Target/Sparc/SparcAsmPrinter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp b/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp index ee9358e3cf83f..6855471840e9d 100644 --- a/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp +++ b/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp @@ -451,7 +451,7 @@ bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even, &SP::IntPairRegClass); if (!MOReg) { - SMLoc Loc = SMLoc(); + SMLoc Loc; OutContext.reportError( Loc, "Hi part of pair should point to an even-numbered register"); OutContext.reportError(