[SystemZ] Allow integer AND involving high words

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191762 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Sandiford 2013-10-01 14:20:41 +00:00
parent 1ff62e182e
commit b9dcca8265
6 changed files with 170 additions and 63 deletions

View File

@ -127,6 +127,9 @@ void SystemZAsmPrinter::EmitInstruction(const MachineInstr *MI) {
LOWER_HIGH(IIHL);
LOWER_HIGH(IIHH);
LOWER_HIGH(NIHL);
LOWER_HIGH(NIHH);
LOWER_HIGH(NIHF);
LOWER_HIGH(OIHL);
LOWER_HIGH(OIHH);
LOWER_HIGH(OIHF);

View File

@ -2963,14 +2963,14 @@ EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const {
return emitAtomicLoadBinary(MI, MBB, SystemZ::NILL64, 64);
case SystemZ::ATOMIC_LOAD_NILH64:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NILH64, 64);
case SystemZ::ATOMIC_LOAD_NIHL:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHL, 64);
case SystemZ::ATOMIC_LOAD_NIHH:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHH, 64);
case SystemZ::ATOMIC_LOAD_NIHL64:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHL64, 64);
case SystemZ::ATOMIC_LOAD_NIHH64:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHH64, 64);
case SystemZ::ATOMIC_LOAD_NILF64:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NILF64, 64);
case SystemZ::ATOMIC_LOAD_NIHF:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHF, 64);
case SystemZ::ATOMIC_LOAD_NIHF64:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHF64, 64);
case SystemZ::ATOMIC_LOADW_OR:
return emitAtomicLoadBinary(MI, MBB, SystemZ::OR, 0);
@ -3032,14 +3032,14 @@ EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const {
return emitAtomicLoadBinary(MI, MBB, SystemZ::NILL64, 64, true);
case SystemZ::ATOMIC_LOAD_NILH64i:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NILH64, 64, true);
case SystemZ::ATOMIC_LOAD_NIHLi:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHL, 64, true);
case SystemZ::ATOMIC_LOAD_NIHHi:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHH, 64, true);
case SystemZ::ATOMIC_LOAD_NIHL64i:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHL64, 64, true);
case SystemZ::ATOMIC_LOAD_NIHH64i:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHH64, 64, true);
case SystemZ::ATOMIC_LOAD_NILF64i:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NILF64, 64, true);
case SystemZ::ATOMIC_LOAD_NIHFi:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHF, 64, true);
case SystemZ::ATOMIC_LOAD_NIHF64i:
return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHF64, 64, true);
case SystemZ::ATOMIC_LOADW_MIN:
return emitAtomicLoadMinMax(MI, MBB, SystemZ::CR,

View File

@ -1397,6 +1397,16 @@ class StoreRXYPseudo<SDPatternOperator operator, RegisterOperand cls,
let AccessBytes = bytes;
}
// Like RotateSelectRIEf, but expanded after RA depending on the choice
// of registers.
class RotateSelectRIEfPseudo<RegisterOperand cls1, RegisterOperand cls2>
: Pseudo<(outs cls1:$R1),
(ins cls1:$R1src, cls2:$R2, uimm8:$I3, uimm8:$I4, uimm8zx6:$I5),
[]> {
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
}
// Implements "$dst = $cc & (8 >> CC) ? $src1 : $src2", where CC is
// the value of the PSW's 2-bit condition code field.
class SelectWrapper<RegisterOperand cls>

View File

