[SystemZ] Add remaining branch instructions
This patch adds assembler support for the remaining branch instructions:
the non-relative branch on count variants, and all variants of branch
on index.
The only one of those that can be readily exploited for code generation
is BRCTH (branch on count using a high 32-bit register as count). Do
use it, however, it is necessary to also introduce a hew CHIMux pseudo
to allow comparisons of a 32-bit value agains a short immediate to go
into a high register as well (implemented via CHI/CIH).
This causes a bit of codegen changes overall, but those have proven to
be neutral (or even beneficial) in performance measurements.
llvm-svn: 288029
diff --git a/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp b/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
index 6b07c54..b292b55 100644
--- a/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
@@ -171,7 +171,7 @@
// Compare compares the result of MI against zero. If MI is an addition
// of -1 and if CCUsers is a single branch on nonzero, eliminate the addition
-// and convert the branch to a BRCT(G). Return true on success.
+// and convert the branch to a BRCT(G) or BRCTH. Return true on success.
bool SystemZElimCompare::convertToBRCT(
MachineInstr &MI, MachineInstr &Compare,
SmallVectorImpl<MachineInstr *> &CCUsers) {
@@ -182,6 +182,8 @@
BRCT = SystemZ::BRCT;
else if (Opcode == SystemZ::AGHI)
BRCT = SystemZ::BRCTG;
+ else if (Opcode == SystemZ::AIH)
+ BRCT = SystemZ::BRCTH;
else
return false;
if (MI.getOperand(2).getImm() != -1)
@@ -205,16 +207,20 @@
if (getRegReferences(*MBBI, SrcReg))
return false;
- // The transformation is OK. Rebuild Branch as a BRCT(G).
+ // The transformation is OK. Rebuild Branch as a BRCT(G) or BRCTH.
MachineOperand Target(Branch->getOperand(2));
while (Branch->getNumOperands())
Branch->RemoveOperand(0);
Branch->setDesc(TII->get(BRCT));
- MachineInstrBuilder(*Branch->getParent()->getParent(), Branch)
- .addOperand(MI.getOperand(0))
- .addOperand(MI.getOperand(1))
- .addOperand(Target)
- .addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead);
+ MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch);
+ MIB.addOperand(MI.getOperand(0))
+ .addOperand(MI.getOperand(1))
+ .addOperand(Target);
+ // Add a CC def to BRCT(G), since we may have to split them again if the
+ // branch displacement overflows. BRCTH has a 32-bit displacement, so
+ // this is not necessary there.
+ if (BRCT != SystemZ::BRCTH)
+ MIB.addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead);
MI.eraseFromParent();
return true;
}
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrFormats.td b/llvm/lib/Target/SystemZ/SystemZInstrFormats.td
index 7a3aa40..a5c1c26 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrFormats.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrFormats.td
@@ -291,6 +291,23 @@
let Inst{7-0} = op{7-0};
}
+class InstRIEe<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<4> R1;
+ bits<4> R3;
+ bits<16> RI2;
+
+ let Inst{47-40} = op{15-8};
+ let Inst{39-36} = R1;
+ let Inst{35-32} = R3;
+ let Inst{31-16} = RI2;
+ let Inst{15-8} = 0;
+ let Inst{7-0} = op{7-0};
+}
+
class InstRIEf<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<6, outs, ins, asmstr, pattern> {
field bits<48> Inst;
@@ -1506,15 +1523,14 @@
// compares the two input operands and branches or traps on the result.
//
// BranchUnary:
-// One register output operand, one register input operand and
-// one branch displacement. The instructions stores a modified
-// form of the source register in the destination register and
-// branches on the result.
+// One register output operand, one register input operand and one branch
+// target. The instructions stores a modified form of the source register
+// in the destination register and branches on the result.
//
// BranchBinary:
// One register output operand, two register input operands and one branch
-// displacement. The instructions stores a modified form of one of the
-// source registers in the destination register and branches on the result.
+// target. The instructions stores a modified form of one of the source
+// registers in the destination register and branches on the result.
//
// LoadMultiple:
// One address input operand and two explicit output operands.
@@ -1911,6 +1927,41 @@
let DisableEncoding = "$R1src";
}
+class BranchUnaryRIL<string mnemonic, bits<12> opcode, RegisterOperand cls>
+ : InstRILb<opcode, (outs cls:$R1), (ins cls:$R1src, brtarget32:$RI2),
+ mnemonic##"\t$R1, $RI2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchUnaryRR<string mnemonic, bits<8> opcode, RegisterOperand cls>
+ : InstRR<opcode, (outs cls:$R1), (ins cls:$R1src, GR64:$R2),
+ mnemonic##"\t$R1, $R2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchUnaryRRE<string mnemonic, bits<16> opcode, RegisterOperand cls>
+ : InstRRE<opcode, (outs cls:$R1), (ins cls:$R1src, GR64:$R2),
+ mnemonic##"\t$R1, $R2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchUnaryRX<string mnemonic, bits<8> opcode, RegisterOperand cls>
+ : InstRXa<opcode, (outs cls:$R1), (ins cls:$R1src, bdxaddr12only:$XBD2),
+ mnemonic##"\t$R1, $XBD2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchUnaryRXY<string mnemonic, bits<16> opcode, RegisterOperand cls>
+ : InstRXYa<opcode, (outs cls:$R1), (ins cls:$R1src, bdxaddr20only:$XBD2),
+ mnemonic##"\t$R1, $XBD2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
class BranchBinaryRSI<string mnemonic, bits<8> opcode, RegisterOperand cls>
: InstRSI<opcode, (outs cls:$R1), (ins cls:$R1src, cls:$R3, brtarget16:$RI2),
mnemonic##"\t$R1, $R3, $RI2", []> {
@@ -1918,6 +1969,30 @@
let DisableEncoding = "$R1src";
}
+class BranchBinaryRIEe<string mnemonic, bits<16> opcode, RegisterOperand cls>
+ : InstRIEe<opcode, (outs cls:$R1),
+ (ins cls:$R1src, cls:$R3, brtarget16:$RI2),
+ mnemonic##"\t$R1, $R3, $RI2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchBinaryRS<string mnemonic, bits<8> opcode, RegisterOperand cls>
+ : InstRSa<opcode, (outs cls:$R1),
+ (ins cls:$R1src, cls:$R3, bdaddr12only:$BD2),
+ mnemonic##"\t$R1, $R3, $BD2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchBinaryRSY<string mnemonic, bits<16> opcode, RegisterOperand cls>
+ : InstRSYa<opcode,
+ (outs cls:$R1), (ins cls:$R1src, cls:$R3, bdaddr20only:$BD2),
+ mnemonic##"\t$R1, $R3, $BD2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
class LoadMultipleRS<string mnemonic, bits<8> opcode, RegisterOperand cls,
AddressingMode mode = bdaddr12only>
: InstRSa<opcode, (outs cls:$R1, cls:$R3), (ins mode:$BD2),
@@ -3639,7 +3714,9 @@
// Like CompareRI, but expanded after RA depending on the choice of register.
class CompareRIPseudo<SDPatternOperator operator, RegisterOperand cls,
Immediate imm>
- : Pseudo<(outs), (ins cls:$R1, imm:$I2), [(operator cls:$R1, imm:$I2)]>;
+ : Pseudo<(outs), (ins cls:$R1, imm:$I2), [(operator cls:$R1, imm:$I2)]> {
+ let isCompare = 1;
+}
// Like CompareRXY, but expanded after RA depending on the choice of register.
class CompareRXYPseudo<SDPatternOperator operator, RegisterOperand cls,
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 8f1b557..7b835b0 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1321,6 +1321,10 @@
expandRIPseudo(MI, SystemZ::AFI, SystemZ::AIH, false);
return true;
+ case SystemZ::CHIMux:
+ expandRIPseudo(MI, SystemZ::CHI, SystemZ::CIH, false);
+ return true;
+
case SystemZ::CFIMux:
expandRIPseudo(MI, SystemZ::CFI, SystemZ::CIH, false);
return true;
@@ -1386,6 +1390,7 @@
MI.getOperand(1).getImm(), &MI.getOperand(2));
case SystemZ::BRCT:
+ case SystemZ::BRCTH:
return SystemZII::Branch(SystemZII::BranchCT, SystemZ::CCMASK_ICMP,
SystemZ::CCMASK_CMP_NE, &MI.getOperand(2));
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 28c8557..87a70da 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -155,15 +155,33 @@
}
// Decrement a register and branch if it is nonzero. These don't clobber CC,
-// but we might need to split long branches into sequences that do.
-let isBranch = 1, isTerminator = 1, Defs = [CC] in {
- def BRCT : BranchUnaryRI<"brct", 0xA76, GR32>;
- def BRCTG : BranchUnaryRI<"brctg", 0xA77, GR64>;
+// but we might need to split long relative branches into sequences that do.
+let isBranch = 1, isTerminator = 1 in {
+ let Defs = [CC] in {
+ def BRCT : BranchUnaryRI<"brct", 0xA76, GR32>;
+ def BRCTG : BranchUnaryRI<"brctg", 0xA77, GR64>;
+ }
+ // This doesn't need to clobber CC since we never need to split it.
+ def BRCTH : BranchUnaryRIL<"brcth", 0xCC6, GRH32>,
+ Requires<[FeatureHighWord]>;
+
+ def BCT : BranchUnaryRX<"bct", 0x46,GR32>;
+ def BCTR : BranchUnaryRR<"bctr", 0x06, GR32>;
+ def BCTG : BranchUnaryRXY<"bctg", 0xE346, GR64>;
+ def BCTGR : BranchUnaryRRE<"bctgr", 0xB946, GR64>;
}
-let isBranch = 1, isTerminator = 1, Defs = [CC] in {
- def BRXH : BranchBinaryRSI<"brxh", 0x84, GR32>;
- def BRXLE : BranchBinaryRSI<"brxle", 0x85, GR32>;
+let isBranch = 1, isTerminator = 1 in {
+ let Defs = [CC] in {
+ def BRXH : BranchBinaryRSI<"brxh", 0x84, GR32>;
+ def BRXLE : BranchBinaryRSI<"brxle", 0x85, GR32>;
+ def BRXHG : BranchBinaryRIEe<"brxhg", 0xEC44, GR64>;
+ def BRXLG : BranchBinaryRIEe<"brxlg", 0xEC45, GR64>;
+ }
+ def BXH : BranchBinaryRS<"bxh", 0x86, GR32>;
+ def BXLE : BranchBinaryRS<"bxle", 0x87, GR32>;
+ def BXHG : BranchBinaryRSY<"bxhg", 0xEB44, GR64>;
+ def BXLEG : BranchBinaryRSY<"bxleg", 0xEB45, GR64>;
}
//===----------------------------------------------------------------------===//
@@ -1235,7 +1253,10 @@
def CGFR : CompareRRE<"cgfr", 0xB930, null_frag, GR64, GR32>;
def CGR : CompareRRE<"cgr", 0xB920, z_scmp, GR64, GR64>;
- // Comparison with a signed 16-bit immediate.
+ // Comparison with a signed 16-bit immediate. CHIMux expands to CHI or CIH,
+ // depending on the choice of register.
+ def CHIMux : CompareRIPseudo<z_scmp, GRX32, imm32sx16>,
+ Requires<[FeatureHighWord]>;
def CHI : CompareRI<"chi", 0xA7E, z_scmp, GR32, imm32sx16>;
def CGHI : CompareRI<"cghi", 0xA7F, z_scmp, GR64, imm64sx16>;
diff --git a/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp b/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
index 0be0396..14ff6af 100644
--- a/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
@@ -226,6 +226,10 @@
// Relaxes to A(G)HI and BRCL, which is 6 bytes longer.
Terminator.ExtraRelaxSize = 6;
break;
+ case SystemZ::BRCTH:
+ // Never needs to be relaxed.
+ Terminator.ExtraRelaxSize = 0;
+ break;
case SystemZ::CRJ:
case SystemZ::CLRJ:
// Relaxes to a C(L)R/BRCL sequence, which is 2 bytes longer.
diff --git a/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td b/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td
index 0030ed1..c9007e5 100644
--- a/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td
+++ b/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td
@@ -116,7 +116,10 @@
def : InstRW<[FXb], (instregex "(Call)?BC(R)?(Asm.*)?$")>;
def : InstRW<[FXb], (instregex "(Call)?B(R)?(Asm.*)?$")>;
def : InstRW<[FXa, EndGroup], (instregex "BRCT(G)?$")>;
-def : InstRW<[FXa, FXa, FXb, FXb, Lat4, GroupAlone], (instregex "BRX(H|LE)$")>;
+def : InstRW<[FXb, FXa, Lat2, GroupAlone], (instregex "BRCTH$")>;
+def : InstRW<[FXb, FXa, Lat2, GroupAlone], (instregex "BCT(G)?(R)?$")>;
+def : InstRW<[FXa, FXa, FXb, FXb, Lat4, GroupAlone],
+ (instregex "B(R)?X(H|L).*$")>;
// Compare and branch
def : InstRW<[FXb], (instregex "C(L)?(G)?(I|R)J(Asm.*)?$")>;
@@ -466,11 +469,11 @@
//===----------------------------------------------------------------------===//
def : InstRW<[FXb, LSU, Lat5], (instregex "C(G|Y|Mux|RL)?$")>;
-def : InstRW<[FXb], (instregex "CFI(Mux)?$")>;
+def : InstRW<[FXb], (instregex "C(F|H)I(Mux)?$")>;
def : InstRW<[FXb], (instregex "CG(F|H)I$")>;
def : InstRW<[FXb, LSU, Lat5], (instregex "CG(HSI|RL)$")>;
def : InstRW<[FXb], (instregex "C(G)?R$")>;
-def : InstRW<[FXb], (instregex "C(HI|IH)$")>;
+def : InstRW<[FXb], (instregex "CIH$")>;
def : InstRW<[FXb, LSU, Lat5], (instregex "CH(F|SI)$")>;
def : InstRW<[FXb, LSU, Lat5], (instregex "CL(Y|Mux|FHSI)?$")>;
def : InstRW<[FXb], (instregex "CLFI(Mux)?$")>;
diff --git a/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td b/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td
index 4d4a912..f8e0ccb 100644
--- a/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td
+++ b/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td
@@ -90,8 +90,10 @@
def : InstRW<[LSU, EndGroup], (instregex "(Call)?J(G)?(Asm.*)?$")>;
def : InstRW<[LSU, EndGroup], (instregex "(Call)?BC(R)?(Asm.*)?$")>;
def : InstRW<[LSU, EndGroup], (instregex "(Call)?B(R)?(Asm.*)?$")>;
-def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BRCT(G)?$")>;
-def : InstRW<[FXU, FXU, FXU, LSU, Lat7, GroupAlone], (instregex "BRX(H|LE)$")>;
+def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BRCT(G|H)?$")>;
+def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BCT(G)?(R)?$")>;
+def : InstRW<[FXU, FXU, FXU, LSU, Lat7, GroupAlone],
+ (instregex "B(R)?X(H|L).*$")>;
// Compare and branch
def : InstRW<[FXU, LSU, Lat5, GroupAlone],
@@ -433,11 +435,11 @@
//===----------------------------------------------------------------------===//
def : InstRW<[FXU, LSU, Lat5], (instregex "C(G|Y|Mux|RL)?$")>;
-def : InstRW<[FXU], (instregex "CFI(Mux)?$")>;
+def : InstRW<[FXU], (instregex "C(F|H)I(Mux)?$")>;
def : InstRW<[FXU], (instregex "CG(F|H)I$")>;
def : InstRW<[FXU, LSU, Lat5], (instregex "CG(HSI|RL)$")>;
def : InstRW<[FXU], (instregex "C(G)?R$")>;
-def : InstRW<[FXU], (instregex "C(HI|IH)$")>;
+def : InstRW<[FXU], (instregex "CIH$")>;
def : InstRW<[FXU, LSU, Lat5], (instregex "CH(F|SI)$")>;
def : InstRW<[FXU, LSU, Lat5], (instregex "CL(Y|Mux|FHSI)?$")>;
def : InstRW<[FXU], (instregex "CLFI(Mux)?$")>;
diff --git a/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td b/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td
index 69c70bb..7300874 100644
--- a/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td
+++ b/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td
@@ -93,7 +93,10 @@
def : InstRW<[LSU, Lat4], (instregex "(Call)?BC(R)?(Asm.*)?$")>;
def : InstRW<[LSU, Lat4], (instregex "(Call)?B(R)?(Asm.*)?$")>;
def : InstRW<[FXU, EndGroup], (instregex "BRCT(G)?$")>;
-def : InstRW<[FXU, FXU, FXU, LSU, Lat7, GroupAlone], (instregex "BRX(H|LE)$")>;
+def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BRCTH$")>;
+def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BCT(G)?(R)?$")>;
+def : InstRW<[FXU, FXU, FXU, LSU, Lat7, GroupAlone],
+ (instregex "B(R)?X(H|L).*$")>;
// Compare and branch
def : InstRW<[FXU], (instregex "C(L)?(G)?(I|R)J(Asm.*)?$")>;
@@ -436,11 +439,11 @@
//===----------------------------------------------------------------------===//
def : InstRW<[FXU, LSU, Lat5], (instregex "C(G|Y|Mux|RL)?$")>;
-def : InstRW<[FXU], (instregex "CFI(Mux)?$")>;
+def : InstRW<[FXU], (instregex "C(F|H)I(Mux)?$")>;
def : InstRW<[FXU], (instregex "CG(F|H)I$")>;
def : InstRW<[FXU, LSU, Lat5], (instregex "CG(HSI|RL)$")>;
def : InstRW<[FXU], (instregex "C(G)?R$")>;
-def : InstRW<[FXU], (instregex "C(HI|IH)$")>;
+def : InstRW<[FXU], (instregex "CIH$")>;
def : InstRW<[FXU, LSU, Lat5], (instregex "CH(F|SI)$")>;
def : InstRW<[FXU, LSU, Lat5], (instregex "CL(Y|Mux|FHSI)?$")>;
def : InstRW<[FXU], (instregex "CLFI(Mux)?$")>;