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

This adds support for using the L and H argument modifiers for twinword
operands in inline asm code, such as in:

```
%1 = tail call i64 asm sideeffect "rd %pc, ${0:L} ; srlx ${0:L}, 32, ${0:H}", "={o4}"()
```

This is needed by the Linux kernel.
This commit is contained in:
Koakuma
2024-04-05 04:34:07 +07:00
committed by GitHub
parent 18380c522a
commit 697dd93ae3
4 changed files with 64 additions and 0 deletions

View File

@@ -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:

View File

@@ -434,6 +434,50 @@ 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
{
const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>();
const MachineOperand &MO = MI->getOperand(OpNo);
const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo();
Register MOReg = MO.getReg();
Register HiReg, LoReg;
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.
MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even,
&SP::IntPairRegClass);
if (!MOReg) {
SMLoc Loc;
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;
}
}
HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even);
LoReg = RegisterInfo->getSubReg(MOReg, SP::sub_odd);
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;

View File

@@ -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
}

View File

@@ -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}", "={i0}"()
ret i64 %1
}