diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h index 17e0e87b91f..97e325b984f 100644 --- a/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h @@ -62,6 +62,11 @@ namespace SystemZMC { inline unsigned getRegAsGR32(unsigned Reg) { return GR32Regs[getFirstReg(Reg)]; } + + // Return the given register as a high GR32. + inline unsigned getRegAsGRH32(unsigned Reg) { + return GRH32Regs[getFirstReg(Reg)]; + } } MCCodeEmitter *createSystemZMCCodeEmitter(const MCInstrInfo &MCII, diff --git a/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/lib/Target/SystemZ/SystemZAsmPrinter.cpp index 9ad5c8bdc66..0a89a96862e 100644 --- a/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ b/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -82,6 +82,12 @@ void SystemZAsmPrinter::EmitInstruction(const MachineInstr *MI) { .addImm(MI->getOperand(2).getImm()); break; + case SystemZ::IIHF64: + LoweredMI = MCInstBuilder(SystemZ::IIHF) + .addReg(SystemZMC::getRegAsGRH32(MI->getOperand(0).getReg())) + .addImm(MI->getOperand(2).getImm()); + break; + case SystemZ::RISBHH: case SystemZ::RISBHL: LoweredMI = lowerRIEfLow(MI, SystemZ::RISBHG); diff --git a/lib/Target/SystemZ/SystemZInstrFormats.td b/lib/Target/SystemZ/SystemZInstrFormats.td index 97a1578f174..c74091f5948 100644 --- a/lib/Target/SystemZ/SystemZInstrFormats.td +++ b/lib/Target/SystemZ/SystemZInstrFormats.td @@ -1349,6 +1349,12 @@ class Pseudo pattern> let isCodeGenOnly = 1; } +// Like UnaryRI, but expanded after RA depending on the choice of register. +class UnaryRIPseudo + : Pseudo<(outs cls:$R1), (ins imm:$I2), + [(set cls:$R1, (operator imm:$I2))]>; + // Like UnaryRXY, but expanded after RA depending on the choice of registers. class UnaryRXYPseudo bytes, diff --git a/lib/Target/SystemZ/SystemZInstrInfo.cpp b/lib/Target/SystemZ/SystemZInstrInfo.cpp index ede1eceb8c0..3abecf684dd 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ b/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -91,6 +91,22 @@ void SystemZInstrInfo::splitAdjDynAlloc(MachineBasicBlock::iterator MI) const { OffsetMO.setImm(Offset); } +// MI is an RI-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. ConvertHigh is true if LowOpcode takes a signed operand +// and HighOpcode takes an unsigned 32-bit operand. In those cases, +// MI has the same kind of operand as LowOpcode, so needs to be converted +// if HighOpcode is used. +void SystemZInstrInfo::expandRIPseudo(MachineInstr *MI, unsigned LowOpcode, + unsigned HighOpcode, + bool ConvertHigh) const { + unsigned Reg = MI->getOperand(0).getReg(); + bool IsHigh = isHighReg(Reg); + MI->setDesc(get(IsHigh ? HighOpcode : LowOpcode)); + if (IsHigh && ConvertHigh) + MI->getOperand(1).setImm(uint32_t(MI->getOperand(1).getImm())); +} + // 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. @@ -857,6 +873,14 @@ SystemZInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { expandRXYPseudo(MI, SystemZ::ST, SystemZ::STFH); return true; + case SystemZ::LHIMux: + expandRIPseudo(MI, SystemZ::LHI, SystemZ::IIHF, true); + return true; + + case SystemZ::IIFMux: + expandRIPseudo(MI, SystemZ::IILF, SystemZ::IIHF, false); + return true; + case SystemZ::ADJDYNALLOC: splitAdjDynAlloc(MI); return true; diff --git a/lib/Target/SystemZ/SystemZInstrInfo.h b/lib/Target/SystemZ/SystemZInstrInfo.h index 30f4c7dde44..06e677a9c32 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.h +++ b/lib/Target/SystemZ/SystemZInstrInfo.h @@ -116,6 +116,8 @@ class SystemZInstrInfo : public SystemZGenInstrInfo { void splitMove(MachineBasicBlock::iterator MI, unsigned NewOpcode) const; void splitAdjDynAlloc(MachineBasicBlock::iterator MI) const; + void expandRIPseudo(MachineInstr *MI, unsigned LowOpcode, + unsigned HighOpcode, bool ConvertHigh) 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 0ce016e9ef5..00229260f67 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -278,7 +278,10 @@ let Uses = [CC] in { // Immediate moves. let neverHasSideEffects = 1, isAsCheapAsAMove = 1, isMoveImm = 1, isReMaterializable = 1 in { - // 16-bit sign-extended immediates. + // 16-bit sign-extended immediates. LHIMux expands to LHI or IIHF, + // deopending on the choice of register. + def LHIMux : UnaryRIPseudo, + Requires<[FeatureHighWord]>; def LHI : UnaryRI<"lhi", 0xA78, bitconvert, GR32, imm32sx16>; def LGHI : UnaryRI<"lghi", 0xA79, bitconvert, GR64, imm64sx16>; @@ -636,16 +639,20 @@ def IIHH : BinaryRI<"iihh", 0xA50, inserthh, GR64, imm64hh16>; // full-width move. (We use IILF rather than something like LLILF // for 32-bit moves because IILF leaves the upper 32 bits of the // GR64 unchanged.) -let isAsCheapAsAMove = 1, isMoveImm = 1, isReMaterializable = 1 in +let isAsCheapAsAMove = 1, isMoveImm = 1, isReMaterializable = 1 in { + def IIFMux : UnaryRIPseudo, + Requires<[FeatureHighWord]>; def IILF : UnaryRIL<"iilf", 0xC09, bitconvert, GR32, uimm32>; + def IIHF : UnaryRIL<"iihf", 0xC08, bitconvert, GRH32, uimm32>; +} def IILF64 : BinaryAliasRIL; -def IIHF : BinaryRIL<"iihf", 0xC08, inserthf, GR64, imm64hf32>; +def IIHF64 : BinaryAliasRIL; // An alternative model of inserthf, with the first operand being // a zero-extended value. def : Pat<(or (zext32 GR32:$src), imm64hf32:$imm), - (IIHF (INSERT_SUBREG (i64 (IMPLICIT_DEF)), GR32:$src, subreg_l32), - imm64hf32:$imm)>; + (IIHF64 (INSERT_SUBREG (i64 (IMPLICIT_DEF)), GR32:$src, subreg_l32), + imm64hf32:$imm)>; //===----------------------------------------------------------------------===// // Addition diff --git a/lib/Target/SystemZ/SystemZShortenInst.cpp b/lib/Target/SystemZ/SystemZShortenInst.cpp index b4808646717..537a5455404 100644 --- a/lib/Target/SystemZ/SystemZShortenInst.cpp +++ b/lib/Target/SystemZ/SystemZShortenInst.cpp @@ -58,6 +58,7 @@ SystemZShortenInst::SystemZShortenInst(const SystemZTargetMachine &tm) for (unsigned I = 0; I < 16; ++I) { LowGPRs[SystemZMC::GR32Regs[I]] |= 1 << I; LowGPRs[SystemZMC::GR64Regs[I]] |= 1 << I; + HighGPRs[SystemZMC::GRH32Regs[I]] |= 1 << I; HighGPRs[SystemZMC::GR64Regs[I]] |= 1 << I; if (unsigned GR128 = SystemZMC::GR128Regs[I]) { LowGPRs[GR128] |= 3 << I; @@ -122,6 +123,9 @@ bool SystemZShortenInst::processBlock(MachineBasicBlock *MBB) { if (Opcode == SystemZ::IILF) Changed |= shortenIIF(MI, LowGPRs, LiveHigh, SystemZ::LLILL, SystemZ::LLILH); + else if (Opcode == SystemZ::IIHF) + Changed |= shortenIIF(MI, HighGPRs, LiveLow, SystemZ::LLIHL, + SystemZ::LLIHH); unsigned UsedLow = 0; unsigned UsedHigh = 0; for (MachineInstr::mop_iterator MOI = MI.operands_begin(), diff --git a/test/CodeGen/SystemZ/asm-18.ll b/test/CodeGen/SystemZ/asm-18.ll index c2f80d9de47..e7e171e80bf 100644 --- a/test/CodeGen/SystemZ/asm-18.ll +++ b/test/CodeGen/SystemZ/asm-18.ll @@ -230,3 +230,60 @@ define i32 @f10(i16 %val1, i16 %val2) { %ext4 = zext i16 %val4 to i32 ret i32 %ext4 } + +; Test loads of 16-bit constants into mixtures of high and low registers. +define void @f11() { +; CHECK-LABEL: f11: +; CHECK-DAG: iihf [[REG1:%r[0-5]]], 4294934529 +; CHECK-DAG: lhi [[REG2:%r[0-5]]], -32768 +; CHECK-DAG: llihl [[REG3:%r[0-5]]], 32766 +; CHECK-DAG: lhi [[REG4:%r[0-5]]], 32767 +; CHECK: blah [[REG1]], [[REG2]], [[REG3]], [[REG4]] +; CHECK: br %r14 + call void asm sideeffect "blah $0, $1, $2, $3", + "h,r,h,r"(i32 -32767, i32 -32768, + i32 32766, i32 32767) + ret void +} + +; Test loads of unsigned constants into mixtures of high and low registers. +; For stepc, we expect the h and r operands to be paired by the register +; allocator. It doesn't really matter which comes first: LLILL/IIHF would +; be just as good. +define void @f12() { +; CHECK-LABEL: f12: +; CHECK-DAG: llihl [[REG1:%r[0-5]]], 32768 +; CHECK-DAG: llihl [[REG2:%r[0-5]]], 65535 +; CHECK-DAG: llihh [[REG3:%r[0-5]]], 1 +; CHECK-DAG: llihh [[REG4:%r[0-5]]], 65535 +; CHECK: stepa [[REG1]], [[REG2]], [[REG3]], [[REG4]] +; CHECK-DAG: llill [[REG1:%r[0-5]]], 32769 +; CHECK-DAG: llill [[REG2:%r[0-5]]], 65534 +; CHECK-DAG: llilh [[REG3:%r[0-5]]], 2 +; CHECK-DAG: llilh [[REG4:%r[0-5]]], 65534 +; CHECK: stepb [[REG1]], [[REG2]], [[REG3]], [[REG4]] +; CHECK-DAG: llihl [[REG1:%r[0-5]]], 32770 +; CHECK-DAG: iilf [[REG1]], 65533 +; CHECK-DAG: llihh [[REG2:%r[0-5]]], 4 +; CHECK-DAG: iilf [[REG2]], 524288 +; CHECK: stepc [[REG1]], [[REG1]], [[REG2]], [[REG2]] +; CHECK-DAG: iihf [[REG1:%r[0-5]]], 3294967296 +; CHECK-DAG: iilf [[REG2:%r[0-5]]], 4294567296 +; CHECK-DAG: iihf [[REG3:%r[0-5]]], 1000000000 +; CHECK-DAG: iilf [[REG4:%r[0-5]]], 400000 +; CHECK: stepd [[REG1]], [[REG2]], [[REG3]], [[REG4]] +; CHECK: br %r14 + call void asm sideeffect "stepa $0, $1, $2, $3", + "h,h,h,h"(i32 32768, i32 65535, + i32 65536, i32 -65536) + call void asm sideeffect "stepb $0, $1, $2, $3", + "r,r,r,r"(i32 32769, i32 65534, + i32 131072, i32 -131072) + call void asm sideeffect "stepc $0, $1, $2, $3", + "h,r,h,r"(i32 32770, i32 65533, + i32 262144, i32 524288) + call void asm sideeffect "stepd $0, $1, $2, $3", + "h,r,h,r"(i32 -1000000000, i32 -400000, + i32 1000000000, i32 400000) + ret void +}