[SystemZ] Add TM and TMY
The main complication here is that TM and TMY (the memory forms) set
CC differently from the register forms. When the tested bits contain
some 0s and some 1s, the register forms set CC to 1 or 2 based on the
value the uppermost bit. The memory forms instead set CC to 1
regardless of the uppermost bit.
Until now, I've tried to make it so that a branch never tests for an
impossible CC value. E.g. NR only sets CC to 0 or 1, so branches on the
result will only test for 0 or 1. Originally I'd tried to do the same
thing for TM and TMY by using custom matching code in ISelDAGToDAG.
That ended up being very ugly though, and would have meant duplicating
some of the chain checks that the common isel code does.
I've therefore gone for the simpler alternative of adding an extra
operand to the TM DAG opcode to say whether a memory form would be OK.
This means that the inverse of a "TM;JE" is "TM;JNE" rather than the
more precise "TM;JNLE", just like the inverse of "TMLL;JE" is "TMLL;JNE".
I suppose that's arguably less confusing though...
llvm-svn: 190400
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 9fc56fe..5528404 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -1226,13 +1226,13 @@
return 0;
}
-// See whether the comparison (Opcode CmpOp0, CmpOp1) can be implemented
-// as a TEST UNDER MASK instruction when the condition being tested is
-// as described by CCValid and CCMask. Update the arguments with the
-// TM version if so.
+// See whether the comparison (Opcode CmpOp0, CmpOp1, ICmpType) can be
+// implemented as a TEST UNDER MASK instruction when the condition being
+// tested is as described by CCValid and CCMask. Update the arguments
+// with the TM version if so.
static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0,
SDValue &CmpOp1, unsigned &CCValid,
- unsigned &CCMask, unsigned ICmpType) {
+ unsigned &CCMask, unsigned &ICmpType) {
// Check that we have a comparison with a constant.
ConstantSDNode *ConstCmpOp1 = dyn_cast<ConstantSDNode>(CmpOp1);
if (!ConstCmpOp1)
@@ -1266,6 +1266,8 @@
Opcode = SystemZISD::TM;
CmpOp0 = AndOp0;
CmpOp1 = AndOp1;
+ ICmpType = (bool(NewCCMask & SystemZ::CCMASK_TM_MIXED_MSB_0) !=
+ bool(NewCCMask & SystemZ::CCMASK_TM_MIXED_MSB_1));
CCValid = SystemZ::CCMASK_TM;
CCMask = NewCCMask;
}
@@ -1315,7 +1317,7 @@
}
adjustForTestUnderMask(Opcode, CmpOp0, CmpOp1, CCValid, CCMask, ICmpType);
- if (Opcode == SystemZISD::ICMP)
+ if (Opcode == SystemZISD::ICMP || Opcode == SystemZISD::TM)
return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1,
DAG.getConstant(ICmpType, MVT::i32));
return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1);
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index 500abce..9822463 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -46,7 +46,10 @@
FCMP,
// Test under mask. The first operand is ANDed with the second operand
- // and the condition codes are set on the result.
+ // and the condition codes are set on the result. The third operand is
+ // a boolean that is true if the condition codes need to distinguish
+ // between CCMASK_TM_MIXED_MSB_0 and CCMASK_TM_MIXED_MSB_1 (which the
+ // register forms do but the memory forms don't).
TM,
// Branches if a condition is true. Operand 0 is the chain operand;
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 5bfa06d..32b70b9 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -1037,14 +1037,16 @@
// Test under mask.
let Defs = [CC] in {
let isCodeGenOnly = 1 in {
- def TMLL32 : CompareRI<"tmll", 0xA71, z_tm, GR32, imm32ll16>;
- def TMLH32 : CompareRI<"tmlh", 0xA70, z_tm, GR32, imm32lh16>;
+ def TMLL32 : CompareRI<"tmll", 0xA71, z_tm_reg, GR32, imm32ll16>;
+ def TMLH32 : CompareRI<"tmlh", 0xA70, z_tm_reg, GR32, imm32lh16>;
}
- def TMLL : CompareRI<"tmll", 0xA71, z_tm, GR64, imm64ll16>;
- def TMLH : CompareRI<"tmlh", 0xA70, z_tm, GR64, imm64lh16>;
- def TMHL : CompareRI<"tmhl", 0xA73, z_tm, GR64, imm64hl16>;
- def TMHH : CompareRI<"tmhh", 0xA72, z_tm, GR64, imm64hh16>;
+ def TMLL : CompareRI<"tmll", 0xA71, z_tm_reg, GR64, imm64ll16>;
+ def TMLH : CompareRI<"tmlh", 0xA70, z_tm_reg, GR64, imm64lh16>;
+ def TMHL : CompareRI<"tmhl", 0xA73, z_tm_reg, GR64, imm64hl16>;
+ def TMHH : CompareRI<"tmhh", 0xA72, z_tm_reg, GR64, imm64hh16>;
+
+ defm TM : CompareSIPair<"tm", 0x91, 0xEB51, z_tm_mem, anyextloadi8, imm32zx8>;
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index c135b3b..4a6b665 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -99,7 +99,7 @@
def z_pcrel_wrapper : SDNode<"SystemZISD::PCREL_WRAPPER", SDT_ZWrapPtr, []>;
def z_icmp : SDNode<"SystemZISD::ICMP", SDT_ZICmp, [SDNPOutGlue]>;
def z_fcmp : SDNode<"SystemZISD::FCMP", SDT_ZCmp, [SDNPOutGlue]>;
-def z_tm : SDNode<"SystemZISD::TM", SDT_ZCmp, [SDNPOutGlue]>;
+def z_tm : SDNode<"SystemZISD::TM", SDT_ZICmp, [SDNPOutGlue]>;
def z_br_ccmask : SDNode<"SystemZISD::BR_CCMASK", SDT_ZBRCCMask,
[SDNPHasChain, SDNPInGlue]>;
def z_select_ccmask : SDNode<"SystemZISD::SELECT_CCMASK", SDT_ZSelectCCMask,
@@ -176,6 +176,10 @@
return Type != SystemZICMP::SignedOnly;
}]>;
+// Register- and memory-based TEST UNDER MASK.
+def z_tm_reg : PatFrag<(ops node:$a, node:$b), (z_tm node:$a, node:$b, imm)>;
+def z_tm_mem : PatFrag<(ops node:$a, node:$b), (z_tm node:$a, node:$b, 0)>;
+
// Register sign-extend operations. Sub-32-bit values are represented as i32s.
def sext8 : PatFrag<(ops node:$src), (sext_inreg node:$src, i8)>;
def sext16 : PatFrag<(ops node:$src), (sext_inreg node:$src, i16)>;