@ -616,15 +616,15 @@ namespace {
static LogicOp interpretAndImmediate(unsigned Opcode) {
switch (Opcode) {
case SystemZ::NILL: return LogicOp(32, 0, 16);
case SystemZ::NILH: return LogicOp(32, 16, 16);
case SystemZ::NILMux: return LogicOp(32, 0, 16);
case SystemZ::NIHMux: return LogicOp(32, 16, 16);
case SystemZ::NILL64: return LogicOp(64, 0, 16);
case SystemZ::NILH64: return LogicOp(64, 16, 16);
case SystemZ::NIHL: return LogicOp(64, 32, 16);
case SystemZ::NIHH: return LogicOp(64, 48, 16);
case SystemZ::NILF: return LogicOp(32, 0, 32);
case SystemZ::NIHL64: return LogicOp(64, 32, 16);
case SystemZ::NIHH64: return LogicOp(64, 48, 16);
case SystemZ::NIFMux: return LogicOp(32, 0, 32);
case SystemZ::NILF64: return LogicOp(64, 0, 32);
case SystemZ::NIHF: return LogicOp(64, 32, 32);
case SystemZ::NIHF64: return LogicOp(64, 32, 32);
default: return LogicOp();
}
}
@ -678,34 +678,27 @@ SystemZInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
// Try to convert an AND into an RISBG-type instruction.
if (LogicOp And = interpretAndImmediate(Opcode)) {
unsigned NewOpcode;
if (And.RegSize == 64)
NewOpcode = SystemZ::RISBG;
else if (TM.getSubtargetImpl()->hasHighWord())
NewOpcode = SystemZ::RISBLL;
else
// We can't use RISBG for 32-bit operations because it clobbers the
// high word of the destination too.
NewOpcode = 0;
if (NewOpcode) {
uint64_t Imm = MI->getOperand(2).getImm() << And.ImmLSB;
// AND IMMEDIATE leaves the other bits of the register unchanged.
Imm |= allOnes(And.RegSize) & ~(allOnes(And.ImmSize) << And.ImmLSB);
unsigned Start, End;
if (isRxSBGMask(Imm, And.RegSize, Start, End)) {
if (NewOpcode == SystemZ::RISBLL) {
Start &= 31;
End &= 31;
}
MachineOperand &Dest = MI->getOperand(0);
MachineOperand &Src = MI->getOperand(1);
MachineInstrBuilder MIB =
BuildMI(*MBB, MI, MI->getDebugLoc(), get(NewOpcode))
.addOperand(Dest).addReg(0)
.addReg(Src.getReg(), getKillRegState(Src.isKill()), Src.getSubReg())
.addImm(Start).addImm(End + 128).addImm(0);
return finishConvertToThreeAddress(MI, MIB, LV);
uint64_t Imm = MI->getOperand(2).getImm() << And.ImmLSB;
// AND IMMEDIATE leaves the other bits of the register unchanged.
Imm |= allOnes(And.RegSize) & ~(allOnes(And.ImmSize) << And.ImmLSB);
unsigned Start, End;
if (isRxSBGMask(Imm, And.RegSize, Start, End)) {
unsigned NewOpcode;
if (And.RegSize == 64)
NewOpcode = SystemZ::RISBG;
else {
NewOpcode = SystemZ::RISBMux;
Start &= 31;
End &= 31;
}
MachineOperand &Dest = MI->getOperand(0);
MachineOperand &Src = MI->getOperand(1);
MachineInstrBuilder MIB =
BuildMI(*MBB, MI, MI->getDebugLoc(), get(NewOpcode))
.addOperand(Dest).addReg(0)
.addReg(Src.getReg(), getKillRegState(Src.isKill()), Src.getSubReg())
.addImm(Start).addImm(End + 128).addImm(0);
return finishConvertToThreeAddress(MI, MIB, LV);
}
}
return 0;
@ -889,6 +882,18 @@ SystemZInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const {
expandRIPseudo(MI, SystemZ::IILH, SystemZ::IIHH, false);
return true;
case SystemZ::NIFMux:
expandRIPseudo(MI, SystemZ::NILF, SystemZ::NIHF, false);
return true;
case SystemZ::NILMux:
expandRIPseudo(MI, SystemZ::NILL, SystemZ::NIHL, false);
return true;
case SystemZ::NIHMux:
expandRIPseudo(MI, SystemZ::NILH, SystemZ::NIHH, false);
return true;
case SystemZ::OIFMux:
expandRIPseudo(MI, SystemZ::OILF, SystemZ::OIHF, false);
return true;
@ -905,6 +910,18 @@ SystemZInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const {
expandRIPseudo(MI, SystemZ::XILF, SystemZ::XIHF, false);
return true;
case SystemZ::RISBMux: {
bool DestIsHigh = isHighReg(MI->getOperand(0).getReg());
bool SrcIsHigh = isHighReg(MI->getOperand(2).getReg());
if (SrcIsHigh == DestIsHigh)
MI->setDesc(get(DestIsHigh ? SystemZ::RISBHH : SystemZ::RISBLL));
else {
MI->setDesc(get(DestIsHigh ? SystemZ::RISBHL : SystemZ::RISBLH));
MI->getOperand(5).setImm(MI->getOperand(5).getImm() ^ 32);
}
return true;
}
case SystemZ::ADJDYNALLOC:
splitAdjDynAlloc(MI);
return true;

View File

@ -797,20 +797,33 @@ let Defs = [CC] in {
let isConvertibleToThreeAddress = 1 in {
// ANDs of a 16-bit immediate, leaving other bits unaffected.
// The CC result only reflects the 16-bit field, not the full register.
//
// NIxMux expands to NI[LH]x, depending on the choice of register.
def NILMux : BinaryRIPseudo<and, GRX32, imm32ll16c>,
Requires<[FeatureHighWord]>;
def NIHMux : BinaryRIPseudo<and, GRX32, imm32lh16c>,
Requires<[FeatureHighWord]>;
def NILL : BinaryRI<"nill", 0xA57, and, GR32, imm32ll16c>;
def NILH : BinaryRI<"nilh", 0xA56, and, GR32, imm32lh16c>;
def NIHL : BinaryRI<"nihl", 0xA55, and, GRH32, imm32ll16c>;
def NIHH : BinaryRI<"nihh", 0xA54, and, GRH32, imm32lh16c>;
def NILL64 : BinaryAliasRI<and, GR64, imm64ll16c>;
def NILH64 : BinaryAliasRI<and, GR64, imm64lh16c>;
def NIHL : BinaryRI<"nihl", 0xA55, and, GR64, imm64hl16c>;
def NIHH : BinaryRI<"nihh", 0xA54, and, GR64, imm64hh16c>;
def NIHL64 : BinaryAliasRI<and, GR64, imm64hl16c>;
def NIHH64 : BinaryAliasRI<and, GR64, imm64hh16c>;
// ANDs of a 32-bit immediate, leaving other bits unaffected.
// The CC result only reflects the 32-bit field, which means we can
// use it as a zero indicator for i32 operations but not otherwise.
let CCValues = 0xC, CompareZeroCCMask = 0x8 in
let CCValues = 0xC, CompareZeroCCMask = 0x8 in {
// Expands to NILF or NIHF, depending on the choice of register.
def NIFMux : BinaryRIPseudo<and, GRX32, uimm32>,
Requires<[FeatureHighWord]>;
def NILF : BinaryRIL<"nilf", 0xC0B, and, GR32, uimm32>;
def NIHF : BinaryRIL<"nihf", 0xC0A, and, GRH32, uimm32>;
}
def NILF64 : BinaryAliasRIL<and, GR64, imm64lf32c>;
def NIHF : BinaryRIL<"nihf", 0xC0A, and, GR64, imm64hf32c>;
def NIHF64 : BinaryAliasRIL<and, GR64, imm64hf32c>;
}
// ANDs of memory.
@ -1014,14 +1027,15 @@ let Defs = [CC] in {
// Forms of RISBG that only affect one word of the destination register.
// They do not set CC.
def RISBLL : RotateSelectAliasRIEf<GR32, GR32>, Requires<[FeatureHighWord]>;
def RISBLH : RotateSelectAliasRIEf<GR32, GRH32>, Requires<[FeatureHighWord]>;
def RISBHL : RotateSelectAliasRIEf<GRH32, GR32>, Requires<[FeatureHighWord]>;
def RISBHH : RotateSelectAliasRIEf<GRH32, GRH32>, Requires<[FeatureHighWord]>;
def RISBLG : RotateSelectRIEf<"risblg", 0xEC51, GR32, GR64>,
Requires<[FeatureHighWord]>;
def RISBHG : RotateSelectRIEf<"risbhg", 0xEC5D, GRH32, GR64>,
Requires<[FeatureHighWord]>;
def RISBMux : RotateSelectRIEfPseudo<GRX32, GRX32>, Requires<[FeatureHighWord]>;
def RISBLL : RotateSelectAliasRIEf<GR32, GR32>, Requires<[FeatureHighWord]>;
def RISBLH : RotateSelectAliasRIEf<GR32, GRH32>, Requires<[FeatureHighWord]>;
def RISBHL : RotateSelectAliasRIEf<GRH32, GR32>, Requires<[FeatureHighWord]>;
def RISBHH : RotateSelectAliasRIEf<GRH32, GRH32>, Requires<[FeatureHighWord]>;
def RISBLG : RotateSelectRIEf<"risblg", 0xEC51, GR32, GR64>,
Requires<[FeatureHighWord]>;
def RISBHG : RotateSelectRIEf<"risbhg", 0xEC5D, GRH32, GR64>,
Requires<[FeatureHighWord]>;
// Rotate second operand left and perform a logical operation with selected
// bits of the first operand. The CC result only describes the selected bits,
@ -1166,10 +1180,10 @@ def ATOMIC_LOAD_NILF : AtomicLoadBinaryImm32<atomic_load_and_32, uimm32>;
def ATOMIC_LOAD_NGR : AtomicLoadBinaryReg64<atomic_load_and_64>;
def ATOMIC_LOAD_NILL64 : AtomicLoadBinaryImm64<atomic_load_and_64, imm64ll16c>;
def ATOMIC_LOAD_NILH64 : AtomicLoadBinaryImm64<atomic_load_and_64, imm64lh16c>;
def ATOMIC_LOAD_NIHL : AtomicLoadBinaryImm64<atomic_load_and_64, imm64hl16c>;
def ATOMIC_LOAD_NIHH : AtomicLoadBinaryImm64<atomic_load_and_64, imm64hh16c>;
def ATOMIC_LOAD_NIHL64 : AtomicLoadBinaryImm64<atomic_load_and_64, imm64hl16c>;
def ATOMIC_LOAD_NIHH64 : AtomicLoadBinaryImm64<atomic_load_and_64, imm64hh16c>;
def ATOMIC_LOAD_NILF64 : AtomicLoadBinaryImm64<atomic_load_and_64, imm64lf32c>;
def ATOMIC_LOAD_NIHF : AtomicLoadBinaryImm64<atomic_load_and_64, imm64hf32c>;
def ATOMIC_LOAD_NIHF64 : AtomicLoadBinaryImm64<atomic_load_and_64, imm64hf32c>;
def ATOMIC_LOADW_OR : AtomicLoadWBinaryReg<z_atomic_loadw_or>;
def ATOMIC_LOADW_OILH : AtomicLoadWBinaryImm<z_atomic_loadw_or, imm32lh16>;
@ -1207,13 +1221,13 @@ def ATOMIC_LOAD_NILL64i : AtomicLoadBinaryImm64<atomic_load_nand_64,
imm64ll16c>;
def ATOMIC_LOAD_NILH64i : AtomicLoadBinaryImm64<atomic_load_nand_64,
imm64lh16c>;
def ATOMIC_LOAD_NIHLi : AtomicLoadBinaryImm64<atomic_load_nand_64,
def ATOMIC_LOAD_NIHL64i : AtomicLoadBinaryImm64<atomic_load_nand_64,
imm64hl16c>;
def ATOMIC_LOAD_NIHHi : AtomicLoadBinaryImm64<atomic_load_nand_64,
def ATOMIC_LOAD_NIHH64i : AtomicLoadBinaryImm64<atomic_load_nand_64,
imm64hh16c>;
def ATOMIC_LOAD_NILF64i : AtomicLoadBinaryImm64<atomic_load_nand_64,
imm64lf32c>;
def ATOMIC_LOAD_NIHFi : AtomicLoadBinaryImm64<atomic_load_nand_64,
def ATOMIC_LOAD_NIHF64i : AtomicLoadBinaryImm64<atomic_load_nand_64,
imm64hf32c>;
def ATOMIC_LOADW_MIN : AtomicLoadWBinaryReg<z_atomic_loadw_min>;

View File

@ -437,3 +437,66 @@ define void @f20() {
call void asm sideeffect "stepd $0", "r"(i32 %xor3)
ret void
}
; Test two-operand immediate AND involving high registers.
define void @f21() {
; CHECK-LABEL: f21:
; CHECK: stepa [[REG:%r[0-5]]]
; CHECK: nihh [[REG]], 4096
; CHECK: stepb [[REG]]
; CHECK: nihl [[REG]], 57536
; CHECK: stepc [[REG]]
; CHECK: nihf [[REG]], 12345678
; CHECK: stepd [[REG]]
; CHECK: br %r14
%res1 = call i32 asm "stepa $0", "=h"()
%and1 = and i32 %res1, 268500991
%res2 = call i32 asm "stepb $0, $1", "=h,h"(i32 %and1)
%and2 = and i32 %res2, -8000
%res3 = call i32 asm "stepc $0, $1", "=h,h"(i32 %and2)
%and3 = and i32 %res3, 12345678
call void asm sideeffect "stepd $0", "h"(i32 %and3)
ret void
}
; Test two-operand immediate AND involving low registers.
define void @f22() {
; CHECK-LABEL: f22:
; CHECK: stepa [[REG:%r[0-5]]]
; CHECK: nilh [[REG]], 4096
; CHECK: stepb [[REG]]
; CHECK: nill [[REG]], 57536
; CHECK: stepc [[REG]]
; CHECK: nilf [[REG]], 12345678
; CHECK: stepd [[REG]]
; CHECK: br %r14
%res1 = call i32 asm "stepa $0", "=r"()
%and1 = and i32 %res1, 268500991
%res2 = call i32 asm "stepb $0, $1", "=r,r"(i32 %and1)
%and2 = and i32 %res2, -8000
%res3 = call i32 asm "stepc $0, $1", "=r,r"(i32 %and2)
%and3 = and i32 %res3, 12345678
call void asm sideeffect "stepd $0", "r"(i32 %and3)
ret void
}
; Test three-operand immediate AND involving mixtures of low and high registers.
define i32 @f23(i32 %old) {
; CHECK-LABEL: f23:
; CHECK-DAG: risblg [[REG1:%r[0-5]]], %r2, 28, 158, 0
; CHECK-DAG: risbhg [[REG2:%r[0-5]]], %r2, 24, 158, 32
; CHECK: stepa %r2, [[REG1]], [[REG2]]
; CHECK-DAG: risbhg [[REG3:%r[0-5]]], [[REG2]], 25, 159, 0
; CHECK-DAG: risblg %r2, [[REG2]], 24, 152, 32
; CHECK: stepb [[REG2]], [[REG3]], %r2
; CHECK: br %r14
%and1 = and i32 %old, 14
%and2 = and i32 %old, 254
%res1 = call i32 asm "stepa $1, $2, $3",
"=h,r,r,0"(i32 %old, i32 %and1, i32 %and2)
%and3 = and i32 %res1, 127
%and4 = and i32 %res1, 128
%res2 = call i32 asm "stepb $1, $2, $3",
"=r,h,h,0"(i32 %res1, i32 %and3, i32 %and4)
ret i32 %res2
}