From ad366a3f67679a56d25464dc2bcad3a0a6a51780 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 1 Oct 2013 14:53:46 +0000 Subject: [SystemZ] Add immediate addition involving high words git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191774 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/SystemZ/SystemZInstrFormats.td | 19 +++++ lib/Target/SystemZ/SystemZInstrInfo.cpp | 52 +++++++++++++- lib/Target/SystemZ/SystemZInstrInfo.h | 2 + lib/Target/SystemZ/SystemZInstrInfo.td | 5 ++ test/CodeGen/SystemZ/asm-18.ll | 115 ++++++++++++++++++++++++++++++ test/MC/Disassembler/SystemZ/insns.txt | 18 +++++ test/MC/SystemZ/insn-bad-z196.s | 8 +++ test/MC/SystemZ/insn-bad.s | 5 ++ test/MC/SystemZ/insn-good-z196.s | 14 ++++ 9 files changed, 236 insertions(+), 2 deletions(-) diff --git a/lib/Target/SystemZ/SystemZInstrFormats.td b/lib/Target/SystemZ/SystemZInstrFormats.td index 9ca1a8a..3b06732 100644 --- a/lib/Target/SystemZ/SystemZInstrFormats.td +++ b/lib/Target/SystemZ/SystemZInstrFormats.td @@ -1386,6 +1386,25 @@ class BinaryRIPseudo + : Pseudo<(outs cls:$R1), (ins cls:$R3, imm:$I2), + [(set cls:$R1, (operator cls:$R3, imm:$I2))]>; + +// Like BinaryRIAndK, but expanded after RA depending on the choice of register. +multiclass BinaryRIAndKPseudo { + let NumOpsKey = key in { + let NumOpsValue = "3" in + def K : BinaryRIEPseudo, + Requires<[FeatureHighWord, FeatureDistinctOps]>; + let NumOpsValue = "2", isConvertibleToThreeAddress = 1 in + def "" : BinaryRIPseudo, + Requires<[FeatureHighWord]>; + } +} + // Like CompareRI, but expanded after RA depending on the choice of register. class CompareRIPseudo diff --git a/lib/Target/SystemZ/SystemZInstrInfo.cpp b/lib/Target/SystemZ/SystemZInstrInfo.cpp index 2c48c78..acefd9c 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ b/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -107,6 +107,28 @@ void SystemZInstrInfo::expandRIPseudo(MachineInstr *MI, unsigned LowOpcode, MI->getOperand(1).setImm(uint32_t(MI->getOperand(1).getImm())); } +// MI is a three-operand RIE-style pseudo instruction. Replace it with +// LowOpcode3 if the registers are both low GR32s, otherwise use a move +// followed by HighOpcode or LowOpcode, depending on whether the target +// is a high or low GR32. +void SystemZInstrInfo::expandRIEPseudo(MachineInstr *MI, unsigned LowOpcode, + unsigned LowOpcodeK, + unsigned HighOpcode) const { + unsigned DestReg = MI->getOperand(0).getReg(); + unsigned SrcReg = MI->getOperand(1).getReg(); + bool DestIsHigh = isHighReg(DestReg); + bool SrcIsHigh = isHighReg(SrcReg); + if (!DestIsHigh && !SrcIsHigh) + MI->setDesc(get(LowOpcodeK)); + else { + emitGRX32Move(*MI->getParent(), MI, MI->getDebugLoc(), + DestReg, SrcReg, SystemZ::LR, 32, + MI->getOperand(1).isKill()); + MI->setDesc(get(DestIsHigh ? HighOpcode : LowOpcode)); + MI->getOperand(1).setReg(DestReg); + } +} + // MI is an RXY-style pseudo instruction. Replace it with LowOpcode // if the first operand is a low GR32 and HighOpcode if the first operand // is a high GR32. @@ -651,6 +673,7 @@ SystemZInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI, LiveVariables *LV) const { MachineInstr *MI = MBBI; MachineBasicBlock *MBB = MI->getParent(); + MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo(); unsigned Opcode = MI->getOpcode(); unsigned NumOps = MI->getNumOperands(); @@ -660,10 +683,23 @@ SystemZInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI, // because it tends to be shorter and because some instructions // have memory forms that can be used during spilling. if (TM.getSubtargetImpl()->hasDistinctOps()) { + MachineOperand &Dest = MI->getOperand(0); + MachineOperand &Src = MI->getOperand(1); + unsigned DestReg = Dest.getReg(); + unsigned SrcReg = Src.getReg(); + // AHIMux is only really a three-operand instruction when both operands + // are low registers. Try to constrain both operands to be low if + // possible. + if (Opcode == SystemZ::AHIMux && + TargetRegisterInfo::isVirtualRegister(DestReg) && + TargetRegisterInfo::isVirtualRegister(SrcReg) && + MRI.getRegClass(DestReg)->contains(SystemZ::R1L) && + MRI.getRegClass(SrcReg)->contains(SystemZ::R1L)) { + MRI.constrainRegClass(DestReg, &SystemZ::GR32BitRegClass); + MRI.constrainRegClass(SrcReg, &SystemZ::GR32BitRegClass); + } int ThreeOperandOpcode = SystemZ::getThreeOperandOpcode(Opcode); if (ThreeOperandOpcode >= 0) { - MachineOperand &Dest = MI->getOperand(0); - MachineOperand &Src = MI->getOperand(1); MachineInstrBuilder MIB = BuildMI(*MBB, MBBI, MI->getDebugLoc(), get(ThreeOperandOpcode)) .addOperand(Dest); @@ -918,6 +954,18 @@ SystemZInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { expandRIPseudo(MI, SystemZ::TMLH, SystemZ::TMHH, false); return true; + case SystemZ::AHIMux: + expandRIPseudo(MI, SystemZ::AHI, SystemZ::AIH, false); + return true; + + case SystemZ::AHIMuxK: + expandRIEPseudo(MI, SystemZ::AHI, SystemZ::AHIK, SystemZ::AIH); + return true; + + case SystemZ::AFIMux: + expandRIPseudo(MI, SystemZ::AFI, SystemZ::AIH, false); + return true; + case SystemZ::RISBMux: { bool DestIsHigh = isHighReg(MI->getOperand(0).getReg()); bool SrcIsHigh = isHighReg(MI->getOperand(2).getReg()); diff --git a/lib/Target/SystemZ/SystemZInstrInfo.h b/lib/Target/SystemZ/SystemZInstrInfo.h index 06e677a..7978be4 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.h +++ b/lib/Target/SystemZ/SystemZInstrInfo.h @@ -118,6 +118,8 @@ class SystemZInstrInfo : public SystemZGenInstrInfo { void splitAdjDynAlloc(MachineBasicBlock::iterator MI) const; void expandRIPseudo(MachineInstr *MI, unsigned LowOpcode, unsigned HighOpcode, bool ConvertHigh) const; + void expandRIEPseudo(MachineInstr *MI, unsigned LowOpcode, + unsigned LowOpcodeK, unsigned HighOpcode) const; void expandRXYPseudo(MachineInstr *MI, unsigned LowOpcode, unsigned HighOpcode) const; void expandZExtPseudo(MachineInstr *MI, unsigned LowOpcode, diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td index 340580a..986e77f 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -685,11 +685,16 @@ let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8 in { def AGFR : BinaryRRE<"agf", 0xB918, null_frag, GR64, GR32>; // Addition of signed 16-bit immediates. + defm AHIMux : BinaryRIAndKPseudo<"ahimux", add, GRX32, imm32sx16>; defm AHI : BinaryRIAndK<"ahi", 0xA7A, 0xECD8, add, GR32, imm32sx16>; defm AGHI : BinaryRIAndK<"aghi", 0xA7B, 0xECD9, add, GR64, imm64sx16>; // Addition of signed 32-bit immediates. + def AFIMux : BinaryRIPseudo, + Requires<[FeatureHighWord]>; def AFI : BinaryRIL<"afi", 0xC29, add, GR32, simm32>; + def AIH : BinaryRIL<"aih", 0xCC8, add, GRH32, simm32>, + Requires<[FeatureHighWord]>; def AGFI : BinaryRIL<"agfi", 0xC28, add, GR64, imm64sx32>; // Addition of memory. diff --git a/test/CodeGen/SystemZ/asm-18.ll b/test/CodeGen/SystemZ/asm-18.ll index 9eed60a..e16bf65 100644 --- a/test/CodeGen/SystemZ/asm-18.ll +++ b/test/CodeGen/SystemZ/asm-18.ll @@ -554,3 +554,118 @@ define i32 @f25(i32 %old) { "=r,h,h"(i32 %sel3, i32 %sel4) ret i32 %res2 } + +; Test two-operand halfword immediate addition involving high registers. +define void @f26() { +; CHECK-LABEL: f26: +; CHECK: stepa [[REG:%r[0-5]]] +; CHECK: aih [[REG]], -32768 +; CHECK: stepb [[REG]] +; CHECK: aih [[REG]], 1 +; CHECK: stepc [[REG]] +; CHECK: aih [[REG]], 32767 +; CHECK: stepd [[REG]] +; CHECK: br %r14 + %res1 = call i32 asm "stepa $0", "=h"() + %add1 = add i32 %res1, -32768 + %res2 = call i32 asm "stepb $0, $1", "=h,h"(i32 %add1) + %add2 = add i32 %res2, 1 + %res3 = call i32 asm "stepc $0, $1", "=h,h"(i32 %add2) + %add3 = add i32 %res3, 32767 + call void asm sideeffect "stepd $0", "h"(i32 %add3) + ret void +} + +; Test two-operand halfword immediate addition involving low registers. +define void @f27() { +; CHECK-LABEL: f27: +; CHECK: stepa [[REG:%r[0-5]]] +; CHECK: ahi [[REG]], -32768 +; CHECK: stepb [[REG]] +; CHECK: ahi [[REG]], 1 +; CHECK: stepc [[REG]] +; CHECK: ahi [[REG]], 32767 +; CHECK: stepd [[REG]] +; CHECK: br %r14 + %res1 = call i32 asm "stepa $0", "=r"() + %add1 = add i32 %res1, -32768 + %res2 = call i32 asm "stepb $0, $1", "=r,r"(i32 %add1) + %add2 = add i32 %res2, 1 + %res3 = call i32 asm "stepc $0, $1", "=r,r"(i32 %add2) + %add3 = add i32 %res3, 32767 + call void asm sideeffect "stepd $0", "r"(i32 %add3) + ret void +} + +; Test three-operand halfword immediate addition involving mixtures of low +; and high registers. RISBHG/AIH would be OK too, instead of AHIK/RISBHG. +define i32 @f28(i32 %old) { +; CHECK-LABEL: f28: +; CHECK: ahik [[REG1:%r[0-5]]], %r2, 14 +; CHECK: stepa %r2, [[REG1]] +; CHECK: ahik [[TMP:%r[0-5]]], [[REG1]], 254 +; CHECK: risbhg [[REG2:%r[0-5]]], [[TMP]], 0, 159, 32 +; CHECK: stepb [[REG1]], [[REG2]] +; CHECK: risbhg [[REG3:%r[0-5]]], [[REG2]], 0, 159, 0 +; CHECK: aih [[REG3]], 127 +; CHECK: stepc [[REG2]], [[REG3]] +; CHECK: risblg %r2, [[REG3]], 0, 159, 32 +; CHECK: ahi %r2, 128 +; CHECK: stepd [[REG3]], %r2 +; CHECK: br %r14 + %add1 = add i32 %old, 14 + %res1 = call i32 asm "stepa $1, $2", + "=r,r,0"(i32 %old, i32 %add1) + %add2 = add i32 %res1, 254 + %res2 = call i32 asm "stepb $1, $2", + "=h,r,0"(i32 %res1, i32 %add2) + %add3 = add i32 %res2, 127 + %res3 = call i32 asm "stepc $1, $2", + "=h,h,0"(i32 %res2, i32 %add3) + %add4 = add i32 %res3, 128 + %res4 = call i32 asm "stepd $1, $2", + "=r,h,0"(i32 %res3, i32 %add4) + ret i32 %res4 +} + +; Test large immediate addition involving high registers. +define void @f29() { +; CHECK-LABEL: f29: +; CHECK: stepa [[REG:%r[0-5]]] +; CHECK: aih [[REG]], -32769 +; CHECK: stepb [[REG]] +; CHECK: aih [[REG]], 32768 +; CHECK: stepc [[REG]] +; CHECK: aih [[REG]], 1000000000 +; CHECK: stepd [[REG]] +; CHECK: br %r14 + %res1 = call i32 asm "stepa $0", "=h"() + %add1 = add i32 %res1, -32769 + %res2 = call i32 asm "stepb $0, $1", "=h,h"(i32 %add1) + %add2 = add i32 %res2, 32768 + %res3 = call i32 asm "stepc $0, $1", "=h,h"(i32 %add2) + %add3 = add i32 %res3, 1000000000 + call void asm sideeffect "stepd $0", "h"(i32 %add3) + ret void +} + +; Test large immediate addition involving low registers. +define void @f30() { +; CHECK-LABEL: f30: +; CHECK: stepa [[REG:%r[0-5]]] +; CHECK: afi [[REG]], -32769 +; CHECK: stepb [[REG]] +; CHECK: afi [[REG]], 32768 +; CHECK: stepc [[REG]] +; CHECK: afi [[REG]], 1000000000 +; CHECK: stepd [[REG]] +; CHECK: br %r14 + %res1 = call i32 asm "stepa $0", "=r"() + %add1 = add i32 %res1, -32769 + %res2 = call i32 asm "stepb $0, $1", "=r,r"(i32 %add1) + %add2 = add i32 %res2, 32768 + %res3 = call i32 asm "stepc $0, $1", "=r,r"(i32 %add2) + %add3 = add i32 %res3, 1000000000 + call void asm sideeffect "stepd $0", "r"(i32 %add3) + ret void +} diff --git a/test/MC/Disassembler/SystemZ/insns.txt b/test/MC/Disassembler/SystemZ/insns.txt index 4775a5d..2f2e7fa 100644 --- a/test/MC/Disassembler/SystemZ/insns.txt +++ b/test/MC/Disassembler/SystemZ/insns.txt @@ -349,6 +349,24 @@ # CHECK: ahy %r15, 0 0xe3 0xf0 0x00 0x00 0x00 0x7a +# CHECK: aih %r0, -2147483648 +0xcc 0x08 0x80 0x00 0x00 0x00 + +# CHECK: aih %r0, -1 +0xcc 0x08 0xff 0xff 0xff 0xff + +# CHECK: aih %r0, 0 +0xcc 0x08 0x00 0x00 0x00 0x00 + +# CHECK: aih %r0, 1 +0xcc 0x08 0x00 0x00 0x00 0x01 + +# CHECK: aih %r0, 2147483647 +0xcc 0x08 0x7f 0xff 0xff 0xff + +# CHECK: aih %r15, 0 +0xcc 0xf8 0x00 0x00 0x00 0x00 + # CHECK: alcgr %r0, %r0 0xb9 0x88 0x00 0x00 diff --git a/test/MC/SystemZ/insn-bad-z196.s b/test/MC/SystemZ/insn-bad-z196.s index 0ed3370..2464001 100644 --- a/test/MC/SystemZ/insn-bad-z196.s +++ b/test/MC/SystemZ/insn-bad-z196.s @@ -25,6 +25,14 @@ ahik %r0, %r1, foo #CHECK: error: invalid operand +#CHECK: aih %r0, (-1 << 31) - 1 +#CHECK: error: invalid operand +#CHECK: aih %r0, (1 << 31) + + aih %r0, (-1 << 31) - 1 + aih %r0, (1 << 31) + +#CHECK: error: invalid operand #CHECK: fidbra %f0, 0, %f0, -1 #CHECK: error: invalid operand #CHECK: fidbra %f0, 0, %f0, 16 diff --git a/test/MC/SystemZ/insn-bad.s b/test/MC/SystemZ/insn-bad.s index 3fe3f4d..eadb9f0 100644 --- a/test/MC/SystemZ/insn-bad.s +++ b/test/MC/SystemZ/insn-bad.s @@ -128,6 +128,11 @@ ahy %r0, -524289 ahy %r0, 524288 +#CHECK: error: {{(instruction requires: high-word)?}} +#CHECK: aih %r0, 0 + + aih %r0, 0 + #CHECK: error: invalid operand #CHECK: al %r0, -1 #CHECK: error: invalid operand diff --git a/test/MC/SystemZ/insn-good-z196.s b/test/MC/SystemZ/insn-good-z196.s index 769ab02..2bc27bd 100644 --- a/test/MC/SystemZ/insn-good-z196.s +++ b/test/MC/SystemZ/insn-good-z196.s @@ -49,6 +49,20 @@ ahik %r15, %r0, 0 ahik %r7, %r8, -16 +#CHECK: aih %r0, -2147483648 # encoding: [0xcc,0x08,0x80,0x00,0x00,0x00] +#CHECK: aih %r0, -1 # encoding: [0xcc,0x08,0xff,0xff,0xff,0xff] +#CHECK: aih %r0, 0 # encoding: [0xcc,0x08,0x00,0x00,0x00,0x00] +#CHECK: aih %r0, 1 # encoding: [0xcc,0x08,0x00,0x00,0x00,0x01] +#CHECK: aih %r0, 2147483647 # encoding: [0xcc,0x08,0x7f,0xff,0xff,0xff] +#CHECK: aih %r15, 0 # encoding: [0xcc,0xf8,0x00,0x00,0x00,0x00] + + aih %r0, -1 << 31 + aih %r0, -1 + aih %r0, 0 + aih %r0, 1 + aih %r0, (1 << 31) - 1 + aih %r15, 0 + #CHECK: alghsik %r0, %r0, -32768 # encoding: [0xec,0x00,0x80,0x00,0x00,0xdb] #CHECK: alghsik %r0, %r0, -1 # encoding: [0xec,0x00,0xff,0xff,0x00,0xdb] #CHECK: alghsik %r0, %r0, 0 # encoding: [0xec,0x00,0x00,0x00,0x00,0xdb] -- cgit v1.1